diff --git a/.idea/scopes/Fabric_sources.xml b/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/scopes/Forge_sources.xml b/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Common/src/main/java/tschipp/carryon/Constants.java b/Common/src/main/java/tschipp/carryon/Constants.java index c7ce9f8..4410baa 100644 --- a/Common/src/main/java/tschipp/carryon/Constants.java +++ b/Common/src/main/java/tschipp/carryon/Constants.java @@ -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); + } } \ No newline at end of file diff --git a/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java b/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java index d0f9163..1cfeacd 100644 --- a/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java +++ b/Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java @@ -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> 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; } diff --git a/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java b/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java index 69c37d5..0dab93c 100644 --- a/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java +++ b/Common/src/main/java/tschipp/carryon/client/render/CarryRenderHelper.java @@ -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(); + } } diff --git a/Common/src/main/java/tschipp/carryon/common/carry/ListHandler.java b/Common/src/main/java/tschipp/carryon/common/carry/ListHandler.java new file mode 100644 index 0000000..7773f47 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/common/carry/ListHandler.java @@ -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 FORBIDDEN_TILES = new HashSet<>(); + private static Set FORBIDDEN_ENTITIES = new HashSet<>(); + private static Set ALLOWED_ENTITIES = new HashSet<>(); + private static Set ALLOWED_TILES = new HashSet<>(); + private static Set FORBIDDEN_STACKING = new HashSet<>(); + private static Set ALLOWED_STACKING = new HashSet<>(); + + private static List> FORBIDDEN_TILES_TAGS = new ArrayList<>(); + private static List>> FORBIDDEN_ENTITIES_TAGS = new ArrayList<>(); + private static List>> ALLOWED_ENTITIES_TAGS = new ArrayList<>(); + private static List> ALLOWED_TILES_TAGS = new ArrayList<>(); + private static List>> FORBIDDEN_STACKING_TAGS = new ArrayList<>(); + private static List>> ALLOWED_STACKING_TAGS = new ArrayList<>(); + + + private static Set> 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 regular, List> tags) + { + String name = Registry.BLOCK.getKey(block).toString(); + if(regular.contains(name)) + return true; + for(TagKey tag : tags) + if(block.defaultBlockState().is(tag)) + return true; + return false; + } + + private static boolean doCheck(Entity entity, Set regular, List>> tags) + { + String name = Registry.ENTITY_TYPE.getKey(entity.getType()).toString(); + if(regular.contains(name)) + return true; + for(TagKey> 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> blocktags = Registry.BLOCK.getTagNames().collect(Collectors.toMap(t -> t.location(), t -> t)); + Map>> entitytags = Registry.ENTITY_TYPE.getTagNames().collect(Collectors.toMap(t -> t.location(), t -> t)); + + List 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 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 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 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 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 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 void addTag(String tag, Map> tagMap, List> tags) { + String sub = tag.substring(1); + TagKey t = tagMap.get(new ResourceLocation(sub)); + if (t != null) + tags.add(t); + } + + private static void addWithWildcards(List entries, Set toAddTo, Registry registry, Map> tags, List> 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; + } + +} diff --git a/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java b/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java index a08c452..e7c185c 100644 --- a/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java +++ b/Common/src/main/java/tschipp/carryon/common/carry/PickupHandler.java @@ -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); diff --git a/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java b/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java index 34dbe60..dccc4c8 100644 --- a/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java +++ b/Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java @@ -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 , V extends T> BlockState updateProperty(BlockState state, BlockState otherState, Property prop) + private static > BlockState updateProperty(BlockState state, BlockState otherState, Property 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; diff --git a/Common/src/main/java/tschipp/carryon/common/config/CarryConfig.java b/Common/src/main/java/tschipp/carryon/common/config/CarryConfig.java new file mode 100644 index 0000000..1fff280 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/common/config/CarryConfig.java @@ -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" + }; + } + +} diff --git a/Common/src/main/java/tschipp/carryon/config/AnnotationData.java b/Common/src/main/java/tschipp/carryon/config/AnnotationData.java new file mode 100644 index 0000000..06f7d63 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/AnnotationData.java @@ -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() + ); + } +} diff --git a/Common/src/main/java/tschipp/carryon/config/BuiltCategory.java b/Common/src/main/java/tschipp/carryon/config/BuiltCategory.java new file mode 100644 index 0000000..b001281 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/BuiltCategory.java @@ -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 properties = new ArrayList<>(); + public final List 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 getProperty(String id) { + for (PropertyData property : properties) { + if (property.getId().equals(id)) { + return Optional.of(property); + } + } + return Optional.empty(); + } + + public Optional getCategory(String id) { + for (BuiltCategory category : categories) { + if (category.category.equals(id)) { + return Optional.of(category); + } + } + return Optional.empty(); + } +} diff --git a/Common/src/main/java/tschipp/carryon/config/BuiltConfig.java b/Common/src/main/java/tschipp/carryon/config/BuiltConfig.java new file mode 100644 index 0000000..cb950fb --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/BuiltConfig.java @@ -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; + } +} diff --git a/Common/src/main/java/tschipp/carryon/config/ConfigLoader.java b/Common/src/main/java/tschipp/carryon/config/ConfigLoader.java new file mode 100644 index 0000000..ffe129a --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/ConfigLoader.java @@ -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; + } +} diff --git a/Common/src/main/java/tschipp/carryon/config/PropertyData.java b/Common/src/main/java/tschipp/carryon/config/PropertyData.java new file mode 100644 index 0000000..af16458 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/PropertyData.java @@ -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 + } + } +} diff --git a/Common/src/main/java/tschipp/carryon/config/PropertyType.java b/Common/src/main/java/tschipp/carryon/config/PropertyType.java new file mode 100644 index 0000000..9c985d2 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/PropertyType.java @@ -0,0 +1,9 @@ +package tschipp.carryon.config; + +public enum PropertyType { + INT, + DOUBLE, + BOOLEAN, + STRING_ARRAY, + CATEGORY +} diff --git a/Common/src/main/java/tschipp/carryon/config/annotations/Category.java b/Common/src/main/java/tschipp/carryon/config/annotations/Category.java new file mode 100644 index 0000000..e2cbd08 --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/annotations/Category.java @@ -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(); +} diff --git a/Common/src/main/java/tschipp/carryon/config/annotations/Config.java b/Common/src/main/java/tschipp/carryon/config/annotations/Config.java new file mode 100644 index 0000000..897d47c --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/annotations/Config.java @@ -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(); +} diff --git a/Common/src/main/java/tschipp/carryon/config/annotations/Property.java b/Common/src/main/java/tschipp/carryon/config/annotations/Property.java new file mode 100644 index 0000000..680949f --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/config/annotations/Property.java @@ -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; +} diff --git a/Common/src/main/java/tschipp/carryon/mixin/HumanoidModelMixin.java b/Common/src/main/java/tschipp/carryon/mixin/HumanoidModelMixin.java new file mode 100644 index 0000000..0df344f --- /dev/null +++ b/Common/src/main/java/tschipp/carryon/mixin/HumanoidModelMixin.java @@ -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; + } + + } + } + +} diff --git a/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java b/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java index f11a43c..9e31831 100644 --- a/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java +++ b/Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java @@ -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")) diff --git a/Common/src/main/java/tschipp/carryon/platform/services/IPlatformHelper.java b/Common/src/main/java/tschipp/carryon/platform/services/IPlatformHelper.java index b62b62e..ce27a98 100644 --- a/Common/src/main/java/tschipp/carryon/platform/services/IPlatformHelper.java +++ b/Common/src/main/java/tschipp/carryon/platform/services/IPlatformHelper.java @@ -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); } diff --git a/Common/src/main/resources/assets/carryon/logo.png b/Common/src/main/resources/assets/carryon/logo.png new file mode 100644 index 0000000..1b9a978 Binary files /dev/null and b/Common/src/main/resources/assets/carryon/logo.png differ diff --git a/Common/src/main/resources/carryon.mixins.json b/Common/src/main/resources/carryon.mixins.json index 4879127..ec19c7d 100644 --- a/Common/src/main/resources/carryon.mixins.json +++ b/Common/src/main/resources/carryon.mixins.json @@ -8,7 +8,8 @@ "PlayerMixin" ], "client": [ - "MinecraftMixin" + "MinecraftMixin", + "HumanoidModelMixin" ], "server": [ ], diff --git a/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java b/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java index 955c14e..9bc2e24 100644 --- a/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java +++ b/Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java @@ -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(); + } } diff --git a/Fabric/src/main/java/tschipp/carryon/config/fabric/ConfigLoaderImpl.java b/Fabric/src/main/java/tschipp/carryon/config/fabric/ConfigLoaderImpl.java new file mode 100644 index 0000000..972653c --- /dev/null +++ b/Fabric/src/main/java/tschipp/carryon/config/fabric/ConfigLoaderImpl.java @@ -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 CONFIGS = new HashMap<>(); + + public static void initialize() throws IOException { + Path cfgPath = FabricLoader.getInstance().getConfigDir(); + + for (Map.Entry 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 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."); + } + } +} diff --git a/Fabric/src/main/java/tschipp/carryon/events/ClientEvents.java b/Fabric/src/main/java/tschipp/carryon/events/ClientEvents.java new file mode 100644 index 0000000..0efba9a --- /dev/null +++ b/Fabric/src/main/java/tschipp/carryon/events/ClientEvents.java @@ -0,0 +1,4 @@ +package tschipp.carryon.events; + +public class ClientEvents { +} diff --git a/Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java b/Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java new file mode 100644 index 0000000..5cd490c --- /dev/null +++ b/Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java @@ -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; + }); + + } + +} diff --git a/Fabric/src/main/java/tschipp/carryon/platform/FabricPlatformHelper.java b/Fabric/src/main/java/tschipp/carryon/platform/FabricPlatformHelper.java index bd10051..93e37a3 100644 --- a/Fabric/src/main/java/tschipp/carryon/platform/FabricPlatformHelper.java +++ b/Fabric/src/main/java/tschipp/carryon/platform/FabricPlatformHelper.java @@ -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); + } } diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 160567a..098c01b 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -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": "*" } } \ No newline at end of file diff --git a/Forge/src/main/java/tschipp/carryon/CarryOnForge.java b/Forge/src/main/java/tschipp/carryon/CarryOnForge.java index 46799c3..1684936 100644 --- a/Forge/src/main/java/tschipp/carryon/CarryOnForge.java +++ b/Forge/src/main/java/tschipp/carryon/CarryOnForge.java @@ -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(); } } \ No newline at end of file diff --git a/Forge/src/main/java/tschipp/carryon/config/forge/ConfigLoaderImpl.java b/Forge/src/main/java/tschipp/carryon/config/forge/ConfigLoaderImpl.java new file mode 100644 index 0000000..754206b --- /dev/null +++ b/Forge/src/main/java/tschipp/carryon/config/forge/ConfigLoaderImpl.java @@ -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 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 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."); + } + } +} diff --git a/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java b/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java index 233616d..05d6ec0 100644 --- a/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java +++ b/Forge/src/main/java/tschipp/carryon/events/ClientEvents.java @@ -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); } } diff --git a/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java b/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java index f67beca..8c9961f 100644 --- a/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java +++ b/Forge/src/main/java/tschipp/carryon/events/CommonEvents.java @@ -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; } } diff --git a/Forge/src/main/java/tschipp/carryon/platform/ForgePlatformHelper.java b/Forge/src/main/java/tschipp/carryon/platform/ForgePlatformHelper.java index 8d24bb7..12f42ae 100644 --- a/Forge/src/main/java/tschipp/carryon/platform/ForgePlatformHelper.java +++ b/Forge/src/main/java/tschipp/carryon/platform/ForgePlatformHelper.java @@ -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); + } }