More updates to joint fabric-forge build

This commit is contained in:
Tschipp 2022-11-16 09:23:51 -08:00
parent e6ace77c39
commit cf6a14f5d9
34 changed files with 1417 additions and 52 deletions

View File

@ -1,3 +0,0 @@
<component name="DependencyValidationManager">
<scope name="Fabric sources" pattern="!ext[Gradle: cpw.mods:*:*]:*/&amp;&amp;!ext[Gradle: mezz.jei:*:*:*]:*/&amp;&amp;!ext[Gradle: net.jodah:typetools:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:client:extra:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:joined*:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:mappings_official:zip:*]:*/&amp;&amp;!ext[Gradle: net.minecraftforge:*:*]:*/" />
</component>

View File

@ -1,3 +0,0 @@
<component name="DependencyValidationManager">
<scope name="Forge sources" pattern="!ext[Gradle: loom_mappings_*:*:*]:*/&amp;&amp;!ext[Gradle: net.fabricmc:*:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:joined*:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:mappings_official:zip:*]:*/&amp;&amp;!ext[Gradle: net.minecraft:minecraft-project-*:*]:*/" />
</component>

View File

@ -2,10 +2,20 @@ package tschipp.carryon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tschipp.carryon.common.config.CarryConfig;
import tschipp.carryon.config.ConfigLoader;
public class Constants {
public static final String MOD_ID = "carryon";
public static final String MOD_NAME = "Carry On";
public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common();
public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client();
static {
ConfigLoader.registerConfig(COMMON_CONFIG);
ConfigLoader.registerConfig(CLIENT_CONFIG);
}
}

View File

@ -5,27 +5,36 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import java.util.Optional;
public class CarriedObjectRender
{
public static boolean drawFirstPerson(Player player, MultiBufferSource buffer, PoseStack matrix, int light)
public static boolean drawFirstPerson(Player player, MultiBufferSource buffer, PoseStack matrix, int light, float partialTicks)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK))
drawFirstPersonBlock(player, buffer, matrix, light, carry.getBlock());
else
;
else if (carry.isCarrying(CarryType.ENTITY))
drawFirstPersonEntity(player, buffer, matrix, light, carry.getEntity(player.level), partialTicks);
return carry.isCarrying();
}
@ -39,8 +48,7 @@ public class CarriedObjectRender
RenderSystem.disableCull();
int perspective = CarryRenderHelper.getPerspective();
//TODO: FacePlayer config
if (isChest(state.getBlock())) {
if (Constants.CLIENT_CONFIG.facePlayer && isChest(state.getBlock())) {
matrix.mulPose(Vector3f.YP.rotationDegrees(180));
matrix.mulPose(Vector3f.XN.rotationDegrees(8));
} else {
@ -74,8 +82,76 @@ public class CarriedObjectRender
matrix.popPose();
}
private static void drawFirstPersonEntity(Player player, MultiBufferSource buffer, PoseStack matrix, int light, Entity entity, float partialTicks) {
EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher();
public static boolean isChest(Block block)
if (entity != null)
{
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialTicks);
entity.setPos(playerpos.x, playerpos.y, playerpos.z);
entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
float height = entity.getBbHeight();
float width = entity.getBbWidth();
matrix.pushPose();
matrix.scale(0.8f, 0.8f, 0.8f);
matrix.mulPose(Vector3f.YP.rotationDegrees(180));
matrix.translate(0.0, -height - .1, width + 0.1);
// RenderSystem.enableAlphaTest();
// Lighting.en
manager.setRenderShadow(false);
//TODO: Scripts
/*
CarryOnOverride carryOverride = ScriptChecker.getOverride(player);
if (carryOverride != null)
{
CarryRenderHelper.performOverrideTransformation(matrix, carryOverride);
String entityname = carryOverride.getRenderNameEntity();
if (entityname != null)
{
Entity newEntity = null;
Optional<EntityType<?>> type = EntityType.byString(entityname);
if (type.isPresent())
newEntity = type.get().create(level);
if (newEntity != null)
{
CompoundTag nbttag = carryOverride.getRenderNBT();
if (nbttag != null)
newEntity.deserializeNBT(nbttag);
entity = newEntity;
entity.setPos(playerpos.x, playerpos.y, playerpos.z);
entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
}
}
}
*/
if (entity instanceof LivingEntity)
((LivingEntity) entity).hurtTime = 0;
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light);
manager.setRenderShadow(true);
}
// RenderSystem.disableAlphaTest();
matrix.popPose();
}
private static boolean isChest(Block block)
{
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST;
}

View File

@ -10,8 +10,11 @@ import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
@ -36,6 +39,87 @@ public class CarryRenderHelper
return Vector3f.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks));
}
public static void applyGeneralTransformations(Player player, float partialticks, PoseStack matrix)
{
int perspective = CarryRenderHelper.getPerspective();
Quaternion playerrot = CarryRenderHelper.getExactBodyRotation(player, partialticks);
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialticks);
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
Vec3 offset = playerpos.subtract(cameraPos);
Pose pose = player.getPose();
matrix.pushPose();
matrix.translate(offset.x, offset.y, offset.z);
if (perspective == 2)
playerrot.mul(Vector3f.YP.rotationDegrees(180));
matrix.mulPose(playerrot);
matrix.pushPose();
matrix.scale(0.6f, 0.6f, 0.6f);
if (perspective == 2)
matrix.translate(0, 0, -1.35);
if (doSneakCheck(player))
{
matrix.translate(0, -0.4, 0);
}
if (pose == Pose.SWIMMING)
{
float f = player.getSwimAmount(partialticks);
float f3 = player.isInWater() ? -90.0F - player.xRotO : -90.0F;
float f4 = Mth.lerp(f, 0.0F, f3);
if (perspective == 2)
{
matrix.translate(0, 0, 1.35);
matrix.mulPose(Vector3f.XP.rotationDegrees(f4));
}
else
matrix.mulPose(Vector3f.XN.rotationDegrees(f4));
matrix.translate(0, -1.5, -1.848);
if (perspective == 2)
matrix.translate(0, 0, 2.38);
}
if (pose == Pose.FALL_FLYING)
{
float f1 = player.getFallFlyingTicks() + partialticks;
float f2 = Mth.clamp(f1 * f1 / 100.0F, 0.0F, 1.0F);
if (!player.isAutoSpinAttack())
{
if (perspective == 2)
matrix.translate(0, 0, 1.35);
if (perspective == 2)
matrix.mulPose(Vector3f.XP.rotationDegrees(f2 * (-90.0F - player.xRotO)));
else
matrix.mulPose(Vector3f.XN.rotationDegrees(f2 * (-90.0F - player.xRotO)));
}
Vec3 Vector3d = player.getViewVector(partialticks);
Vec3 Vector3d1 = player.getDeltaMovement();
double d0 = Vector3d1.horizontalDistanceSqr();
double d1 = Vector3d1.horizontalDistanceSqr();
if (d0 > 0.0D && d1 > 0.0D)
{
double d2 = (Vector3d1.x * Vector3d.x + Vector3d1.z * Vector3d.z) / (Math.sqrt(d0) * Math.sqrt(d1));
double d3 = Vector3d1.x * Vector3d.z - Vector3d1.z * Vector3d.x;
matrix.mulPose(Vector3f.YP.rotation((float) (Math.signum(d3) * Math.acos(d2))));
}
if (perspective != 2)
matrix.translate(0, 0, -1.35);
matrix.translate(0, -0.2, 0);
}
matrix.translate(0, 1.6, 0.65);
}
//TODO: Scripting
// public static void performOverrideTransformation(PoseStack matrix, CarryOnOverride override)
// {
@ -84,4 +168,12 @@ public class CarryRenderHelper
return 1;
return 2;
}
public static boolean doSneakCheck(Player player)
{
if (player.getAbilities().flying)
return false;
return player.isShiftKeyDown() || player.isCrouching();
}
}

