diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index dbb8e1a36..e002678a6 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -143,6 +143,8 @@ public class AllBlockPartials { CRAFTING_BLUEPRINT_1x1 = entity("crafting_blueprint_small"), CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"), CRAFTING_BLUEPRINT_3x3 = entity("crafting_blueprint_large"), + + TRAIN_HAT = entity("train_hat"), COUPLING_ATTACHMENT = entity("minecart_coupling/attachment"), COUPLING_RING = entity("minecart_coupling/ring"), COUPLING_CONNECTOR = entity("minecart_coupling/connector") diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java index 880f3a1a0..edb929582 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java @@ -18,6 +18,7 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.DyeColor; @@ -161,6 +162,8 @@ public class SeatBlock extends Block { seat.setPos(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f); world.addFreshEntity(seat); entity.startRiding(seat, true); + if (entity instanceof TamableAnimal ta) + ta.setInSittingPose(true); } public DyeColor getColor() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java index 15a795f08..761a6c30b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java @@ -13,6 +13,13 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.TamableAnimal; +import net.minecraft.world.entity.animal.Cat; +import net.minecraft.world.entity.animal.Parrot; +import net.minecraft.world.entity.animal.Wolf; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.entity.monster.Skeleton; +import net.minecraft.world.entity.monster.Slime; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -45,6 +52,30 @@ public class SeatEntity extends Entity implements IEntityAdditionalSpawnData { setBoundingBox(bb.move(diff)); } + @Override + protected void positionRider(Entity pEntity, Entity.MoveFunction pCallback) { + if (!this.hasPassenger(pEntity)) + return; + double d0 = this.getY() + this.getPassengersRidingOffset() + pEntity.getMyRidingOffset(); + pCallback.accept(pEntity, this.getX(), d0 + getCustomEntitySeatOffset(pEntity), this.getZ()); + } + + public static double getCustomEntitySeatOffset(Entity entity) { + if (entity instanceof Slime) + return 0.25f; + if (entity instanceof Parrot) + return 1 / 16f; + if (entity instanceof Skeleton) + return 1 / 8f; + if (entity instanceof Creeper) + return 1 / 8f; + if (entity instanceof Cat) + return 1 / 8f; + if (entity instanceof Wolf) + return 1 / 16f; + return 0; + } + @Override public void setDeltaMovement(Vec3 p_213317_1_) {} @@ -69,6 +100,8 @@ public class SeatEntity extends Entity implements IEntityAdditionalSpawnData { @Override protected void removePassenger(Entity entity) { super.removePassenger(entity); + if (entity instanceof TamableAnimal ta) + ta.setInSittingPose(false); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index fe9401d56..a1a0acabf 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -51,6 +51,7 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.decoration.HangingEntity; import net.minecraft.world.entity.player.Player; @@ -120,6 +121,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit } } passenger.startRiding(this, true); + if (passenger instanceof TamableAnimal ta) + ta.setInSittingPose(true); if (level.isClientSide) return; contraption.getSeatMapping() @@ -132,6 +135,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit protected void removePassenger(Entity passenger) { Vec3 transformedVector = getPassengerPosition(passenger, 1); super.removePassenger(passenger); + if (passenger instanceof TamableAnimal ta) + ta.setInSittingPose(false); if (level.isClientSide) return; if (transformedVector != null) @@ -150,7 +155,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit Vec3 transformedVector = getPassengerPosition(passenger, 1); if (transformedVector == null) return; - callback.accept(passenger, transformedVector.x, transformedVector.y, transformedVector.z); + callback.accept(passenger, transformedVector.x, + transformedVector.y + SeatEntity.getCustomEntitySeatOffset(passenger) - 1 / 8f, transformedVector.z); } protected Vec3 getPassengerPosition(Entity passenger, float partialTicks) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java index 9dbb767a8..501571e5c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java @@ -52,6 +52,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { SynchedEntityData.defineId(CarriageContraptionEntity.class, AllEntityDataSerializers.CARRIAGE_DATA); private static final EntityDataAccessor> TRACK_GRAPH = SynchedEntityData.defineId(CarriageContraptionEntity.class, EntityDataSerializers.OPTIONAL_UUID); + private static final EntityDataAccessor SCHEDULED = + SynchedEntityData.defineId(CarriageContraptionEntity.class, EntityDataSerializers.BOOLEAN); public UUID trainId; public int carriageIndex; @@ -79,6 +81,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { super.defineSynchedData(); entityData.define(CARRIAGE_DATA, new CarriageSyncData()); entityData.define(TRACK_GRAPH, Optional.empty()); + entityData.define(SCHEDULED, false); } public void syncCarriage() { @@ -113,6 +116,10 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { private CarriageSyncData getCarriageData() { return entityData.get(CARRIAGE_DATA); } + + public boolean hasSchedule() { + return entityData.get(SCHEDULED); + } public static CarriageContraptionEntity create(Level world, CarriageContraption contraption) { CarriageContraptionEntity entity = @@ -167,6 +174,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { CarriageSyncData carriageData = getCarriageData(); if (!level.isClientSide) { + entityData.set(SCHEDULED, carriage.train.runtime.getSchedule() != null); if (tickCount % getType().updateInterval() == 0 && carriageData.isDirty()) { entityData.set(CARRIAGE_DATA, null); entityData.set(CARRIAGE_DATA, carriageData); @@ -257,9 +265,9 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { public Couple checkConductors() { Couple sides = Couple.create(false, false); - if (!(contraption instanceof CarriageContraption cc)) return sides; + sides.setFirst(cc.blazeBurnerConductors.getFirst()); sides.setSecond(cc.blazeBurnerConductors.getSecond()); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatArmorLayer.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatArmorLayer.java new file mode 100644 index 000000000..8e459a22b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatArmorLayer.java @@ -0,0 +1,175 @@ +package com.simibubi.create.content.logistics.trains.management.schedule; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; +import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.foundation.mixin.accessor.AgeableListModelAccessor; +import com.simibubi.create.foundation.render.CachedBufferer; +import com.simibubi.create.foundation.utility.Couple; + +import net.minecraft.client.model.AgeableListModel; +import net.minecraft.client.model.AxolotlModel; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.HierarchicalModel; +import net.minecraft.client.model.LavaSlimeModel; +import net.minecraft.client.model.SlimeModel; +import net.minecraft.client.model.WolfModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.ModelPart.Cube; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +public class TrainHatArmorLayer> extends RenderLayer { + + private Vec3 offset; + + public TrainHatArmorLayer(RenderLayerParent renderer, Vec3 offset) { + super(renderer); + this.offset = offset; + } + + @Override + public void render(PoseStack ms, MultiBufferSource buffer, int light, LivingEntity entity, float yaw, float pitch, + float pt, float p_225628_8_, float p_225628_9_, float p_225628_10_) { + if (!shouldRenderOn(entity)) + return; + + M entityModel = getParentModel(); + RenderType renderType = Sheets.cutoutBlockSheet(); + ms.pushPose(); + + boolean valid = false; + TransformStack msr = TransformStack.cast(ms); + + if (entityModel instanceof AgeableListModel model) { + if (model.young) { + if (model.scaleHead) { + float f = 1.5F / model.babyHeadScale; + ms.scale(f, f, f); + } + ms.translate(0.0D, model.babyYHeadOffset / 16.0F, model.babyZHeadOffset / 16.0F); + } + + ModelPart head = getHeadPart(model); + if (head != null) { + head.translateAndRotate(ms); + + if (model instanceof WolfModel) + head = head.getChild("real_head"); + if (model instanceof AxolotlModel) + head = head.getChild("head"); + + ms.translate(offset.x / 16f, offset.y / 16f, offset.z / 16f); + + if (!head.isEmpty()) { + Cube cube = head.cubes.get(0); + ms.translate(offset.x / 16f, (cube.minY - cube.maxY + offset.y) / 16f, offset.z / 16f); + float max = Math.max(cube.maxX - cube.minX, cube.maxZ - cube.minZ) / 8f; + ms.scale(max, max, max); + } + + valid = true; + } + } + + else if (entityModel instanceof HierarchicalModel model) { + boolean slime = model instanceof SlimeModel || model instanceof LavaSlimeModel; + ModelPart head = model.root().children.get(slime ? "cube" : "head"); + + if (head != null) { + head.translateAndRotate(ms); + + if (!head.isEmpty()) { + Cube cube = head.cubes.get(0); + ms.translate(offset.x, (cube.minY - cube.maxY + offset.y) / 16f, offset.z / 16f); + float max = Math.max(cube.maxX - cube.minX, cube.maxZ - cube.minZ) / (slime ? 6.5f : 8f); + ms.scale(max, max, max); + } + + valid = true; + } + } + + if (valid) { + ms.scale(1, -1, -1); + ms.translate(0, -2.25f / 16f, 0); + msr.rotateX(-8.5f); + BlockState air = Blocks.AIR.defaultBlockState(); + CachedBufferer.partial(AllBlockPartials.TRAIN_HAT, air) + .forEntityRender() + .light(light) + .renderInto(ms, buffer.getBuffer(renderType)); + } + + ms.popPose(); + } + + private boolean shouldRenderOn(LivingEntity entity) { + if (entity == null) + return false; + if (!entity.isPassenger()) + return false; + Entity vehicle = entity.getVehicle(); + if (!(vehicle instanceof CarriageContraptionEntity cce)) + return false; + if (!cce.hasSchedule()) + return false; + Contraption contraption = cce.getContraption(); + if (!(contraption instanceof CarriageContraption cc)) + return false; + BlockPos seatOf = cc.getSeatOf(entity.getUUID()); + if (seatOf == null) + return false; + Couple validSides = cc.conductorSeats.get(seatOf); + return validSides != null; + } + + public static void registerOnAll(EntityRenderDispatcher renderManager) { + for (EntityRenderer renderer : renderManager.getSkinMap() + .values()) + registerOn(renderer); + for (EntityRenderer renderer : renderManager.renderers.values()) + registerOn(renderer); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static void registerOn(EntityRenderer entityRenderer) { + if (!(entityRenderer instanceof LivingEntityRenderer)) + return; + + LivingEntityRenderer livingRenderer = (LivingEntityRenderer) entityRenderer; + EntityModel model = livingRenderer.getModel(); + + if (!(model instanceof HierarchicalModel) && !(model instanceof AgeableListModel)) + return; + + Vec3 offset = TrainHatOffsets.getOffset(model); + TrainHatArmorLayer layer = new TrainHatArmorLayer<>(livingRenderer, offset); + livingRenderer.addLayer((TrainHatArmorLayer) layer); + } + + private static ModelPart getHeadPart(AgeableListModel model) { + for (ModelPart part : ((AgeableListModelAccessor) model).create$callHeadParts()) + return part; + for (ModelPart part : ((AgeableListModelAccessor) model).create$callBodyParts()) + return part; + return null; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java new file mode 100644 index 000000000..f1f7ddc98 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/schedule/TrainHatOffsets.java @@ -0,0 +1,101 @@ +package com.simibubi.create.content.logistics.trains.management.schedule; + +import net.minecraft.client.model.AgeableListModel; +import net.minecraft.client.model.AxolotlModel; +import net.minecraft.client.model.BeeModel; +import net.minecraft.client.model.BlazeModel; +import net.minecraft.client.model.ChickenModel; +import net.minecraft.client.model.CowModel; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.FoxModel; +import net.minecraft.client.model.GuardianModel; +import net.minecraft.client.model.HierarchicalModel; +import net.minecraft.client.model.HoglinModel; +import net.minecraft.client.model.IronGolemModel; +import net.minecraft.client.model.LavaSlimeModel; +import net.minecraft.client.model.OcelotModel; +import net.minecraft.client.model.PandaModel; +import net.minecraft.client.model.ParrotModel; +import net.minecraft.client.model.PigModel; +import net.minecraft.client.model.QuadrupedModel; +import net.minecraft.client.model.SheepModel; +import net.minecraft.client.model.SlimeModel; +import net.minecraft.client.model.SnowGolemModel; +import net.minecraft.client.model.SpiderModel; +import net.minecraft.client.model.WolfModel; +import net.minecraft.world.phys.Vec3; + +public class TrainHatOffsets { + + // sorry + public static Vec3 getOffset(EntityModel model) { + + float x = 0; + float y = 0; + float z = 0; + + if (model instanceof AgeableListModel) { + if (model instanceof WolfModel) { + x += .5f; + y += 1.5f; + z += .25f; + } else if (model instanceof OcelotModel) { + y += 1f; + z -= .25f; + } else if (model instanceof ChickenModel) { + z -= .25f; + } else if (model instanceof FoxModel) { + x += .5f; + y += 2f; + z -= 1f; + } else if (model instanceof QuadrupedModel) { + y += 2f; + + if (model instanceof CowModel) + z -= 1.25f; + else if (model instanceof PandaModel) + z += .5f; + else if (model instanceof PigModel) + z -= 2f; + else if (model instanceof SheepModel) { + z -= .75f; + y -= 1.5f; + + } + } else if (model instanceof HoglinModel) + z -= 4.5f; + else if (model instanceof BeeModel) { + z -= .75f; + y -= 4f; + } else if (model instanceof AxolotlModel) { + z -= 5f; + y += .5f; + } + } + + if (model instanceof HierarchicalModel) { + if (model instanceof BlazeModel) + y += 4; + else if (model instanceof GuardianModel) + y += 20; + else if (model instanceof IronGolemModel) { + z -= 1.5f; + y -= 2f; + } else if (model instanceof SnowGolemModel) { + z -= .75f; + y -= 3f; + } else if (model instanceof SlimeModel || model instanceof LavaSlimeModel) { + y += 22; + } else if (model instanceof SpiderModel) { + z -= 3.5f; + y += 2f; + } else if (model instanceof ParrotModel) { + z -= 1.5f; + } + } + + return new Vec3(x, y, z); + + } + +} diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 08f3df72d..6bd26fcc7 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -37,6 +37,7 @@ import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler; import com.simibubi.create.content.logistics.trains.entity.CarriageCouplingRenderer; import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem; +import com.simibubi.create.content.logistics.trains.management.schedule.TrainHatArmorLayer; import com.simibubi.create.content.logistics.trains.track.TrackPlacement; import com.simibubi.create.content.logistics.trains.track.TrackRemoval; import com.simibubi.create.foundation.config.AllConfigs; @@ -352,6 +353,7 @@ public class ClientEvents { EntityRenderDispatcher dispatcher = Minecraft.getInstance() .getEntityRenderDispatcher(); CopperBacktankArmorLayer.registerOnAll(dispatcher); + TrainHatArmorLayer.registerOnAll(dispatcher); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/foundation/mixin/accessor/AgeableListModelAccessor.java b/src/main/java/com/simibubi/create/foundation/mixin/accessor/AgeableListModelAccessor.java new file mode 100644 index 000000000..9f2680736 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/accessor/AgeableListModelAccessor.java @@ -0,0 +1,15 @@ +package com.simibubi.create.foundation.mixin.accessor; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.client.model.AgeableListModel; +import net.minecraft.client.model.geom.ModelPart; + +@Mixin(AgeableListModel.class) +public interface AgeableListModelAccessor { + @Invoker("headParts") + Iterable create$callHeadParts(); + @Invoker("bodyParts") + Iterable create$callBodyParts(); +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index dbf7cf3d1..098382e16 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -29,3 +29,12 @@ public net.minecraft.world.level.biome.BiomeManager f_47863_ # biomeZoomSeed public net.minecraft.world.level.block.entity.BeaconBlockEntity f_58648_ # beamSections public net.minecraft.world.level.chunk.HashMapPalette f_62658_ # values public net.minecraft.world.level.chunk.PaletteResize + +public net.minecraft.client.model.geom.ModelPart f_104212_ # cubes +public net.minecraft.client.model.geom.ModelPart f_104213_ # children +public net.minecraft.client.model.AgeableListModel f_102007_ # scaleHead +public net.minecraft.client.model.AgeableListModel f_170338_ # babyYHeadOffset +public net.minecraft.client.model.AgeableListModel f_170339_ # babyZHeadOffset +public net.minecraft.client.model.AgeableListModel f_102010_ # babyHeadScale +public net.minecraft.client.model.AgeableListModel f_102011_ # babyBodyScale +public net.minecraft.client.model.AgeableListModel f_102012_ # bodyYOffset \ No newline at end of file diff --git a/src/main/resources/assets/create/models/entity/train_hat.json b/src/main/resources/assets/create/models/entity/train_hat.json new file mode 100644 index 000000000..28cc936ef --- /dev/null +++ b/src/main/resources/assets/create/models/entity/train_hat.json @@ -0,0 +1,59 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:entity/train_hat", + "particle": "create:entity/train_hat" + }, + "elements": [ + { + "from": [-4.5, 0, -4.5], + "to": [4.5, 3, 4.5], + "rotation": {"angle": 0, "axis": "x", "origin": [0, 0, -1.5]}, + "faces": { + "north": {"uv": [12, 4, 15, 13], "rotation": 90, "texture": "#0"}, + "east": {"uv": [9, 4, 12, 13], "rotation": 270, "texture": "#0"}, + "south": {"uv": [0, 2, 9, 5], "rotation": 180, "texture": "#0"}, + "west": {"uv": [9, 4, 12, 13], "rotation": 90, "texture": "#0"}, + "up": {"uv": [0, 5, 9, 14], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [4.5, 0, -4.5], + "to": [-4.5, 3, 4.5], + "rotation": {"angle": 0, "axis": "x", "origin": [0, 0, -1.5]}, + "faces": { + "north": {"uv": [12, 4, 15, 13], "rotation": 90, "texture": "#0"}, + "east": {"uv": [9, 4, 12, 13], "rotation": 270, "texture": "#0"}, + "south": {"uv": [0, 2, 9, 5], "rotation": 180, "texture": "#0"}, + "west": {"uv": [9, 4, 12, 13], "rotation": 90, "texture": "#0"}, + "up": {"uv": [0, 5, 9, 14], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [-4.7, 0, -0.3], + "to": [4.7, 2, 4.7], + "rotation": {"angle": 0, "axis": "x", "origin": [0, 0, -1.5]}, + "faces": { + "east": {"uv": [2, 16, 7, 14], "rotation": 180, "texture": "#0"}, + "south": {"uv": [7, 14, 16, 16], "texture": "#0"}, + "west": {"uv": [2, 14, 7, 16], "texture": "#0"} + } + }, + { + "from": [-4.5, 1.3961, 4.04328], + "to": [4.5, 2.3961, 6.04328], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 0, -1.5]}, + "faces": { + "up": {"uv": [0, 0, 9, 2], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [-4.5, 2.31684, 3.9585], + "to": [4.5, 3.31684, 5.9585], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 0, -1.5]}, + "faces": { + "down": {"uv": [0, 0, 9, 2], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/entity/train_hat.png b/src/main/resources/assets/create/textures/entity/train_hat.png new file mode 100644 index 000000000..b7e599e0a Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/train_hat.png differ diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index d824aacef..4952c31b6 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -19,6 +19,7 @@ "HeavyBootsOnPlayerMixin", "ModelDataRefreshMixin", "WindowResizeMixin", + "accessor.AgeableListModelAccessor", "accessor.GameRendererAccessor", "accessor.ParticleEngineAccessor" ],