From 93354a6783989e6b229ab8bc706420a979e6f52c Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 16 Dec 2024 22:01:12 +0100 Subject: [PATCH 1/5] Update documentation --- .../model/armour/ArmourTextureResolver.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/minelittlepony/client/model/armour/ArmourTextureResolver.java b/src/main/java/com/minelittlepony/client/model/armour/ArmourTextureResolver.java index 3c683bad..bb0ef097 100644 --- a/src/main/java/com/minelittlepony/client/model/armour/ArmourTextureResolver.java +++ b/src/main/java/com/minelittlepony/client/model/armour/ArmourTextureResolver.java @@ -20,17 +20,22 @@ import java.util.stream.Stream; /** * The default texture resolver used by Mine Little Pony. *

- * Textures found are of the format: + * Textures are resolved by taking the original path and replacing "humanoid" with "ponified". *

- * namespace:textures/models/armor/material_layer_[outer|1|inner|2](_overlay)(_custom_#)(_pony).png - *

- *

- * - Textures ending _pony are returned first if found - * - _custom_# corresponds to a CustomModelData NBT integer value on the item passed, if available - * - _overlay is used for the second layer of leather armour, or mods if they make use of it. Can be anything! Check your mod's documentation for values supported. - * - outer|1|inner|2 is the layer. outer is an alias for 1 and inner is an alias for 2. Named versions are used instead of numbers if available. - * - the "minecraft" namespace is always replaced with "minelittlepony" + * For example: + * + * assets/minecraft/textures/entity/equipment/humanoid/iron.png + * Becomes: assets/minecraft/textures/entity/equipment/ponified/iron.png + * + * assets/minecraft/textures/entity/equipment/humanoid_leggings/iron.png + * Becomes: assets/minecraft/textures/entity/equipment/ponified_leggings/iron.png *

+ * In addition to the above, unlike in vanilla, all pony armour pieces make use of both the regular and leggings textures to show in two different layers. + * In general, the textures are distributed as follows: + * Helmet = ponified_leggings + * Chestplate = ponified (banner) + ponified_leggings (body plates) + * Leggings = ponified_leggings (leg chainmail) + * Boots = ponified (knee guards and boots) */ public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableResourceReloadListener { public static final Identifier ID = MineLittlePony.id("armor_textures"); From e9f70d6a6e099e2a3e1cae0da35e9e130178a256 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 16 Dec 2024 22:34:41 +0100 Subject: [PATCH 2/5] Fix armour model loading locations and clean up a little bit --- .../com/minelittlepony/api/model/Models.java | 21 ++++---------- .../client/model/PlayerModelKey.java | 14 ++++------ .../model/armour/ArmorModelRegistry.java | 28 +++++++++++++------ .../client/model/armour/ArmourVariant.java | 12 ++++---- .../armour/PonifiedEquipmentRenderer.java | 2 +- .../client/render/EquineRenderManager.java | 3 +- .../blockentity/skull/PlayerPonySkull.java | 2 +- .../render/entity/feature/SkullFeature.java | 3 -- .../entity/npc/AbstractNpcRenderer.java | 7 +++-- .../render/entity/npc/TraderRenderer.java | 2 +- .../com/minelittlepony/util/MathUtil.java | 1 + 11 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/minelittlepony/api/model/Models.java b/src/main/java/com/minelittlepony/api/model/Models.java index f5c2dde8..9149edca 100644 --- a/src/main/java/com/minelittlepony/api/model/Models.java +++ b/src/main/java/com/minelittlepony/api/model/Models.java @@ -4,15 +4,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.equipment.EquipmentModel; import net.minecraft.util.Util; -import org.jetbrains.annotations.Nullable; - import com.minelittlepony.client.model.AbstractPonyModel; -import com.minelittlepony.client.model.PlayerModelKey; import com.minelittlepony.client.model.armour.*; import com.minelittlepony.mson.api.ModelKey; +import com.minelittlepony.mson.api.MsonModel; -import java.util.*; -import java.util.function.Consumer; import java.util.function.Function; /** @@ -23,20 +19,15 @@ public record Models> ( M body ) { - public Models(PlayerModelKey playerModelKey, boolean slimArms, @Nullable Consumer initializer) { - this(Util.memoize(key -> key.createModel(playerModelKey.armorFactory())), playerModelKey.getKey(slimArms).createModel()); - if (initializer != null) { - initializer.accept(body); - } + public Models(ModelKey modelKey, MsonModel.Factory> armorFactory) { + this(Util.memoize(key -> key.createModel(armorFactory)), modelKey.createModel()); } - public Models(ModelKey key) { + public Models(ModelKey key) { this(Util.memoize(k -> k.createModel()), key.createModel()); } - public Optional> getArmourModel(ItemStack stack, EquipmentModel.LayerType layerType, ArmourVariant variant) { - return ArmorModelRegistry.getModelKey(stack.getItem(), layerType) - .or(() -> variant.getDefaultModel(layerType)) - .map(armor); + public AbstractPonyModel getArmourModel(ItemStack stack, EquipmentModel.LayerType layerType, ArmourVariant variant) { + return armor.apply(ArmorModelRegistry.getModelKey(stack.getItem(), layerType, variant)); } } diff --git a/src/main/java/com/minelittlepony/client/model/PlayerModelKey.java b/src/main/java/com/minelittlepony/client/model/PlayerModelKey.java index 65d42f9f..92187a27 100644 --- a/src/main/java/com/minelittlepony/client/model/PlayerModelKey.java +++ b/src/main/java/com/minelittlepony/client/model/PlayerModelKey.java @@ -3,8 +3,6 @@ package com.minelittlepony.client.model; import net.minecraft.client.model.Model; import net.minecraft.client.model.ModelPart; -import org.jetbrains.annotations.Nullable; - import com.minelittlepony.api.model.Models; import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.client.MineLittlePony; @@ -28,15 +26,15 @@ public record PlayerModelKey> ( ); } - public ModelKey getKey(boolean slimArms) { - return slimArms ? alexKey : steveKey; + public Models alex() { + return new Models(alexKey, armorFactory); } - public Models create(boolean slimArms) { - return create(slimArms, null); + public Models steve() { + return new Models(steveKey, armorFactory); } - public Models create(boolean slimArms, @Nullable Consumer initializer) { - return new Models<>(this, slimArms, initializer); + public Models create(boolean slimArms) { + return slimArms ? alex() : steve(); } } diff --git a/src/main/java/com/minelittlepony/client/model/armour/ArmorModelRegistry.java b/src/main/java/com/minelittlepony/client/model/armour/ArmorModelRegistry.java index 0dd87485..d1bee93b 100644 --- a/src/main/java/com/minelittlepony/client/model/armour/ArmorModelRegistry.java +++ b/src/main/java/com/minelittlepony/client/model/armour/ArmorModelRegistry.java @@ -2,25 +2,35 @@ package com.minelittlepony.client.model.armour; import net.minecraft.item.Item; import net.minecraft.item.equipment.EquipmentModel; -import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.Mson; +import com.minelittlepony.util.ResourceUtil; import java.util.*; public interface ArmorModelRegistry { static final Map>>> REGISTRY = new HashMap<>(); - public static Optional>> getModelKey(Item item, EquipmentModel.LayerType layerType) { - Identifier id = Registries.ITEM.getId(item); - if (id.getNamespace().equals("minecraft")) { - return Optional.empty(); - } - return REGISTRY.computeIfAbsent(id.withPath(p -> "armor/" + layerType.name().toLowerCase(Locale.ROOT) + "_" + p + ".json"), i -> { - return Optional.of(Mson.getInstance().registerModel(i, PonyArmourModel::new)); - }).filter(key -> key.getModelData().isPresent()); + @SuppressWarnings("deprecation") + public static ModelKey> getModelKey(Item item, EquipmentModel.LayerType layerType, ArmourVariant variant) { + return item.getRegistryEntry().getKey().map(key -> key.getValue()).flatMap(id -> { + if (id.getNamespace().equals("minecraft")) { + return Optional.empty(); + } + return REGISTRY.computeIfAbsent(id.withPath(p -> ResourceUtil.format("armor/%s_%s.json", layerName(layerType), p)), i -> { + return Optional.of(Mson.getInstance().registerModel(i, PonyArmourModel::new)); + }).filter(key -> key.getModelData().isPresent()); + }).orElse(variant.getDefaultModel(layerType)); + } + + private static String layerName(EquipmentModel.LayerType layerType) { + return switch (layerType) { + case HUMANOID -> "outer"; + case HUMANOID_LEGGINGS -> "inner"; + default -> layerType.name().toLowerCase(Locale.ROOT); + }; } } diff --git a/src/main/java/com/minelittlepony/client/model/armour/ArmourVariant.java b/src/main/java/com/minelittlepony/client/model/armour/ArmourVariant.java index dda97bd9..52195d61 100644 --- a/src/main/java/com/minelittlepony/client/model/armour/ArmourVariant.java +++ b/src/main/java/com/minelittlepony/client/model/armour/ArmourVariant.java @@ -6,22 +6,20 @@ import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.ModelType; import com.minelittlepony.mson.api.ModelKey; -import java.util.Optional; - public enum ArmourVariant { NORMAL(ModelType.INNER_PONY_ARMOR, ModelType.OUTER_PONY_ARMOR), LEGACY(ModelType.INNER_VANILLA_ARMOR, ModelType.OUTER_VANILLA_ARMOR), TRIM(ModelType.INNER_VANILLA_ARMOR, ModelType.OUTER_VANILLA_ARMOR); - private final Optional>> innerModel; - private final Optional>> outerModel; + private final ModelKey> innerModel; + private final ModelKey> outerModel; ArmourVariant(ModelKey> inner, ModelKey> outer) { - this.innerModel = Optional.of(inner); - this.outerModel = Optional.of(outer); + this.innerModel = inner; + this.outerModel = outer; } - public Optional>> getDefaultModel(EquipmentModel.LayerType layerType) { + public ModelKey> getDefaultModel(EquipmentModel.LayerType layerType) { return layerType == EquipmentModel.LayerType.HUMANOID_LEGGINGS ? innerModel : outerModel; } } diff --git a/src/main/java/com/minelittlepony/client/model/armour/PonifiedEquipmentRenderer.java b/src/main/java/com/minelittlepony/client/model/armour/PonifiedEquipmentRenderer.java index 45fcec0d..f932a3ce 100644 --- a/src/main/java/com/minelittlepony/client/model/armour/PonifiedEquipmentRenderer.java +++ b/src/main/java/com/minelittlepony/client/model/armour/PonifiedEquipmentRenderer.java @@ -82,7 +82,7 @@ public class PonifiedEquipmentRenderer extends EquipmentRenderer { VertexConsumer armorConsumer = getArmorVertexConsumer(plugin, equipmentSlot, vertices, layerTexture, layerType, hasGlint); if (armorConsumer != null) { ArmourVariant variant = layer.usePlayerTexture() ? ArmourVariant.LEGACY : armorTexture.variant(); - AbstractPonyModel model = models.getArmourModel(stack, layerType, variant).orElse(null); + AbstractPonyModel model = models.getArmourModel(stack, layerType, variant); if (model != null) { model.setAngles(entity); models.body().copyTransforms(model); diff --git a/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java b/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java index 09275e60..98004759 100644 --- a/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java +++ b/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java @@ -62,9 +62,8 @@ public class EquineRenderManager< context.setModel(models.body()); } - @SuppressWarnings({"rawtypes", "unchecked"}) public EquineRenderManager(PonyRenderContext context, Transformer transformer, ModelKey key) { - this(context, transformer, new Models(key)); + this(context, transformer, new Models<>(key)); } public void setModelsLookup(Function> modelsLookup) { diff --git a/src/main/java/com/minelittlepony/client/render/blockentity/skull/PlayerPonySkull.java b/src/main/java/com/minelittlepony/client/render/blockentity/skull/PlayerPonySkull.java index a7ae1265..46cefd3c 100644 --- a/src/main/java/com/minelittlepony/client/render/blockentity/skull/PlayerPonySkull.java +++ b/src/main/java/com/minelittlepony/client/render/blockentity/skull/PlayerPonySkull.java @@ -62,7 +62,7 @@ public class PlayerPonySkull implements ISkull { return false; } } - ponyHead = modelCache.computeIfAbsent(ModelType.getPlayerModel(race), key -> key.getKey(false).createModel()); + ponyHead = modelCache.computeIfAbsent(ModelType.getPlayerModel(race), key -> key.steveKey().createModel()); state.pony = pony; state.race = pony.race(); state.attributes.size = pony.size(); diff --git a/src/main/java/com/minelittlepony/client/render/entity/feature/SkullFeature.java b/src/main/java/com/minelittlepony/client/render/entity/feature/SkullFeature.java index 043f8893..0e0c3364 100644 --- a/src/main/java/com/minelittlepony/client/render/entity/feature/SkullFeature.java +++ b/src/main/java/com/minelittlepony/client/render/entity/feature/SkullFeature.java @@ -28,14 +28,11 @@ public class SkullFeature< private final HeadFeatureRenderer.HeadTransformation headTransformation; - private final boolean scaleForChild; - public SkullFeature(PonyRenderContext context, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer, HeadFeatureRenderer.HeadTransformation headTransformation, boolean scaleForChild) { super(context); this.itemRenderer = itemRenderer; this.headTransformation = headTransformation; - this.scaleForChild = scaleForChild; } @Override diff --git a/src/main/java/com/minelittlepony/client/render/entity/npc/AbstractNpcRenderer.java b/src/main/java/com/minelittlepony/client/render/entity/npc/AbstractNpcRenderer.java index 88df81e9..33b4dd0c 100644 --- a/src/main/java/com/minelittlepony/client/render/entity/npc/AbstractNpcRenderer.java +++ b/src/main/java/com/minelittlepony/client/render/entity/npc/AbstractNpcRenderer.java @@ -5,6 +5,7 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.util.Identifier; import net.minecraft.village.*; +import com.minelittlepony.api.model.Models; import com.minelittlepony.api.model.gear.Gear; import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Wearable; @@ -19,13 +20,15 @@ abstract class AbstractNpcRenderer< private final NpcClothingFeature, AbstractNpcRenderer> clothing; public AbstractNpcRenderer(EntityRendererFactory.Context context, String type, TextureSupplier textureSupplier, TextureSupplier formatter) { - super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), SillyPonyTextureSupplier.create(textureSupplier, formatter)); + super(context, ModelType.getPlayerModel(Race.EARTH).steveKey(), SillyPonyTextureSupplier.create(textureSupplier, formatter)); clothing = new NpcClothingFeature<>(this, type); this.manager.setModelsLookup(race -> { if (race.isHuman()) { race = Race.EARTH; } - return ModelType.getPlayerModel(race).create(false, this::initializeModel); + Models> models = ModelType.getPlayerModel(race).steve(); + initializeModel(models.body()); + return models; }); addFeature(clothing); } diff --git a/src/main/java/com/minelittlepony/client/render/entity/npc/TraderRenderer.java b/src/main/java/com/minelittlepony/client/render/entity/npc/TraderRenderer.java index af741842..cd266247 100644 --- a/src/main/java/com/minelittlepony/client/render/entity/npc/TraderRenderer.java +++ b/src/main/java/com/minelittlepony/client/render/entity/npc/TraderRenderer.java @@ -15,7 +15,7 @@ public class TraderRenderer extends PonyRenderer Date: Mon, 16 Dec 2024 22:40:41 +0100 Subject: [PATCH 3/5] Fixed cape offset from the body when lying down --- .../client/render/entity/EnderStallionRenderer.java | 10 ++-------- .../client/render/entity/feature/CapeFeature.java | 5 +---- .../render/entity/feature/GlowingEyesFeature.java | 12 +++--------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/minelittlepony/client/render/entity/EnderStallionRenderer.java b/src/main/java/com/minelittlepony/client/render/entity/EnderStallionRenderer.java index 3b63258c..614ddff3 100644 --- a/src/main/java/com/minelittlepony/client/render/entity/EnderStallionRenderer.java +++ b/src/main/java/com/minelittlepony/client/render/entity/EnderStallionRenderer.java @@ -8,7 +8,6 @@ import com.minelittlepony.client.model.entity.EnderStallionModel; import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature; import com.minelittlepony.client.render.entity.feature.HeldItemFeature; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; -import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature.IGlowingRenderer; import net.minecraft.block.BlockState; import net.minecraft.client.render.VertexConsumerProvider; @@ -24,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Random; -public class EnderStallionRenderer extends PonyRenderer implements IGlowingRenderer { +public class EnderStallionRenderer extends PonyRenderer { public static final Identifier ENDERMAN = MineLittlePony.id("textures/entity/enderman/enderman_pony.png"); private static final Identifier EYES = MineLittlePony.id("textures/entity/enderman/enderman_pony_eyes.png"); @@ -39,7 +38,7 @@ public class EnderStallionRenderer extends PonyRenderer((PonyRenderer)this, context)); - addPonyFeature(new GlowingEyesFeature(this)); + addPonyFeature(new GlowingEyesFeature(this, EYES)); } @Override @@ -81,11 +80,6 @@ public class EnderStallionRenderer extends PonyRenderer & IGlowingRenderer> GlowingEyesFeature(V renderer) { - super(renderer); - layer = RenderLayer.getEyes(renderer.getEyeTexture()); + public GlowingEyesFeature(PonyRenderContext context, Identifier texture) { + super(context.upcast()); + layer = RenderLayer.getEyes(texture); } @Override public RenderLayer getEyesTexture() { return layer; } - - public interface IGlowingRenderer { - Identifier getEyeTexture(); - } } From 2f0ad4bf3efb3f736608d75342042df775c4fe99 Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 16 Dec 2024 22:51:40 +0100 Subject: [PATCH 4/5] Fixed tails and necks rendering on spectator mode players, fixed spectators missing snouts and ears, and fixed spectators bodies rotating when flying --- .../minelittlepony/api/model/ModelAttributes.java | 1 + .../client/model/AbstractPonyModel.java | 1 + .../minelittlepony/client/model/part/PonyEars.java | 4 ++-- .../client/model/part/PonySnout.java | 2 +- .../minelittlepony/client/model/part/PonyTail.java | 14 ++++++++------ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/minelittlepony/api/model/ModelAttributes.java b/src/main/java/com/minelittlepony/api/model/ModelAttributes.java index 9d7306c6..d8c66ac4 100644 --- a/src/main/java/com/minelittlepony/api/model/ModelAttributes.java +++ b/src/main/java/com/minelittlepony/api/model/ModelAttributes.java @@ -144,6 +144,7 @@ public class ModelAttributes { isGoingFast &= zMotion > 0.4F; isGoingFast |= entity.isUsingRiptide(); isGoingFast |= entity.isGliding(); + isGoingFast &= !entity.isSpectator(); motionLerp = MathUtil.clampLimit(zMotion * 30, 1); diff --git a/src/main/java/com/minelittlepony/client/model/AbstractPonyModel.java b/src/main/java/com/minelittlepony/client/model/AbstractPonyModel.java index 56816934..3543cc0f 100644 --- a/src/main/java/com/minelittlepony/client/model/AbstractPonyModel.java +++ b/src/main/java/com/minelittlepony/client/model/AbstractPonyModel.java @@ -86,6 +86,7 @@ public abstract class AbstractPonyModel extends Clien protected void setModelVisibilities(T state) { resetPivot(head, neck, leftArm, rightArm, leftLeg, rightLeg); hat.visible = head.visible && !state.attributes.isHorsey; + neck.visible = body.visible; if (state.attributes.isHorsey) { neck.visible = head.visible; } else { diff --git a/src/main/java/com/minelittlepony/client/model/part/PonyEars.java b/src/main/java/com/minelittlepony/client/model/part/PonyEars.java index deefe4dd..b1cc3339 100644 --- a/src/main/java/com/minelittlepony/client/model/part/PonyEars.java +++ b/src/main/java/com/minelittlepony/client/model/part/PonyEars.java @@ -57,8 +57,8 @@ public class PonyEars implements SubModel, MsonModel { @Override public void setVisible(boolean visible, PonyRenderState state) { - right.visible = visible && !state.race.isHuman(); - left.visible = visible && !state.race.isHuman(); + right.visible = !state.race.isHuman(); + left.visible = !state.race.isHuman(); if (state.attributes.isHorsey) { left.pivotX = -1; diff --git a/src/main/java/com/minelittlepony/client/model/part/PonySnout.java b/src/main/java/com/minelittlepony/client/model/part/PonySnout.java index d5e599ea..f46d0aea 100644 --- a/src/main/java/com/minelittlepony/client/model/part/PonySnout.java +++ b/src/main/java/com/minelittlepony/client/model/part/PonySnout.java @@ -39,7 +39,7 @@ public class PonySnout implements SubModel, MsonModel { @Override public void setVisible(boolean visible, PonyRenderState state) { - visible &= !state.attributes.isHorsey + visible = !state.attributes.isHorsey && !state.attributes.metadata.race().isHuman() && PonyConfig.getInstance().snuzzles.get(); Gender gender = state.attributes.metadata.gender(); diff --git a/src/main/java/com/minelittlepony/client/model/part/PonyTail.java b/src/main/java/com/minelittlepony/client/model/part/PonyTail.java index b91acb7e..bed4ac64 100644 --- a/src/main/java/com/minelittlepony/client/model/part/PonyTail.java +++ b/src/main/java/com/minelittlepony/client/model/part/PonyTail.java @@ -92,14 +92,16 @@ public class PonyTail implements SubModel, MsonModel { @Override public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) { - stack.push(); - tail.rotate(stack); + if (tail.visible) { + stack.push(); + tail.rotate(stack); - for (int i = 0; i < segments.size(); i++) { - segments.get(i).render(stack, vertices, i, overlay, light, color); + for (int i = 0; i < segments.size(); i++) { + segments.get(i).render(stack, vertices, i, overlay, light, color); + } + + stack.pop(); } - - stack.pop(); } public static class Segment { From b6f4161e4b55c4265c22eadac80185a71e044a6e Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 16 Dec 2024 22:54:58 +0100 Subject: [PATCH 5/5] Fixed capes rotating too far when sneaking --- .../client/render/entity/feature/CapeFeature.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minelittlepony/client/render/entity/feature/CapeFeature.java b/src/main/java/com/minelittlepony/client/render/entity/feature/CapeFeature.java index 16d878c1..37b57191 100644 --- a/src/main/java/com/minelittlepony/client/render/entity/feature/CapeFeature.java +++ b/src/main/java/com/minelittlepony/client/render/entity/feature/CapeFeature.java @@ -17,6 +17,7 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.equipment.EquipmentModel; import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; public class CapeFeature extends CapeFeatureRenderer { @@ -54,7 +55,7 @@ public class CapeFeature extends CapeFeatureRenderer { matrices.translate(0, 0.34F, 0); model.transform((PlayerPonyRenderState)player, BodyPart.BODY, matrices); model.body.rotate(matrices); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(85)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(85 - model.body.pitch * MathHelper.DEGREES_PER_RADIAN)); if (player.baby) { matrices.scale(1.1F, 1.1F, 1.1F); }