View File

@ -0,0 +1,194 @@
package tschipp.carryon.common.carry;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.Property;
import tschipp.carryon.Constants;
import java.util.*;
import java.util.stream.Collectors;
public class ListHandler {
private static Set<String> FORBIDDEN_TILES = new HashSet<>();
private static Set<String> FORBIDDEN_ENTITIES = new HashSet<>();
private static Set<String> ALLOWED_ENTITIES = new HashSet<>();
private static Set<String> ALLOWED_TILES = new HashSet<>();
private static Set<String> FORBIDDEN_STACKING = new HashSet<>();
private static Set<String> ALLOWED_STACKING = new HashSet<>();
private static List<TagKey<Block>> FORBIDDEN_TILES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> FORBIDDEN_ENTITIES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> ALLOWED_ENTITIES_TAGS = new ArrayList<>();
private static List<TagKey<Block>> ALLOWED_TILES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> FORBIDDEN_STACKING_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> ALLOWED_STACKING_TAGS = new ArrayList<>();
private static Set<Class<?>> PROPERTY_EXCEPTION_CLASSES = new HashSet<>();
public static boolean isPermitted(Block block)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistBlocks)
return doCheck(block, ALLOWED_TILES, ALLOWED_TILES_TAGS);
else
return !doCheck(block, FORBIDDEN_TILES, FORBIDDEN_TILES_TAGS);
}
public static boolean isPermitted(Entity entity)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistEntities)
return doCheck(entity, ALLOWED_ENTITIES, ALLOWED_ENTITIES_TAGS);
else
return !doCheck(entity, FORBIDDEN_ENTITIES, FORBIDDEN_ENTITIES_TAGS);
}
public static boolean isStackingPermitted(Entity entity)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistStacking)
return doCheck(entity, ALLOWED_STACKING, ALLOWED_STACKING_TAGS);
else
return !doCheck(entity, FORBIDDEN_STACKING, FORBIDDEN_STACKING_TAGS);
}
public static boolean isPropertyException(Property<?> prop)
{
return PROPERTY_EXCEPTION_CLASSES.contains(prop.getValueClass());
}
private static boolean doCheck(Block block, Set<String> regular, List<TagKey<Block>> tags)
{
String name = Registry.BLOCK.getKey(block).toString();
if(regular.contains(name))
return true;
for(TagKey<Block> tag : tags)
if(block.defaultBlockState().is(tag))
return true;
return false;
}
private static boolean doCheck(Entity entity, Set<String> regular, List<TagKey<EntityType<?>>> tags)
{
String name = Registry.ENTITY_TYPE.getKey(entity.getType()).toString();
if(regular.contains(name))
return true;
for(TagKey<EntityType<?>> tag : tags)
if(entity.getType().is(tag))
return true;
return false;
}
public static void initConfigLists()
{
FORBIDDEN_ENTITIES.clear();
FORBIDDEN_ENTITIES_TAGS.clear();
FORBIDDEN_STACKING.clear();
FORBIDDEN_STACKING_TAGS.clear();
FORBIDDEN_TILES.clear();
FORBIDDEN_TILES_TAGS.clear();
ALLOWED_ENTITIES.clear();
ALLOWED_ENTITIES_TAGS.clear();
ALLOWED_STACKING.clear();
ALLOWED_STACKING_TAGS.clear();
ALLOWED_TILES.clear();
ALLOWED_TILES_TAGS.clear();
PROPERTY_EXCEPTION_CLASSES.clear();
Map<ResourceLocation, TagKey<Block>> blocktags = Registry.BLOCK.getTagNames().collect(Collectors.toMap(t -> t.location(), t -> t));
Map<ResourceLocation, TagKey<EntityType<?>>> entitytags = Registry.ENTITY_TYPE.getTagNames().collect(Collectors.toMap(t -> t.location(), t -> t));
List<String> forbidden = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenTiles));
forbidden.add("#carryon:block_blacklist");
addWithWildcards(forbidden, FORBIDDEN_TILES, Registry.BLOCK, blocktags, FORBIDDEN_TILES_TAGS);
List<String> forbiddenEntity = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenEntities));
forbiddenEntity.add("#carryon:entity_blacklist");
addWithWildcards(forbiddenEntity, FORBIDDEN_ENTITIES, Registry.ENTITY_TYPE, entitytags, FORBIDDEN_ENTITIES_TAGS);
List<String> allowedEntities = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedEntities));
allowedEntities.add("#carryon:entity_whitelist");
addWithWildcards(allowedEntities, ALLOWED_ENTITIES, Registry.ENTITY_TYPE, entitytags, ALLOWED_ENTITIES_TAGS);
List<String> allowedBlocks = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedBlocks));
allowedBlocks.add("#carryon:block_whitelist");
addWithWildcards(allowedBlocks, ALLOWED_TILES, Registry.BLOCK, blocktags, ALLOWED_TILES_TAGS);
List<String> forbiddenStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenStacking));
forbiddenStacking.add("#carryon:stacking_blacklist");
addWithWildcards(forbiddenStacking, FORBIDDEN_STACKING, Registry.ENTITY_TYPE, entitytags, FORBIDDEN_STACKING_TAGS);
List<String> allowedStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedStacking));
allowedStacking.add("#carryon:stacking_whitelist");
addWithWildcards(allowedStacking, ALLOWED_STACKING, Registry.ENTITY_TYPE, entitytags, ALLOWED_STACKING_TAGS);
for(String propString : Constants.COMMON_CONFIG.settings.placementStateExceptions)
{
if(!propString.contains("[") || !propString.contains("]"))
continue;
String name = propString.substring(0, propString.indexOf("["));
String propName = propString.substring(propString.indexOf("[") + 1, propString.indexOf("]"));
Block blk = Registry.BLOCK.get(new ResourceLocation(name));
for(Property<?> prop : blk.defaultBlockState().getProperties())
{
if(prop.getName().equals(propName))
PROPERTY_EXCEPTION_CLASSES.add(prop.getValueClass());
}
}
}
private static <T> void addTag(String tag, Map<ResourceLocation, TagKey<T>> tagMap, List<TagKey<T>> tags) {
String sub = tag.substring(1);
TagKey<T> t = tagMap.get(new ResourceLocation(sub));
if (t != null)
tags.add(t);
}
private static <T> void addWithWildcards(List<String> entries, Set<String> toAddTo, Registry<T> registry, Map<ResourceLocation, TagKey<T>> tags, List<TagKey<T>> toAddTags) {
ResourceLocation[] keys = registry.keySet().toArray(new ResourceLocation[0]);
for (int i = 0; i < entries.size(); i++)
{
String curr = entries.get(i);
if (!curr.startsWith("#"))
{
if (curr.contains("*"))
{
String[] filter = curr.replace("*", ",").split(",");
for (ResourceLocation key : keys)
{
if (containsAll(key.toString(), filter))
{
toAddTo.add(key.toString());
}
}
}
else
toAddTo.add(curr);
}
else
addTag(curr, tags, toAddTags);
}
}
public static boolean containsAll(String str, String... strings)
{
boolean containsAll = true;
for (String s : strings)
{
if (!str.contains(s))
containsAll = false;
}
return containsAll;
}
}

