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
public void reload(ResourceManager var1) {
public void reload(ResourceManager manager) {
clearCache();
PonySkullRenderer.reload();
PonySkullRenderer.INSTANCE.reload();
}
@Override

View file

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

View file

@ -1,26 +1,35 @@
package com.minelittlepony.client.render.blockentity.skull;
import com.google.common.collect.Maps;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.armour.ArmourRendererPlugin;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.entity.SkeleponyRenderer;
import com.minelittlepony.client.render.entity.ZomponyRenderer;
import com.minelittlepony.client.render.entity.*;
import net.minecraft.block.AbstractSkullBlock;
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.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
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.component.DataComponentTypes;
import net.minecraft.component.type.ProfileComponent;
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.Util;
import net.minecraft.util.math.Direction;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
@ -28,29 +37,44 @@ import org.jetbrains.annotations.Nullable;
* PonySkullRenderer! It renders ponies as skulls, or something...
*/
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 static Identifier selectedSkin;
private ISkull selectedSkull;
private Identifier selectedSkin;
public static void reload() {
SKULLS.clear();
loadSkulls(SKULLS);
}
boolean isBeingWorn;
boolean isPony;
private static void loadSkulls(Map<SkullBlock.SkullType, ISkull> skullMap) {
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());
}
public static RenderLayer getSkullRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile) {
public void renderSkull(MatrixStack matrices, VertexConsumerProvider provider, ItemStack stack, LivingEntity entity, float tickDelta, int light, boolean isPony) {
isBeingWorn = true;
this.isPony = isPony;
SkullType type = ((AbstractSkullBlock) ((BlockItem) stack.getItem()).getBlock()).getSkullType();
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 RenderLayer getSkullRenderLayer(SkullBlock.SkullType skullType, @Nullable ProfileComponent profile) {
selectedSkull = null;
selectedSkin = null;
ISkull skull = SKULLS.get(skullType);
ISkull skull = skulls.get(skullType);
if (skull == null || !skull.canRender(PonyConfig.getInstance())) {
return null;
@ -61,16 +85,12 @@ public class PonySkullRenderer {
return RenderLayer.getEntityTranslucent(selectedSkin);
}
public static boolean renderSkull(@Nullable Direction direction,
public boolean renderSkull(@Nullable Direction direction,
float yaw, float animationProgress,
MatrixStack stack, VertexConsumerProvider renderContext, RenderLayer layer,
int lightUv) {
if (selectedSkull == null || !selectedSkull.canRender(PonyConfig.getInstance())) {
return false;
}
if (!selectedSkull.bindPony(Pony.getManager().getPony(selectedSkin))) {
if (selectedSkull == null || !selectedSkull.canRender(PonyConfig.getInstance()) || !selectedSkull.bindPony(Pony.getManager().getPony(selectedSkin))) {
return false;
}
@ -79,7 +99,6 @@ public class PonySkullRenderer {
if (direction == null) {
stack.translate(0.5, 0, 0.5);
} else {
final float offset = 0.25F;
stack.translate(
0.5F - direction.getOffsetX() * offset,
@ -105,7 +124,6 @@ public class PonySkullRenderer {
* Implement this interface if you want to extend our behaviour, modders.
*/
public interface ISkull {
void setAngles(float angle, float poweredTicks);
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);
}
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;
public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyModel> {
private 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");
private static final Identifier ZOMBIFIED_PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/zombified_piglin_pony.png");
public static final Identifier PIGLIN = new Identifier("minelittlepony", "textures/entity/piglin/piglin_pony.png");
public static final Identifier PIGLIN_BRUTE = new Identifier("minelittlepony", "textures/entity/piglin/piglin_brute_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) {
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.PonyModel;
import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.armour.ArmourRendererPlugin;
import com.minelittlepony.client.render.PonyRenderContext;
import java.util.Map;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
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.block.entity.SkullBlockEntityModel;
import net.minecraft.client.render.block.entity.SkullBlockEntityRenderer;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.EntityModelLoader;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
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.LivingEntity;
import net.minecraft.entity.mob.ZombieVillagerEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
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> {
private final ItemRenderer itemRenderer;
private final Map<SkullBlock.SkullType, SkullBlockEntityModel> headModels;
public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) {
super(renderPony);
headModels = SkullBlockEntityRenderer.getModels(entityModelLoader);
this.itemRenderer = itemRenderer;
}
@ -56,21 +46,30 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
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.getHead().rotate(matrices);
if (model instanceof AbstractPonyModel) {
matrices.translate(0, 0.225F, 0);
} else {
matrices.translate(0, 0, 0.15F);
}
boolean isVillager = entity instanceof VillagerEntity || entity instanceof ZombieVillagerEntity;
float f = 1.1F;
matrices.scale(f, f, f);
if (item instanceof BlockItem b && b.getBlock() instanceof AbstractSkullBlock) {
boolean isVillager = entity instanceof VillagerDataContainer;
renderSkull(matrices, provider, stack, isVillager, limbDistance, light);
float n = 1.1875F;
matrices.scale(n, -n, -n);
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) {
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();
@ -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);
}
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);
}
}