Clean up the EquineRendermanager (should fix some crashing issues with null seapony models)

This commit is contained in:
Sollace 2023-10-05 19:46:40 +01:00
parent f54cd5682d
commit 76a2e043b7
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
14 changed files with 189 additions and 202 deletions

View file

@ -18,14 +18,14 @@ import java.util.function.Consumer;
/**
* Container class for the various models and their associated piece of armour.
*/
public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> {
public class Models<T extends LivingEntity, M extends PonyModel<?>> {
@Nullable
private final MsonModel.Factory<PonyArmourModel<T>> armorFactory;
private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>();
private final M body;
public ModelWrapper(PlayerModelKey<T, ? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) {
public Models(PlayerModelKey<T, ? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) {
this.armorFactory = playerModelKey.armorFactory();
this.body = playerModelKey.getKey(slimArms).createModel();
if (initializer != null) {
@ -33,7 +33,7 @@ public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> {
}
}
public ModelWrapper(ModelKey<M> key) {
public Models(ModelKey<M> key) {
this.armorFactory = null;
this.body = key.createModel();
}
@ -49,7 +49,7 @@ public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> {
}));
}
public ModelWrapper<T, M> applyMetadata(PonyData meta) {
public Models<T, M> applyMetadata(PonyData meta) {
body.setMetadata(meta);
armor.values().forEach(a -> a.setMetadata(meta));
return this;

View file

@ -7,7 +7,7 @@ import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.*;
@ -31,12 +31,12 @@ public record PlayerModelKey<T extends LivingEntity, M extends Model & PonyModel
return slimArms ? alexKey : steveKey;
}
public <E extends T, N extends M> ModelWrapper<E, N> create(boolean slimArms) {
public <E extends T, N extends M> Models<E, N> create(boolean slimArms) {
return create(slimArms, null);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public <E extends T, N extends M> ModelWrapper<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new ModelWrapper(this, slimArms, initializer);
public <E extends T, N extends M> Models<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new Models(this, slimArms, initializer);
}
}

View file

@ -12,6 +12,7 @@ import com.minelittlepony.util.MathUtil;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.Objects;
import java.util.function.Function;
import net.fabricmc.api.EnvType;
import net.minecraft.client.MinecraftClient;
@ -26,40 +27,38 @@ import org.jetbrains.annotations.Nullable;
public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
private ModelWrapper<T, M> playerModel;
private Models<T, M> models;
@Nullable
private Function<T, Models<T, M>> modelsLookup;
private final PonyRenderContext<T, M> renderer;
private final PonyRenderContext<T, M> context;
private final Transformer<T> transformer;
private final FrustrumCheck<T> frustrum = new FrustrumCheck<>(this);
private final FrustrumCheck<T> frustrum;
public static void disableModelRenderProfile() {
RenderSystem.disableBlend();
}
public EquineRenderManager(PonyRenderContext<T, M> renderer) {
this.renderer = renderer;
}
public PonyRenderContext<T, M> getContext() {
return renderer;
}
public ModelWrapper<T, M> getModelWrapper() {
return playerModel;
}
public M getModel() {
return playerModel.body();
public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, Models<T, M> models) {
this.context = context;
this.transformer = transformer;
this.models = models;
frustrum = new FrustrumCheck<>(context);
context.setModel(models.body());
}
@SuppressWarnings({"rawtypes", "unchecked"})
public ModelWrapper<T, M> setModel(ModelKey<? super M> key) {
return setModel(new ModelWrapper(key));
public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, ModelKey<? super M> key) {
this(context, transformer, new Models(key));
}
public ModelWrapper<T, M> setModel(ModelWrapper<T, M> wrapper) {
playerModel = wrapper;
return wrapper;
public void setModelsLookup(@Nullable Function<T, Models<T, M>> modelsLookup) {
this.modelsLookup = modelsLookup;
}
public Models<T, M> getModels() {
return models;
}
public Frustum getFrustrum(T entity, Frustum vanilla) {
@ -73,7 +72,61 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return frustrum.withCamera(entity, vanilla);
}
public float getRenderYaw(T entity, float rotationYaw, float partialTicks) {
public void preRender(T entity, ModelAttributes.Mode mode) {
Pony pony = context.getEntityPony(entity);
if (modelsLookup != null) {
models = modelsLookup.apply(entity);
context.setModel(models.body());
}
models.applyMetadata(pony.metadata());
models.body().updateLivingState(entity, pony, mode);
if (entity instanceof PlayerEntity player && entity instanceof RegistrationHandler handler) {
handler.getSyncedPony().synchronize(player, pony);
}
}
public void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float tickDelta) {
float s = getScaleFactor();
stack.scale(s, s, s);
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity livingVehicles) {
PonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(livingVehicles);
if (renderer != null) {
// negate vanilla translations so the rider begins at the ridees feet.
stack.translate(0, -livingVehicles.getHeight(), 0);
Pony pony = context.getEntityPony(entity);
if (!pony.race().isHuman()) {
renderer.getInternalRenderer().translateRider(livingVehicles, renderer.getEntityPony(livingVehicles), entity, pony, stack, tickDelta);
}
}
}
if (entity instanceof PlayerEntity) {
if (getModels().body().getAttributes().isSitting) {
stack.translate(0, 0.125D, 0);
}
}
rotationYaw = getMountedYaw(entity, rotationYaw, tickDelta);
transformer.setupTransforms(entity, stack, ageInTicks, rotationYaw, tickDelta);
PonyPosture.of(getModels().body().getAttributes()).apply(entity, getModels().body(), stack, rotationYaw, tickDelta, 1);
}
private void translateRider(T entity, Pony pony, LivingEntity passenger, Pony passengerPony, MatrixStack stack, float tickDelta) {
if (!passengerPony.race().isHuman()) {
float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), tickDelta);
models.applyMetadata(pony.metadata());
models.body().transform(BodyPart.BACK, stack);
PonyPosture.of(models.body().getAttributes()).apply(entity, getModels().body(), stack, yaw, tickDelta, -1);
}
}
private float getMountedYaw(T entity, float rotationYaw, float partialTicks) {
if (entity.hasVehicle()) {
Entity mount = entity.getVehicle();
if (mount instanceof LivingEntity) {
@ -84,91 +137,20 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return rotationYaw;
}
public void preRenderCallback(T entity, MatrixStack stack, float ticks) {
updateModel(entity, ModelAttributes.Mode.THIRD_PERSON);
float s = getScaleFactor();
stack.scale(s, s, s);
translateRider(entity, stack, ticks);
}
private void translateRider(T entity, MatrixStack stack, float ticks) {
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity) {
LivingEntity ridingEntity = (LivingEntity) entity.getVehicle();
PonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(ridingEntity);
if (renderer != null) {
// negate vanilla translations so the rider begins at the ridees feet.
stack.translate(0, -ridingEntity.getHeight(), 0);
Pony riderPony = renderer.getEntityPony(ridingEntity);
renderer.translateRider(ridingEntity, riderPony, entity, renderer.getEntityPony(entity), stack, ticks);
}
}
}
public void setupTransforms(T entity, MatrixStack stack, float yaw, float tickDelta) {
PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, 1);
}
public void applyPostureRiding(T entity, MatrixStack stack, float yaw, float tickDelta) {
PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, -1);
}
public Pony updateModel(T entity, ModelAttributes.Mode mode) {
Pony pony = renderer.getEntityPony(entity);
playerModel.applyMetadata(pony.metadata());
if (entity instanceof PlayerEntity player && entity instanceof RegistrationHandler handler) {
SyncedPony synced = handler.getSyncedPony();
boolean changed = pony.compareTo(synced.lastRenderedPony) != 0;
if (changed) {
synced.lastRenderedPony = pony;
player.calculateDimensions();
}
if (!(player instanceof PreviewModel)) {
@Nullable
PlayerEntity clientPlayer = MinecraftClient.getInstance().player;
if (pony.compareTo(synced.lastTransmittedPony) != 0) {
if (clientPlayer != null && (Objects.equals(player, clientPlayer) || Objects.equals(player.getGameProfile(), clientPlayer.getGameProfile()))) {
if (Channel.broadcastPonyData(pony.metadata())) {
synced.lastTransmittedPony = pony;
}
}
}
if (changed) {
PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, pony.metadata(), EnvType.CLIENT);
}
}
}
getModel().updateLivingState(entity, pony, mode);
return pony;
}
public float getScaleFactor() {
return getModel().getSize().scaleFactor();
return getModels().body().getSize().scaleFactor();
}
public float getShadowSize() {
return getModel().getSize().shadowSize();
return getModels().body().getSize().shadowSize();
}
public double getNamePlateYOffset(T entity) {
// We start by negating the height calculation done by mahjong.
float y = -(entity.getHeight() + 0.5F);
// Then we add our own offsets.
y += getModel().getAttributes().visualHeight * getScaleFactor() + 0.25F;
y += getModels().body().getAttributes().visualHeight * getScaleFactor() + 0.25F;
if (entity.isSneaking()) {
y -= 0.25F;
@ -185,14 +167,48 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return y;
}
public interface Transformer<T extends LivingEntity> {
void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks);
}
public interface RegistrationHandler {
SyncedPony getSyncedPony();
}
public interface ModelHolder<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
void setModel(M model);
}
public static class SyncedPony {
@Nullable
private Pony lastRenderedPony;
@Nullable
private Pony lastTransmittedPony;
public void synchronize(PlayerEntity player, Pony pony) {
boolean changed = pony.compareTo(lastRenderedPony) != 0;
if (changed) {
lastRenderedPony = pony;
player.calculateDimensions();
}
if (!(player instanceof PreviewModel)) {
@Nullable
PlayerEntity clientPlayer = MinecraftClient.getInstance().player;
if (pony.compareTo(lastTransmittedPony) != 0) {
if (clientPlayer != null && (Objects.equals(player, clientPlayer) || Objects.equals(player.getGameProfile(), clientPlayer.getGameProfile()))) {
if (Channel.broadcastPonyData(pony.metadata())) {
lastTransmittedPony = pony;
}
}
}
if (changed) {
PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, pony.metadata(), EnvType.CLIENT);
}
}
}
}
}