View File

@ -1,12 +1,15 @@
package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.RemovalReason;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.player.Player;
@ -15,15 +18,12 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import tschipp.carryon.Constants;
import java.util.UUID;
public class PickupHandler {
//TODO: CONFIG
private static final double range = 2.0;
public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos)
{
//TODO: Check carry key
@ -33,13 +33,14 @@ public class PickupHandler {
if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty())
return false;
if(player.position().distanceTo(pos) >= range)
if(player.position().distanceTo(pos) > Constants.COMMON_CONFIG.settings.maxDistance)
return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
return false;
//Needed so that we don't pick up and place in the same tick
if(player.tickCount == carry.getTick())
return false;
@ -47,6 +48,7 @@ public class PickupHandler {
return false;
return true;
}
@ -56,12 +58,33 @@ public class PickupHandler {
if(!canCarryGeneral(player, Vec3.atCenterOf(pos)))
return false;
//TODO: Whitelist/Blacklist checks
CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockEntity blockEntity = level.getBlockEntity(pos);
BlockState state = level.getBlockState(pos);
if(!ListHandler.isPermitted(state.getBlock()))
return false;
if(state.getDestroySpeed(level, pos) == -1 && !player.isCreative())
return false;
if(blockEntity == null && !Constants.COMMON_CONFIG.settings.pickupAllBlocks)
return false;
//Check if TE is locked
if(blockEntity != null)
{
CompoundTag nbt = blockEntity.saveWithId();
if(nbt.contains("Lock") && !nbt.getString("Lock").equals(""))
return false;
}
//TODO: Script conditions
//TODO: Gamestages conditions check
//TODO: Protections
carry.setBlock(state, blockEntity);
level.removeBlockEntity(pos);
@ -94,19 +117,37 @@ public class PickupHandler {
return false;
}
if (entity instanceof Animal)
((Animal) entity).dropLeash(true, true);
if(!ListHandler.isPermitted(entity))
{
//We can pick up baby animals even if the grown up animal is blacklisted.
if(!(entity instanceof AgeableMob ageableMob && Constants.COMMON_CONFIG.settings.allowBabies && (ageableMob.getAge() < 0 || ageableMob.isBaby())))
return false;
}
//TODO: White and blacklist
//Non-Creative only guards
if(!player.isCreative())
{
if(!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER)
return false;
if(Constants.COMMON_CONFIG.settings.maxEntityHeight > entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth > entity.getBbWidth())
return false;
}
//TODO: Script conditions
//TODO: Gamestages conditions check
//TODO: Protections
CarryOnData carry = CarryOnDataManager.getCarryData(player);
entity.ejectPassengers();
if (entity instanceof Animal animal)
animal.dropLeash(true, true);
carry.setEntity(entity);
entity.remove(RemovalReason.DISCARDED);
entity.remove(RemovalReason.UNLOADED_WITH_PLAYER);
player.level.playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC, SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry);

View File

@ -2,7 +2,6 @@ package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
@ -16,7 +15,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
@ -55,7 +53,7 @@ public class PlacementHandler
return false;
state = getPlacementState(state, player, context, pos);
boolean doPlace = placementCallback == null ? true : placementCallback.apply(pos, state);
boolean doPlace = placementCallback == null || placementCallback.apply(pos, state);
if (!doPlace)
return false;
@ -80,12 +78,12 @@ public class PlacementHandler
if (prop instanceof DirectionProperty) {
state = updateProperty(state, placementState, prop);
}
if (prop instanceof EnumProperty<?>) {
if (state.getValue(prop) instanceof Axis)
state = updateProperty(state, placementState, prop);
if (prop.getValueClass() == Direction.Axis.class) {
state = updateProperty(state, placementState, prop);
}
//TODO: Add config for state variant names, which should be taken from the placementState
if (prop.getName().equals("type")) {
//This is needed for certain blocks, otherwise we get problems like chests not connecting
if (ListHandler.isPropertyException(prop)) {
state = updateProperty(state, placementState, prop);
}
}
@ -100,7 +98,7 @@ public class PlacementHandler
return state;
}
private static <T extends Comparable<T>, V extends T> BlockState updateProperty(BlockState state, BlockState otherState, Property<T> prop)
private static <T extends Comparable<T>> BlockState updateProperty(BlockState state, BlockState otherState, Property<T> prop)
{
var val = otherState.getValue(prop);
return state.setValue(prop, val);
@ -127,7 +125,7 @@ public class PlacementHandler
Entity entity = carry.getEntity(level);
entity.setPos(placementPos);
boolean doPlace = placementCallback == null ? true : placementCallback.apply(placementPos, entity);
boolean doPlace = placementCallback == null || placementCallback.apply(placementPos, entity);
if (!doPlace)
return false;

View File

@ -0,0 +1,311 @@
package tschipp.carryon.common.config;
import tschipp.carryon.config.PropertyType;
import tschipp.carryon.config.annotations.Category;
import tschipp.carryon.config.annotations.Config;
import tschipp.carryon.config.annotations.Property;
public class CarryConfig {
@Config("carryon-common")
public static class Common {
//Settings
@Property(
type = PropertyType.CATEGORY,
description = "General Settings"
)
public Settings settings = new Settings();
@Category("settings")
public static class Settings {
@Property(
type = PropertyType.DOUBLE,
description = "Maximum distance from where Blocks and Entities can be picked up",
minD = 0
)
public double maxDistance = 2.5;
@Property(
type = PropertyType.DOUBLE,
description = "Max width of entities that can be picked up in survival mode",
minD = 0,
maxD = 10
)
public double maxEntityWidth = 1.5;
@Property(
type = PropertyType.DOUBLE,
description = "Max height of entities that can be picked up in survival mode",
minD = 0,
maxD = 10
)
public double maxEntityHeight = 2.5;
@Property(
type = PropertyType.DOUBLE,
description = "Slowness multiplier for blocks",
minD = 0
)
public double blockSlownessMultiplier = 1;
@Property(
type = PropertyType.DOUBLE,
description = "Slowness multiplier for entities",
minD = 0
)
public double entitySlownessMultiplier = 1;
@Property(
type = PropertyType.INT,
description = "Maximum stack limit for entities",
min = 1
)
public int maxEntityStackLimit = 10;
@Property(
type = PropertyType.BOOLEAN,
description = "More complex Tile Entities slow down the player more"
)
public boolean heavyTiles = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Allow all blocks to be picked up, not just Tile Entites. White/Blacklist will still be respected."
)
public boolean pickupAllBlocks = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether Blocks and Entities slow the creative player down when carried"
)
public boolean slownessInCreative = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether hostile mobs should be able to picked up in survival mode"
)
public boolean pickupHostileMobs = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Larger Entities slow down the player more"
)
public boolean heavyEntities = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Allow babies to be carried even when adult mob is blacklisted (or not whitelisted)"
)
public boolean allowBabies = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Blocks"
)
public boolean useWhitelistBlocks = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Entities"
)
public boolean useWhitelistEntities = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Stacking"
)
public boolean useWhitelistStacking = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether the player can hit blocks and entities while carrying or not"
)
public boolean hitWhileCarrying = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether the player drops the carried object when hit or not"
)
public boolean dropCarriedWhenHit = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use custom Pickup Scripts. Having this set to false, will not allow you to run scripts, but will increase your performance"
)
public boolean useScripts = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Allows entities to be stacked on top of each other"
)
public boolean stackableEntities = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether entities' size matters when stacking or not. This means that larger entities cannot be stacked on smaller ones"
)
public boolean entitySizeMattersStacking = true;
@Property(
type = PropertyType.STRING_ARRAY,
description = "Usually all the block state information is retained when placing a block that was picked up. But some information is changed to a modified property, like rotation or orientation. In this list, add additional properties that should NOT be saved and instead be updated when placed. Format: modid:block[propertyname]. Note: You don't need to add an entry for every subtype of a same block. For example, we only add an entry for one type of slab, but the change is applied to all slabs."
)
public String[] placementStateExceptions = {
"minecraft:chest[type]"
};
}
@Property(
type = PropertyType.CATEGORY,
description = "Whitelist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
)
//Whitelist
public Whitelist whitelist = new Whitelist();
@Category("whitelist")
public static class Whitelist {
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that CAN be picked up (useWhitelistEntities must be true)"
)
public String[] allowedEntities = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Blocks that CAN be picked up (useWhitelistBlocks must be true)"
)
public String[] allowedBlocks = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that CAN have other entities stacked on top of them (useWhitelistStacking must be true)"
)
public String[] allowedStacking = {};
}
//Blacklist
@Property(
type = PropertyType.CATEGORY,
description = "Blacklist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
)
public Blacklist blacklist = new Blacklist();
@Category("blacklist")
public static class Blacklist {
@Property(
type = PropertyType.STRING_ARRAY,
description = "Blocks that cannot be picked up"
)
public String[] forbiddenTiles = {
"#forge:immovable", "#forge:relocation_not_supported", "minecraft:end_portal",
"minecraft:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony",
"minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed",
"minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake",
"minecraft:nether_portal", "minecraft:tall_seagrass", "animania:block_trough",
"animania:block_invisiblock", "colossalchests:*", "ic2:*", "bigreactors:*", "forestry:*",
"tconstruct:*", "rustic:*", "botania:*", "astralsorcery:*", "quark:colored_bed_*",
"immersiveengineering:*", "embers:block_furnace", "embers:ember_bore",
"embers:ember_activator", "embers:mixer", "embers:heat_coil", "embers:large_tank",
"embers:crystal_cell", "embers:alchemy_pedestal", "embers:boiler", "embers:combustor",
"embers:catalzyer", "embers:field_chart", "embers:inferno_forge",
"storagedrawers:framingtable", "skyresources:*", "lootbags:*", "exsartagine:*",
"aquamunda:tank", "opencomputers:*", "malisisdoors:*", "industrialforegoing:*",
"minecolonies:*", "thaumcraft:pillar*", "thaumcraft:infernal_furnace",
"thaumcraft:placeholder*", "thaumcraft:infusion_matrix", "thaumcraft:golem_builder",
"thaumcraft:thaumatorium*", "magneticraft:oil_heater", "magneticraft:solar_panel",
"magneticraft:steam_engine", "magneticraft:shelving_unit", "magneticraft:grinder",
"magneticraft:sieve", "magneticraft:solar_tower", "magneticraft:solar_mirror",
"magneticraft:container", "magneticraft:pumpjack", "magneticraft:solar_panel",
"magneticraft:refinery", "magneticraft:oil_heater", "magneticraft:hydraulic_press",
"magneticraft:multiblock_gap", "refinedstorage:*", "mcmultipart:*", "enderstorage:*",
"betterstorage:*", "practicallogistics2:*", "wearablebackpacks:*", "rftools:screen",
"rftools:creative_screen", "create:*", "magic_doorknob:*", "iceandfire:*", "ftbquests:*",
"waystones:*"
};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that cannot be picked up"
)
public String[] forbiddenEntities = {
"minecraft:end_crystal", "minecraft:ender_dragon", "minecraft:ghast",
"minecraft:shulker", "minecraft:leash_knot", "minecraft:armor_stand",
"minecraft:item_frame", "minecraft:painting", "minecraft:shulker_bullet",
"animania:hamster", "animania:ferret*", "animania:hedgehog*", "animania:cart",
"animania:wagon", "mynko:*", "pixelmon:*", "mocreatures:*", "quark:totem", "vehicle:*"
};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that cannot have other entities stacked on top of them"
)
public String[] forbiddenStacking = {
"minecraft:horse"
};
}
//Custom Pickup Conditions
@Property(
type = PropertyType.CATEGORY,
description = "Custom Pickup Conditions. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Custom-Pickup-Condition-Config"
)
public CustomPickupConditions customPickupConditions = new CustomPickupConditions();
@Category("customPickupConditions")
public static class CustomPickupConditions {
@Property(
type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Blocks"
)
public String[] customPickupConditionsBlocks = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Entities"
)
public String[] customPickupConditionsEntities = {};
}
}
@Config("carryon-client")
public static class Client {
@Property(
type = PropertyType.BOOLEAN,
description = "If the front of the Tile Entities should face the player or should face outward"
)
public boolean facePlayer = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Arms should render on sides when carrying. Set to false if you experience issues with mods that replace the player model (like MoBends, etc)"
)
public boolean renderArms = true;
@Property(
type = PropertyType.STRING_ARRAY,
description = "Model Overrides based on NBT or Meta. Advanced users only! Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Model-Override-Config"
)
public String[] modelOverrides = {
"minecraft:hopper->(block)minecraft:hopper",
"minecraft:comparator->(block)minecraft:comparator",
"minecraft:repeater->(block)minecraft:repeater",
"minecraft:cauldron->(block)minecraft:cauldron",
"minecraft:brewing_stand->(item)minecraft:brewing_stand",
"minecraft:flower_pot->(block)minecraft:flower_pot",
"minecraft:sugar_cane->(block)minecraft:sugar_cane",
"minecraft:redstone_wire->(item)minecraft:redstone",
"animania:block_nest->(block)animania:block_nest",
"animania:cheese_mold;0->(block)animania:cheese_mold;0",
"animania:cheese_mold;1->(block)animania:cheese_mold;1",
"animania:cheese_mold;2->(block)animania:cheese_mold;2",
"animania:cheese_mold;3->(block)animania:cheese_mold;3",
"animania:cheese_mold;4->(block)animania:cheese_mold;4",
"animania:cheese_mold;5->(block)animania:cheese_mold;5",
"animania:cheese_mold;6->(block)animania:cheese_mold;6",
"animania:cheese_mold;7->(block)animania:cheese_mold;7",
"animania:cheese_mold;8->(block)animania:cheese_mold;8",
"animania:cheese_mold;9->(block)animania:cheese_mold;9",
"animania:cheese_mold;10->(block)animania:cheese_mold;10"
};
}
}

