Fix misaligned skulls when worn by ponies + implement pony piglin skulls

This commit is contained in:
Sollace 2024-05-05 17:42:57 +01:00
parent 405d9e2bbf
commit c6560513bc
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
5 changed files with 75 additions and 78 deletions

View file

@ -123,9 +123,9 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe
} }
@Override @Override
public void reload(ResourceManager var1) { public void reload(ResourceManager manager) {
clearCache(); clearCache();
PonySkullRenderer.reload(); PonySkullRenderer.INSTANCE.reload();
} }
@Override @Override

View file

@ -39,7 +39,7 @@ abstract class MixinSkullBlockEntityRenderer implements BlockEntityRenderer<Skul
SkullBlockEntityModel model, RenderLayer layer, SkullBlockEntityModel model, RenderLayer layer,
CallbackInfo info) { CallbackInfo info) {
if (!info.isCancelled() && PonySkullRenderer.renderSkull(direction, angle, poweredTicks, stack, renderContext, layer, lightUv)) { if (!info.isCancelled() && PonySkullRenderer.INSTANCE.renderSkull(direction, angle, poweredTicks, stack, renderContext, layer, lightUv)) {
info.cancel(); info.cancel();
} }
} }
@ -50,7 +50,7 @@ abstract class MixinSkullBlockEntityRenderer implements BlockEntityRenderer<Skul
+ ")Lnet/minecraft/client/render/RenderLayer;", at = @At("HEAD"), cancellable = true) + ")Lnet/minecraft/client/render/RenderLayer;", at = @At("HEAD"), cancellable = true)
private static void onGetRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile, CallbackInfoReturnable<RenderLayer> info) { private static void onGetRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile, CallbackInfoReturnable<RenderLayer> info) {
if (!info.isCancelled()) { if (!info.isCancelled()) {
RenderLayer result = PonySkullRenderer.getSkullRenderLayer(skullType, profile); RenderLayer result = PonySkullRenderer.INSTANCE.getSkullRenderLayer(skullType, profile);
if (result != null) { if (result != null) {
info.setReturnValue(result); info.setReturnValue(result);
} }

View file

@ -1,26 +1,35 @@
package com.minelittlepony.client.render.blockentity.skull; package com.minelittlepony.client.render.blockentity.skull;
import com.google.common.collect.Maps;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.ArmourLayer; import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.armour.ArmourRendererPlugin; import com.minelittlepony.client.model.armour.ArmourRendererPlugin;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.entity.SkeleponyRenderer; import com.minelittlepony.client.render.entity.*;
import com.minelittlepony.client.render.entity.ZomponyRenderer;
import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.block.SkullBlock; import net.minecraft.block.SkullBlock;
import net.minecraft.block.SkullBlock.SkullType;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.SkullBlockEntityModel;
import net.minecraft.client.render.block.entity.SkullBlockEntityRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.ProfileComponent; import net.minecraft.component.type.ProfileComponent;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -28,29 +37,44 @@ import org.jetbrains.annotations.Nullable;
* PonySkullRenderer! It renders ponies as skulls, or something... * PonySkullRenderer! It renders ponies as skulls, or something...
*/ */
public class PonySkullRenderer { public class PonySkullRenderer {
public static final PonySkullRenderer INSTANCE = new PonySkullRenderer();
private static final Map<SkullBlock.SkullType, ISkull> SKULLS = Maps.newHashMap(); private Map<SkullBlock.SkullType, ISkull> skulls = Map.of();
private Map<SkullBlock.SkullType, SkullBlockEntityModel> headModels = Map.of();
private static ISkull selectedSkull; private ISkull selectedSkull;
private static Identifier selectedSkin; private Identifier selectedSkin;
public static void reload() { boolean isBeingWorn;
SKULLS.clear(); boolean isPony;
loadSkulls(SKULLS);
public void reload() {
skulls = Util.make(new HashMap<>(), skullMap -> {
skullMap.put(SkullBlock.Type.SKELETON, new MobSkull(SkeleponyRenderer.SKELETON, MobRenderers.SKELETON, ModelType.SKELETON));
skullMap.put(SkullBlock.Type.WITHER_SKELETON, new MobSkull(SkeleponyRenderer.WITHER, MobRenderers.SKELETON, ModelType.SKELETON));
skullMap.put(SkullBlock.Type.ZOMBIE, new MobSkull(ZomponyRenderer.ZOMBIE, MobRenderers.ZOMBIE, ModelType.ZOMBIE));
skullMap.put(SkullBlock.Type.PIGLIN, new MobSkull(PonyPiglinRenderer.PIGLIN, MobRenderers.PIGLIN, ModelType.PIGLIN));
skullMap.put(SkullBlock.Type.PLAYER, new PlayerPonySkull());
});
headModels = SkullBlockEntityRenderer.getModels(MinecraftClient.getInstance().getEntityModelLoader());
} }
private static void loadSkulls(Map<SkullBlock.SkullType, ISkull> skullMap) { public void renderSkull(MatrixStack matrices, VertexConsumerProvider provider, ItemStack stack, LivingEntity entity, float tickDelta, int light, boolean isPony) {
skullMap.put(SkullBlock.Type.SKELETON, new MobSkull(SkeleponyRenderer.SKELETON, MobRenderers.SKELETON, ModelType.SKELETON)); isBeingWorn = true;
skullMap.put(SkullBlock.Type.WITHER_SKELETON, new MobSkull(SkeleponyRenderer.WITHER, MobRenderers.SKELETON, ModelType.SKELETON)); this.isPony = isPony;
skullMap.put(SkullBlock.Type.ZOMBIE, new MobSkull(ZomponyRenderer.ZOMBIE, MobRenderers.ZOMBIE, ModelType.ZOMBIE)); SkullType type = ((AbstractSkullBlock) ((BlockItem) stack.getItem()).getBlock()).getSkullType();
skullMap.put(SkullBlock.Type.PLAYER, new PlayerPonySkull()); SkullBlockEntityModel skullBlockEntityModel = headModels.get(type);
RenderLayer renderLayer = SkullBlockEntityRenderer.getRenderLayer(type, stack.get(DataComponentTypes.PROFILE));
SkullBlockEntityRenderer.renderSkull(null, 180, (entity.getVehicle() instanceof LivingEntity l ? l : entity).limbAnimator.getPos(tickDelta), matrices, provider, light, skullBlockEntityModel, renderLayer);
isBeingWorn = false;
this.isPony = false;
} }
public static RenderLayer getSkullRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile) { public RenderLayer getSkullRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile) {
selectedSkull = null; selectedSkull = null;
selectedSkin = null; selectedSkin = null;
ISkull skull = SKULLS.get(skullType); ISkull skull = skulls.get(skullType);
if (skull == null || !skull.canRender(PonyConfig.getInstance())) { if (skull == null || !skull.canRender(PonyConfig.getInstance())) {
return null; return null;
@ -61,16 +85,12 @@ public class PonySkullRenderer {
return RenderLayer.getEntityTranslucent(selectedSkin); return RenderLayer.getEntityTranslucent(selectedSkin);
} }
public static boolean renderSkull(@Nullable Direction direction, public boolean renderSkull(@Nullable Direction direction,
float yaw, float animationProgress, float yaw, float animationProgress,
MatrixStack stack, VertexConsumerProvider renderContext, RenderLayer layer, MatrixStack stack, VertexConsumerProvider renderContext, RenderLayer layer,
int lightUv) { int lightUv) {
if (selectedSkull == null || !selectedSkull.canRender(PonyConfig.getInstance())) { if (selectedSkull == null || !selectedSkull.canRender(PonyConfig.getInstance()) || !selectedSkull.bindPony(Pony.getManager().getPony(selectedSkin))) {
return false;
}
if (!selectedSkull.bindPony(Pony.getManager().getPony(selectedSkin))) {
return false; return false;
} }
@ -79,7 +99,6 @@ public class PonySkullRenderer {
if (direction == null) { if (direction == null) {
stack.translate(0.5, 0, 0.5); stack.translate(0.5, 0, 0.5);
} else { } else {
final float offset = 0.25F; final float offset = 0.25F;
stack.translate( stack.translate(
0.5F - direction.getOffsetX() * offset, 0.5F - direction.getOffsetX() * offset,
@ -105,7 +124,6 @@ public class PonySkullRenderer {
* Implement this interface if you want to extend our behaviour, modders. * Implement this interface if you want to extend our behaviour, modders.
*/ */
public interface ISkull { public interface ISkull {
void setAngles(float angle, float poweredTicks); void setAngles(float angle, float poweredTicks);
void render(MatrixStack stack, VertexConsumer vertices, int lightUv, int overlayUv, float red, float green, float blue, float alpha); void render(MatrixStack stack, VertexConsumer vertices, int lightUv, int overlayUv, float red, float green, float blue, float alpha);
@ -116,4 +134,8 @@ public class PonySkullRenderer {
boolean bindPony(Pony pony); boolean bindPony(Pony pony);
} }
public interface SkullRenderer {
Map<SkullBlock.SkullType, SkullBlockEntityModel> getModels();
}
} }

View file

@ -10,9 +10,9 @@ import com.minelittlepony.client.model.entity.PiglinPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyModel> { public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyModel> {
private static final Identifier PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/piglin_pony.png"); public static final Identifier PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/piglin_pony.png");
private static final Identifier PIGLIN_BRUTE = new Identifier("minelittlepony", "textures/entity/piglin/piglin_brute_pony.png"); public static final Identifier PIGLIN_BRUTE = new Identifier("minelittlepony", "textures/entity/piglin/piglin_brute_pony.png");
private static final Identifier ZOMBIFIED_PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/zombified_piglin_pony.png"); public static final Identifier ZOMBIFIED_PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/zombified_piglin_pony.png");
public PonyPiglinRenderer(EntityRendererFactory.Context context, Identifier texture, float scale) { public PonyPiglinRenderer(EntityRendererFactory.Context context, Identifier texture, float scale) {
super(context, ModelType.PIGLIN, TextureSupplier.of(texture), scale); super(context, ModelType.PIGLIN, TextureSupplier.of(texture), scale);

View file

@ -2,43 +2,33 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.armour.ArmourLayer; import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.armour.ArmourRendererPlugin; import com.minelittlepony.client.model.armour.ArmourRendererPlugin;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import java.util.Map;
import net.minecraft.block.AbstractSkullBlock; import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.block.SkullBlock;
import net.minecraft.block.SkullBlock.SkullType;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.block.entity.SkullBlockEntityModel; import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import net.minecraft.client.render.block.entity.SkullBlockEntityRenderer;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.EntityModelLoader; import net.minecraft.client.render.entity.model.EntityModelLoader;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.ZombieVillagerEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ArmorItem; import net.minecraft.item.ArmorItem;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.village.VillagerDataContainer;
public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
private final ItemRenderer itemRenderer; private final ItemRenderer itemRenderer;
private final Map<SkullBlock.SkullType, SkullBlockEntityModel> headModels;
public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) { public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) {
super(renderPony); super(renderPony);
headModels = SkullBlockEntityRenderer.getModels(entityModelLoader);
this.itemRenderer = itemRenderer; this.itemRenderer = itemRenderer;
} }
@ -56,21 +46,30 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
matrices.push(); matrices.push();
if (entity.isBaby() && !(entity instanceof VillagerEntity)) {
matrices.translate(0, 0.03125F, 0);
matrices.scale(0.7F, 0.7F, 0.7F);
matrices.translate(0, 1, 0);
}
model.transform(BodyPart.HEAD, matrices); model.transform(BodyPart.HEAD, matrices);
model.getHead().rotate(matrices); model.getHead().rotate(matrices);
if (model instanceof AbstractPonyModel) { boolean isVillager = entity instanceof VillagerEntity || entity instanceof ZombieVillagerEntity;
matrices.translate(0, 0.225F, 0);
} else { float f = 1.1F;
matrices.translate(0, 0, 0.15F); matrices.scale(f, f, f);
}
if (item instanceof BlockItem b && b.getBlock() instanceof AbstractSkullBlock) { if (item instanceof BlockItem b && b.getBlock() instanceof AbstractSkullBlock) {
boolean isVillager = entity instanceof VillagerDataContainer; float n = 1.1875F;
matrices.scale(n, -n, -n);
renderSkull(matrices, provider, stack, isVillager, limbDistance, light); matrices.translate(0, -0.1F, 0.1F);
matrices.translate(-0.5, 0, -0.5);
PonySkullRenderer.INSTANCE.renderSkull(matrices, provider, stack, entity, tickDelta, light, true);
} else if (!(item instanceof ArmorItem a) || a.getSlotType() != EquipmentSlot.HEAD) { } else if (!(item instanceof ArmorItem a) || a.getSlotType() != EquipmentSlot.HEAD) {
renderBlock(matrices, provider, entity, stack, light); matrices.translate(0, 0.1F, -0.1F);
HeadFeatureRenderer.translate(matrices, isVillager);
itemRenderer.renderItem(entity, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal());
} }
matrices.pop(); matrices.pop();
@ -78,28 +77,4 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL); plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL);
} }
private void renderBlock(MatrixStack matrices, VertexConsumerProvider provider, T entity, ItemStack stack, int light) {
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180));
matrices.scale(0.625F, -0.625F, -0.625F);
matrices.translate(0, 0.6F, -0.21F);
itemRenderer.renderItem(entity, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal());
}
private void renderSkull(MatrixStack matrices, VertexConsumerProvider provider, ItemStack stack, boolean isVillager, float limbDistance, int light) {
matrices.translate(0, 0, -0.14F);
float f = 1.1875f;
matrices.scale(f, -f, -f);
if (isVillager) {
matrices.translate(0, 0.0625F, 0);
}
matrices.translate(-0.5, 0, -0.5);
SkullType type = ((AbstractSkullBlock) ((BlockItem) stack.getItem()).getBlock()).getSkullType();
SkullBlockEntityModel skullBlockEntityModel = (SkullBlockEntityModel)this.headModels.get(type);
RenderLayer renderLayer = SkullBlockEntityRenderer.getRenderLayer(type, stack.get(DataComponentTypes.PROFILE));
SkullBlockEntityRenderer.renderSkull(null, 180, f, matrices, provider, light, skullBlockEntityModel, renderLayer);
}
} }