View file

@ -19,11 +19,11 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
private Frustum vanilla;
private final EquineRenderManager<T, ?> renderer;
private final PonyRenderContext<T, ?> context;
public FrustrumCheck(EquineRenderManager<T, ?> render) {
public FrustrumCheck(PonyRenderContext<T, ?> context) {
super(new Matrix4f(), new Matrix4f());
renderer = render;
this.context = context;
}
public Frustum withCamera(T entity, Frustum vanillaFrustrum) {
@ -34,7 +34,7 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
@Override
public boolean isVisible(Box bounds) {
return vanilla.isVisible(PonyBounds.getBoundingBox(renderer.getContext().getEntityPony(entity), entity));
return vanilla.isVisible(PonyBounds.getBoundingBox(context.getEntityPony(entity), entity));
}
@Override

View file

@ -1,13 +1,10 @@
package com.minelittlepony.client.render;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.util.MathUtil;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
public interface PonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
@ -16,19 +13,5 @@ public interface PonyRenderContext<T extends LivingEntity, M extends EntityModel
EquineRenderManager<T, M> getInternalRenderer();
/**
* Called by riders to have their transportation adjust their position.
*/
default void translateRider(T entity, Pony entityPony, LivingEntity passenger, Pony passengerPony, MatrixStack stack, float ticks) {
if (!passengerPony.race().isHuman()) {
float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), ticks);
getInternalRenderer().getModelWrapper().applyMetadata(entityPony.metadata());
M model = getInternalRenderer().getModelWrapper().body();
model.transform(BodyPart.BACK, stack);
getInternalRenderer().applyPostureRiding(entity, stack, yaw, ticks);
}
}
void setModel(M model);
}