View File

@ -0,0 +1,24 @@
package tschipp.carryon.config;
import tschipp.carryon.config.annotations.Property;
import java.lang.reflect.Field;
public record AnnotationData(
PropertyType type,
String description,
int min, int max,
double minD, double maxD
) {
public static AnnotationData getData(Field field) {
Property annotation = field.getAnnotation(Property.class);
return new AnnotationData(
annotation.type(),
annotation.description(),
annotation.min(), annotation.max(),
annotation.minD(), annotation.maxD()
);
}
}

View File

@ -0,0 +1,37 @@
package tschipp.carryon.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class BuiltCategory {
public final List<PropertyData> properties = new ArrayList<>();
public final List<BuiltCategory> categories = new ArrayList<>();
public final String categoryDesc;
public final String category;
public BuiltCategory(String categoryDesc, String category) {
this.categoryDesc = categoryDesc;
this.category = category;
}
public Optional<PropertyData> getProperty(String id) {
for (PropertyData property : properties) {
if (property.getId().equals(id)) {
return Optional.of(property);
}
}
return Optional.empty();
}
public Optional<BuiltCategory> getCategory(String id) {
for (BuiltCategory category : categories) {
if (category.category.equals(id)) {
return Optional.of(category);
}
}
return Optional.empty();
}
}

View File

@ -0,0 +1,11 @@
package tschipp.carryon.config;
public class BuiltConfig extends BuiltCategory {
public final String fileName;
public BuiltConfig(String fileName) {
super(null, fileName);
this.fileName = fileName;
}
}

View File

@ -0,0 +1,61 @@
package tschipp.carryon.config;
//Many Thanks to ThatGravyBoat for this template!
import tschipp.carryon.common.carry.ListHandler;
import tschipp.carryon.config.annotations.Category;
import tschipp.carryon.config.annotations.Config;
import tschipp.carryon.config.annotations.Property;
import tschipp.carryon.platform.Services;
import java.lang.reflect.Field;
public class ConfigLoader {
public static void registerConfig(Object object) {
BuiltCategory category;
try {
category = buildCategory(null, object);
} catch (Exception e) {
e.printStackTrace();
category = null;
}
if (category instanceof BuiltConfig config) {
registerConfig(config);
} else {
throw new IllegalArgumentException("Config supplied does not have a @Config annotation");
}
}
public static void registerConfig(BuiltConfig config) {
Services.PLATFORM.registerConfig(config);
}
public static void onConfigLoaded() {
ListHandler.initConfigLists();
}
public static BuiltCategory buildCategory(String categoryDesc, Object object) throws IllegalAccessException {
Class<?> configClass = object.getClass();
BuiltCategory category;
if (configClass.isAnnotationPresent(Config.class)) {
category = new BuiltConfig(configClass.getAnnotation(Config.class).value());
} else if (configClass.isAnnotationPresent(Category.class)) {
category = new BuiltCategory(categoryDesc, configClass.getAnnotation(Category.class).value());
} else {
throw new IllegalStateException("Config does not contain any @Config annotation or @Category");
}
for (Field field : configClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Property.class) && field.canAccess(object)) {
PropertyType type = field.getAnnotation(Property.class).type();
if (type.equals(PropertyType.CATEGORY)) {
category.categories.add(buildCategory(field.getAnnotation(Property.class).description(), field.get(object)));
} else {
category.properties.add(new PropertyData(object, field, AnnotationData.getData(field)));
}
}
}
return category;
}
}