View file

@ -1,5 +1,6 @@
package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable;
@ -29,7 +30,7 @@ import net.minecraft.util.Identifier;
public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements PonyRenderContext<T, M> {
protected final EquineRenderManager<T, M> manager = new EquineRenderManager<>(this);
protected final EquineRenderManager<T, M> manager;
private final Map<Wearable, Identifier> wearableTextures = new EnumMap<>(Wearable.class);
@ -39,7 +40,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) {
super(context, null, 0.5F);
this.model = manager.setModel(key).body();
this.manager = new EquineRenderManager<>(this, super::setupTransforms, key);
this.texture = texture;
this.scale = scale;
addFeatures(context);
@ -64,24 +65,14 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
}
@Override
protected void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
manager.preRenderCallback(entity, stack, partialTicks);
if (getModel() instanceof PlayerEntityModel) {
((PlayerEntityModel<?>)getModel()).setVisible(true);
}
if (getModel().getAttributes().isSitting) {
stack.translate(0, 0.125D, 0);
}
rotationYaw = manager.getRenderYaw(entity, rotationYaw, partialTicks);
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
}
@Override
@ -117,8 +108,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override
public Identifier getDefaultTexture(T entity, Wearable wearable) {
return wearableTextures.computeIfAbsent(wearable, w -> {
Identifier texture = getTexture(entity);
texture = new Identifier(texture.getNamespace(), texture.getPath().split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
Identifier texture = getTexture(entity).withPath(path -> path.split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
if (MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent()) {
return texture;
@ -127,6 +117,11 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
});
}
@Override
public void setModel(M model) {
this.model = model;
}
@Override
public EquineRenderManager<T, M> getInternalRenderer() {
return manager;

View file

@ -30,8 +30,8 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
@Override
public void render(AbstractClientPlayerEntity player, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int light) {
updateSeaponyState(player);
super.render(player, entityYaw, tickDelta, stack, renderContext, light);
updateSeaponyState(player);
if (!(player instanceof PreviewModel) && wet && player.getVelocity().length() > 0.1F) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);
@ -44,32 +44,30 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
Race race = super.getPlayerRace(entity, pony);
return wet ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
return PonyPosture.isSeaponyModifier(entity) ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
}
@Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
if (wet) {
protected void setupTransforms(AbstractClientPlayerEntity player, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
if (PonyPosture.isSeaponyModifier(player)) {
stack.translate(0, 0.6, 0);
if (entity.isInSneakingPose()) {
if (player.isInSneakingPose()) {
stack.translate(0, 0.125, 0);
}
}
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
super.setupTransforms(player, stack, ageInTicks, rotationYaw, partialTicks);
}
@Override
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
updateSeaponyState(player);
super.renderArm(stack, renderContext, lightUv, player, side);
updateSeaponyState(player);
}
private void updateSeaponyState(AbstractClientPlayerEntity player) {
wet = PonyPosture.isSeaponyModifier(player);
if (!(player instanceof PreviewModel)) {
float state = wet ? 100 : 0;
float interpolated = getInternalRenderer().getModel().getAttributes().getMainInterpolator().interpolate("seapony_state", state, 5);
float state = PonyPosture.isSeaponyModifier(player) ? 100 : 0;
float interpolated = getInternalRenderer().getModels().body().getAttributes().getMainInterpolator().interpolate("seapony_state", state, 5);
if (!MathUtil.compareFloats(interpolated, state)) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.api.pony.meta.Race;
@ -30,21 +30,20 @@ import net.minecraft.util.*;
import net.minecraft.util.math.*;
public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> {
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager = new EquineRenderManager<>(this);
private final Function<Race, ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache;
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache;
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager;
public PlayerPonyRenderer(EntityRendererFactory.Context context, boolean slim) {
super(context, slim);
modelsCache = Util.memoize(race -> ModelType.getPlayerModel(race).create(slim));
manager = new EquineRenderManager<>(this, super::setupTransforms, modelsCache.apply(Race.EARTH));
manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity, getEntityPony(entity))));
addLayers(context);
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void addLayers(EntityRendererFactory.Context context) {
// remove vanilla features (keep modded ones)
// TODO: test with https://github.com/Globox1997/BackSlot
features.removeIf(feature -> {
return feature instanceof ArmorFeatureRenderer
|| feature instanceof PlayerHeldItemFeatureRenderer
@ -71,19 +70,18 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
@Override
protected void scale(AbstractClientPlayerEntity entity, MatrixStack stack, float tickDelta) {
if (manager.getModel().getAttributes().isSitting && entity.hasVehicle()) {
if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) {
stack.translate(0, entity.getRidingOffset(entity.getVehicle()), 0);
}
}
@Override
public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
Pony pony = getEntityPony(entity);
model = manager.setModel(modelsCache.apply(getPlayerRace(entity, pony))).body();
// EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering
manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
shadowRadius = manager.getShadowSize();
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(pony, this, entity, stack, renderContext, tickDelta);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
// Translate the shadow position after everything is done
// (shadows are drawn after us)
@ -103,10 +101,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
@Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
manager.preRenderCallback(entity, stack, partialTicks);
rotationYaw = manager.getRenderYaw(entity, rotationYaw, partialTicks);
super.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, rotationYaw, partialTicks);
manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
}
@Override
@ -145,9 +140,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
}
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
Pony pony = getEntityPony(player);
model = manager.setModel(modelsCache.apply(getPlayerRace(player, pony))).body();
manager.updateModel(player, ModelAttributes.Mode.FIRST_PERSON);
manager.preRender(player, ModelAttributes.Mode.FIRST_PERSON);
stack.push();
float reflect = side == Arm.LEFT ? 1 : -1;
@ -179,6 +172,11 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
return getEntityPony(player).texture();
}
@Override
public void setModel(ClientPonyModel<AbstractClientPlayerEntity> model) {
this.model = model;
}
@Override
public EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> getInternalRenderer() {
return manager;
@ -192,7 +190,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
@Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) {
return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> {
if (wearable.isSaddlebags() && getInternalRenderer().getModel().getRace().supportsLegacySaddlebags()) {
if (wearable.isSaddlebags() && getInternalRenderer().getModels().body().getRace().supportsLegacySaddlebags()) {
return getTexture(entity);
}

View file

@ -11,7 +11,7 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.ModelType;
@ -60,7 +60,7 @@ public class PonyStandRenderer extends ArmorStandEntityRenderer {
}
class Armour extends ArmorFeatureRenderer<ArmorStandEntity, ArmorStandArmorEntityModel, ArmorStandArmorEntityModel> {
private final ModelWrapper<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>> pony = ModelType.EARTH_PONY.<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>>create(false);
private final Models<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>> pony = ModelType.EARTH_PONY.<ArmorStandEntity, EarthPonyModel<ArmorStandEntity>>create(false);
public Armour(FeatureRendererContext<ArmorStandEntity, ArmorStandArmorEntityModel> renderer, EntityRendererFactory.Context context) {
super(renderer,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.client.render.entity;
import org.jetbrains.annotations.NotNull;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.mixin.IResizeable;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.GuardianPonyModel;
@ -52,7 +53,7 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
@Override
public void render(GuardianEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
ponyRenderer.manager.preRenderCallback(entity, stack, tickDelta);
ponyRenderer.manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
float height = entity.getStandingEyeHeight();
@ -61,4 +62,9 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
((IResizeable)entity).setStandingEyeHeight(height);
}
@Override
protected void setupTransforms(GuardianEntity entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
ponyRenderer.manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, partialTicks);
}
}

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.PonyRenderContext;
@ -45,10 +45,10 @@ public abstract class AbstractPonyFeature<T extends LivingEntity, M extends Enti
@Override
public final M getContextModel() {
return context.getInternalRenderer().getModel();
return context.getInternalRenderer().getModels().body();
}
protected ModelWrapper<T, M> getModelWrapper() {
return context.getInternalRenderer().getModelWrapper();
protected Models<T, M> getModelWrapper() {
return context.getInternalRenderer().getModels();
}
}

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.client.render.ArmorRenderLayers;
@ -29,7 +29,7 @@ public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & Po
@Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
ModelWrapper<T, M> pony = getModelWrapper();
Models<T, M> pony = getModelWrapper();
for (EquipmentSlot i : EquipmentSlot.values()) {
if (i.getType() == EquipmentSlot.Type.ARMOR) {
@ -40,7 +40,7 @@ public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & Po
}
public static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor(
ModelWrapper<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
VertexConsumerProvider renderContext, int light, T entity,
float limbDistance, float limbAngle,
float age, float headYaw, float headPitch,

View file

@ -44,7 +44,7 @@ public class HeldItemFeature<T extends LivingEntity, M extends EntityModel<T> &
ItemStack right = getRightItem(entity);
if (!left.isEmpty() || !right.isEmpty()) {
M model = context.getInternalRenderer().getModel();
M model = context.getInternalRenderer().getModels().body();
stack.push();

View file

@ -1,14 +1,13 @@
package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.VillagerProfession;
import com.minelittlepony.api.model.ModelWrapper;
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;
@ -17,15 +16,21 @@ import com.minelittlepony.client.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.*;
import java.util.*;
import java.util.function.Function;
abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer> extends PonyRenderer<T, ClientPonyModel<T>> {
private final Map<Race, ModelWrapper<T, ClientPonyModel<T>>> models = new EnumMap<>(Race.class);
private final NpcClothingFeature<T, ClientPonyModel<T>, AbstractNpcRenderer<T>> clothing;
private final Function<Race, Models<T, ClientPonyModel<T>>> models = Util.memoize(race -> {
if (race.isHuman()) {
race = Race.EARTH;
}
return ModelType.getPlayerModel(race).create(false, this::initializeModel);
});
public AbstractNpcRenderer(EntityRendererFactory.Context context, String type, TextureSupplier<T> textureSupplier, TextureSupplier<String> formatter) {
super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), SillyPonyTextureSupplier.create(textureSupplier, formatter));
clothing = new NpcClothingFeature<>(this, type);
this.manager.setModelsLookup(entity -> models.apply(getEntityPony(entity).race()));
addFeature(clothing);
}
@ -54,20 +59,6 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
return super.shouldRender(model, entity, wearable, gear);
}
@Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
model = manager.setModel(models.computeIfAbsent(getEntityPony(entity).race(), this::createModel)).body();
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
}
private ModelWrapper<T, ClientPonyModel<T>> createModel(Race race) {
if (race.isHuman()) {
race = Race.EARTH;
}
return ModelType.getPlayerModel(race).create(false, this::initializeModel);
}
protected void initializeModel(ClientPonyModel<T> model) {
}