View File

@ -0,0 +1,59 @@
package tschipp.carryon.config;
import java.lang.reflect.Field;
public record PropertyData(Object fieldClass, Field field, AnnotationData data) {
public String getId() {
return field().getName();
}
public boolean getBoolean() throws IllegalAccessException {
return field().getBoolean(fieldClass());
}
public void setBoolean(boolean _boolean) {
try {
field.setBoolean(fieldClass, _boolean);
} catch (Exception e) {
//Ignore
}
}
public int getInt() throws IllegalAccessException {
return field().getInt(fieldClass());
}
public void setInt(int _int) {
try {
field.setInt(fieldClass, _int);
} catch (Exception e) {
//Ignore
}
}
public double getDouble() throws IllegalAccessException {
return field().getDouble(fieldClass());
}
public void setDouble(double _double) {
try {
field.setDouble(fieldClass, _double);
} catch (Exception e) {
//Ignore
}
}
public String[] getStringArray() throws IllegalAccessException {
return (String[])field().get(fieldClass());
}
public void setStringArray(String[] arr)
{
try {
field.set(fieldClass, arr);
} catch (Exception e) {
//Ignore
}
}
}

View File

@ -0,0 +1,9 @@
package tschipp.carryon.config;
public enum PropertyType {
INT,
DOUBLE,
BOOLEAN,
STRING_ARRAY,
CATEGORY
}

View File

@ -0,0 +1,12 @@
package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Category {
String value();
}

View File

@ -0,0 +1,12 @@
package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
String value();
}

View File

@ -0,0 +1,24 @@
package tschipp.carryon.config.annotations;
import tschipp.carryon.config.PropertyType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
PropertyType type();
String description();
int min() default Integer.MIN_VALUE;
int max() default Integer.MAX_VALUE;
double minD() default Double.MIN_VALUE;
double maxD() default Double.MAX_VALUE;
}

View File

@ -0,0 +1,55 @@
package tschipp.carryon.mixin;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(HumanoidModel.class)
public class HumanoidModelMixin {
@Shadow
public ModelPart rightArm;
@Shadow
public ModelPart leftArm;
@Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V")
private void onSetupAnimations(LivingEntity living, float f1, float f2, float f3, float f4, float f5, CallbackInfo ci)
{
System.out.println("Reached model injectiob");
if(living instanceof Player player)
{
System.out.println("Model is player");
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying() && !player.isVisuallySwimming() && !player.isFallFlying())
{
System.out.println("Player is carrying");
boolean sneaking = !player.getAbilities().flying && player.isShiftKeyDown() || player.isCrouching();
float x = 1.0f + (sneaking ? 0.2f : 0.0f) - (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f);
float z = 0.15f;
rightArm.yRot = 0;
leftArm.yRot = 0;
rightArm.xRot = -x;
leftArm.xRot = -x;
rightArm.zRot = z;
leftArm.zRot = -z;
}
}
}
}

View File

@ -23,6 +23,7 @@ public abstract class PlayerMixin extends LivingEntity {
@Inject(method = "defineSynchedData()V", at = @At("RETURN"))
private void onDefineSynchedData(CallbackInfo info) {
this.entityData.define(CarryOnDataManager.CARRY_DATA_KEY, new CompoundTag());
System.out.println("Added Carry Data!");
}
@Inject(method = "addAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN"))

View File

@ -1,5 +1,7 @@
package tschipp.carryon.platform.services;
import tschipp.carryon.config.BuiltConfig;
public interface IPlatformHelper {
/**
@ -23,4 +25,6 @@ public interface IPlatformHelper {
* @return True if in a development environment, false otherwise.
*/
boolean isDevelopmentEnvironment();
void registerConfig(BuiltConfig cfg);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View File

@ -8,7 +8,8 @@
"PlayerMixin"
],
"client": [
"MinecraftMixin"
"MinecraftMixin",
"HumanoidModelMixin"
],
"server": [
],

View File

@ -1,6 +1,10 @@
package tschipp.carryon;
import net.fabricmc.api.ModInitializer;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.events.CommonEvents;
import java.io.IOException;
public class CarryOnFabricMod implements ModInitializer {
@ -13,6 +17,14 @@ public class CarryOnFabricMod implements ModInitializer {
// Use Fabric to bootstrap the Common mod.
Constants.LOG.info("Hello Fabric world!");
try {
ConfigLoaderImpl.initialize();
} catch (IOException e) {
throw new RuntimeException(e);
}
CommonEvents.registerEvents();
}
}

View File

@ -0,0 +1,131 @@
package tschipp.carryon.config.fabric;
import com.google.gson.*;
import net.fabricmc.loader.api.FabricLoader;
import org.apache.commons.io.FileUtils;
import tschipp.carryon.config.*;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConfigLoaderImpl {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
//Default JSON and config data.
public static final Map<JsonObject, BuiltConfig> CONFIGS = new HashMap<>();
public static void initialize() throws IOException {
Path cfgPath = FabricLoader.getInstance().getConfigDir();
for (Map.Entry<JsonObject, BuiltConfig> entry : CONFIGS.entrySet()) {
File cfgFile = new File(cfgPath.toFile(), entry.getValue().fileName+".json");
if (!cfgFile.exists()) {
cfgPath.toFile().mkdirs();
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
} else {
JsonObject cfgJson = GSON.fromJson(FileUtils.readFileToString(cfgFile, StandardCharsets.UTF_8), JsonObject.class);
FileUtils.write(cfgFile, GSON.toJson(loadConfig(entry.getValue(), cfgJson)), StandardCharsets.UTF_8);
}
}
}
private static JsonObject loadConfig(BuiltCategory category, JsonObject config) {
config.entrySet().forEach((entry) -> {
String id = entry.getKey();
if (!id.startsWith("//")) {
JsonElement value = entry.getValue();
if (value instanceof JsonPrimitive configValue) {
category.getProperty(id).ifPresent(data -> {
if (configValue.isBoolean() && data.data().type().equals(PropertyType.BOOLEAN))
data.setBoolean(configValue.getAsBoolean());
if (configValue.isNumber() && data.data().type().equals(PropertyType.INT)) {
int configInt = configValue.getAsInt();
if (configInt > data.data().max() || configInt < data.data().min()) {
try {
config.addProperty(id, data.getInt());
} catch (IllegalAccessException ignored) {
}
} else {
data.setInt(configInt);
}
}
if (configValue.isNumber() && data.data().type().equals(PropertyType.DOUBLE)) {
double configDouble = configValue.getAsDouble();
if (configDouble > data.data().maxD() || configDouble < data.data().minD()) {
try {
config.addProperty(id, data.getDouble());
} catch (IllegalAccessException ignored) {
}
} else {
data.setDouble(configDouble);
}
}
});
} else if (value instanceof JsonObject subConfig) {
category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig));
} else if (value instanceof JsonArray list) {
category.getProperty(id).ifPresent(data -> {
if(data.data().type() == PropertyType.STRING_ARRAY)
{
List<String> ls = new ArrayList<>();
for(JsonElement arrEle : list)
{
if(arrEle instanceof JsonPrimitive p && p.isString())
{
ls.add(p.getAsString());
}
}
data.setStringArray(ls.toArray(new String[ls.size()]));
}
});
}
}
});
ConfigLoader.onConfigLoaded();
return config;
}
public static void registerConfig(BuiltConfig config) {
try {
JsonObject configJson = new JsonObject();
for (PropertyData property : config.properties) buildProperty(configJson, property);
for (BuiltCategory category : config.categories) buildCategory(configJson, category);
CONFIGS.put(configJson, config);
}catch (Exception e) {
e.printStackTrace();
}
}
private static void buildCategory(JsonObject builder, BuiltCategory category) throws IllegalAccessException {
JsonObject categoryJson = new JsonObject();
if (category.categoryDesc != null) categoryJson.addProperty("//"+category.category, category.categoryDesc);
for (PropertyData property : category.properties) buildProperty(categoryJson, property);
for (BuiltCategory builtCategory : category.categories) buildCategory(categoryJson, builtCategory);
builder.add(category.category, categoryJson);
}
private static void buildProperty(JsonObject builder, PropertyData data) throws IllegalAccessException {
AnnotationData annotationData = data.data();
builder.addProperty("//"+data.getId(), annotationData.description());
switch (annotationData.type()) {
case BOOLEAN -> builder.addProperty(data.getId(), data.getBoolean());
case INT -> builder.addProperty(data.getId(), data.getInt());
case DOUBLE -> builder.addProperty(data.getId(), data.getDouble());
case STRING_ARRAY -> {
JsonArray arr = new JsonArray();
for(String s : data.getStringArray())
arr.add(s);
builder.add(data.getId(), arr);
}
default -> throw new IllegalAccessException("Unknown property type.");
}
}
}

View File

@ -0,0 +1,4 @@
package tschipp.carryon.events;
public class ClientEvents {
}

View File

@ -0,0 +1,75 @@
package tschipp.carryon.events;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PickupHandler;
import tschipp.carryon.common.carry.PlacementHandler;
public class CommonEvents {
public static void registerEvents() {
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
if(world.isClientSide)
return InteractionResult.PASS;
BlockPos pos = hitResult.getBlockPos();
Direction facing = hitResult.getDirection();
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(!carry.isCarrying())
{
if (PickupHandler.tryPickUpBlock((ServerPlayer) player, pos, world))
return InteractionResult.SUCCESS;
return InteractionResult.PASS;
}
else
{
if(carry.isCarrying(CarryOnData.CarryType.BLOCK))
{
if(PlacementHandler.tryPlaceBlock((ServerPlayer) player, pos, facing, null))
return InteractionResult.SUCCESS;
}
else
{
if(PlacementHandler.tryPlaceEntity((ServerPlayer) player, pos, facing, null))
return InteractionResult.SUCCESS;
}
//Fail here, so that we don't interact with placed things
return InteractionResult.FAIL;
}
});
UseEntityCallback.EVENT.register((player, level, hand, entity, hitResult) -> {
if(level.isClientSide)
return InteractionResult.PASS;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying()) {
if (PickupHandler.tryPickupEntity((ServerPlayer) player, entity)) {
return InteractionResult.SUCCESS;
}
}
else if(carry.isCarrying(CarryOnData.CarryType.ENTITY))
{
//TODO: Stacking
}
return InteractionResult.PASS;
});
}
}

View File

@ -1,5 +1,7 @@
package tschipp.carryon.platform;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.platform.services.IPlatformHelper;
import net.fabricmc.loader.api.FabricLoader;
@ -21,4 +23,9 @@ public class FabricPlatformHelper implements IPlatformHelper {
return FabricLoader.getInstance().isDevelopmentEnvironment();
}
@Override
public void registerConfig(BuiltConfig cfg) {
ConfigLoaderImpl.registerConfig(cfg);
}
}

View File

@ -1,12 +1,12 @@
{
"schemaVersion": 1,
"id": "modid",
"id": "carryon",
"version": "${version}",
"name": "Example Mod",
"name": "Carry On",
"description": "This is an example description! Tell everyone what your mod is about!",
"authors": [
"Me!"
"Tschipp"
],
"contact": {
"homepage": "https://fabricmc.net/",
@ -14,7 +14,7 @@
},
"license": "CC0-1.0",
"icon": "assets/modid/icon.png",
"icon": "assets/carryon/logo.png",
"environment": "*",
"entrypoints": {
@ -23,7 +23,8 @@
]
},
"mixins": [
"carryon.fabric.mixins.json"
"carryon.fabric.mixins.json",
"carryon.mixins.json"
],
"depends": {
@ -31,9 +32,6 @@
"fabric": "*",
"minecraft": "1.19.x",
"java": ">=17"
},
"suggests": {
"another-mod": "*"
}
}

View File

@ -1,6 +1,7 @@
package tschipp.carryon;
import net.minecraftforge.fml.common.Mod;
import tschipp.carryon.config.forge.ConfigLoaderImpl;
@Mod(Constants.MOD_ID)
public class CarryOnForge {
@ -13,6 +14,8 @@ public class CarryOnForge {
// Use Forge to bootstrap the Common mod.
Constants.LOG.info("Hello Forge world!");
ConfigLoaderImpl.initialize();
}
}

View File

@ -0,0 +1,102 @@
package tschipp.carryon.config.forge;
import com.electronwill.nightconfig.core.AbstractConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.IConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import tschipp.carryon.config.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConfigLoaderImpl {
public static final Map<ForgeConfigSpec, BuiltConfig> CONFIGS = new HashMap<>();
public static void initialize() {
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
bus.addListener(ConfigLoaderImpl::onConfigLoad);
bus.addListener(ConfigLoaderImpl::onConfigReload);
ConfigLoaderImpl.CONFIGS.forEach((spec, config) -> {
if(config.fileName.contains("client"))
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, spec, config.fileName+".toml");
else
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, spec, config.fileName+".toml");
});
}
public static void onConfigLoad(ModConfigEvent.Loading loading) {
loadConfig(loading.getConfig().getSpec());
ConfigLoader.onConfigLoaded();
}
public static void onConfigReload(ModConfigEvent.Reloading loading) {
loadConfig(loading.getConfig().getSpec());
ConfigLoader.onConfigLoaded();
}
private static void loadConfig(IConfigSpec<ForgeConfigSpec> spec) {
BuiltConfig builtConfig = CONFIGS.get(spec.self());
if (builtConfig == null) return;
loadConfig(builtConfig, spec.self().getValues());
}
private static void loadConfig(BuiltCategory category, UnmodifiableConfig config) {
config.valueMap().forEach((id, value) -> {
if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue) {
category.getProperty(id).ifPresent(data -> {
if (configValue instanceof ForgeConfigSpec.BooleanValue booleanValue)
data.setBoolean(booleanValue.get());
if (configValue instanceof ForgeConfigSpec.IntValue intValue)
data.setInt(intValue.get());
if (configValue instanceof ForgeConfigSpec.DoubleValue doubleValue)
data.setDouble(doubleValue.get());
if(configValue.get() instanceof List<?> listVal)
data.setStringArray(listVal.toArray(new String[listVal.size()]));
});
} else if (value instanceof AbstractConfig subConfig) {
category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig));
}
});
}
public static void registerConfig(BuiltConfig config) {
try {
ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
for (PropertyData property : config.properties) buildProperty(builder, property);
for (BuiltCategory category : config.categories) buildCategory(builder, category);
CONFIGS.put(builder.build(), config);
}catch (Exception e) {
e.printStackTrace();
}
}
private static void buildCategory(ForgeConfigSpec.Builder builder, BuiltCategory category) throws IllegalAccessException {
builder.push(category.category);
if (category.categoryDesc != null) builder.comment(category.categoryDesc);
for (PropertyData property : category.properties) buildProperty(builder, property);
for (BuiltCategory builtCategory : category.categories) buildCategory(builder, builtCategory);
builder.pop();
}
private static void buildProperty(ForgeConfigSpec.Builder builder, PropertyData data) throws IllegalAccessException {
AnnotationData annotationData = data.data();
builder.comment(annotationData.description());
switch (annotationData.type()) {
case BOOLEAN -> builder.define(data.getId(), data.getBoolean());
case INT -> builder.defineInRange(data.getId(), data.getInt(), annotationData.min(), annotationData.max());
case DOUBLE -> builder.defineInRange(data.getId(), data.getDouble(), annotationData.minD(), annotationData.maxD());
case STRING_ARRAY -> builder.defineList(data.getId(), Arrays.asList(data.getStringArray()), obj -> obj instanceof String);
default -> throw new IllegalAccessException("Unknown property type.");
}
}
}

View File

@ -24,8 +24,9 @@ public class ClientEvents {
MultiBufferSource buffer = event.getMultiBufferSource();
PoseStack matrix = event.getPoseStack();
int light = event.getPackedLight();
float partialTicks = event.getPartialTick();
if(CarriedObjectRender.drawFirstPerson(player, buffer, matrix, light) && CarryRenderHelper.getPerspective() == 0)
if(CarriedObjectRender.drawFirstPerson(player, buffer, matrix, light, partialTicks) && CarryRenderHelper.getPerspective() == 0)
event.setCanceled(true);
}
}

View File

@ -25,7 +25,6 @@ import tschipp.carryon.common.carry.PlacementHandler;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = Constants.MOD_ID)
public class CommonEvents
{
@SubscribeEvent(priority = EventPriority.HIGH)
public static void onBlockClick(PlayerInteractEvent.RightClickBlock event)
{
@ -39,12 +38,12 @@ public class CommonEvents
if (level.isClientSide)
return;
boolean cancel = false;
boolean success = false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying()) {
if (PickupHandler.tryPickUpBlock((ServerPlayer) player, pos, level)) {
cancel = true;
success = true;
}
} else {
if (carry.isCarrying(CarryType.BLOCK)) {
@ -54,23 +53,23 @@ public class CommonEvents
MinecraftForge.EVENT_BUS.post(event1);
return !event1.isCanceled();
})) {
cancel = true;
success = true;
}
} else {
//TODO: Entity place perms
if (PlacementHandler.tryPlaceEntity((ServerPlayer) player,pos, event.getFace(), null))
{
cancel = true;
success = true;
}
}
}
if(cancel)
if(success)
{
event.setUseBlock(Event.Result.DENY);
event.setUseItem(Event.Result.DENY);
event.setCancellationResult(InteractionResult.SUCCESS);
event.setCanceled(true);
return;
}
}

View File

@ -1,5 +1,7 @@
package tschipp.carryon.platform;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.forge.ConfigLoaderImpl;
import tschipp.carryon.platform.services.IPlatformHelper;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader;
@ -23,4 +25,9 @@ public class ForgePlatformHelper implements IPlatformHelper {
return !FMLLoader.isProduction();
}
@Override
public void registerConfig(BuiltConfig cfg) {
ConfigLoaderImpl.registerConfig(cfg);
}
}