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. * 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 @Nullable
private final MsonModel.Factory<PonyArmourModel<T>> armorFactory; private final MsonModel.Factory<PonyArmourModel<T>> armorFactory;
private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>(); private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>();
private final M body; 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.armorFactory = playerModelKey.armorFactory();
this.body = playerModelKey.getKey(slimArms).createModel(); this.body = playerModelKey.getKey(slimArms).createModel();
if (initializer != null) { 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.armorFactory = null;
this.body = key.createModel(); 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); body.setMetadata(meta);
armor.values().forEach(a -> a.setMetadata(meta)); armor.values().forEach(a -> a.setMetadata(meta));
return this; return this;

View file

@ -7,7 +7,7 @@ import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable; 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.api.model.PonyModel;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
@ -31,12 +31,12 @@ public record PlayerModelKey<T extends LivingEntity, M extends Model & PonyModel
return slimArms ? alexKey : steveKey; 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); return create(slimArms, null);
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public <E extends T, N extends M> ModelWrapper<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) { public <E extends T, N extends M> Models<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new ModelWrapper(this, slimArms, 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 com.mojang.blaze3d.systems.RenderSystem;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.minecraft.client.MinecraftClient; 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>> { 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() { public static void disableModelRenderProfile() {
RenderSystem.disableBlend(); RenderSystem.disableBlend();
} }
public EquineRenderManager(PonyRenderContext<T, M> renderer) { public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, Models<T, M> models) {
this.renderer = renderer; this.context = context;
} this.transformer = transformer;
this.models = models;
public PonyRenderContext<T, M> getContext() { frustrum = new FrustrumCheck<>(context);
return renderer; context.setModel(models.body());
}
public ModelWrapper<T, M> getModelWrapper() {
return playerModel;
}
public M getModel() {
return playerModel.body();
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public ModelWrapper<T, M> setModel(ModelKey<? super M> key) { public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, ModelKey<? super M> key) {
return setModel(new ModelWrapper(key)); this(context, transformer, new Models(key));
} }
public ModelWrapper<T, M> setModel(ModelWrapper<T, M> wrapper) { public void setModelsLookup(@Nullable Function<T, Models<T, M>> modelsLookup) {
playerModel = wrapper; this.modelsLookup = modelsLookup;
return wrapper; }
public Models<T, M> getModels() {
return models;
} }
public Frustum getFrustrum(T entity, Frustum vanilla) { 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); 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()) { if (entity.hasVehicle()) {
Entity mount = entity.getVehicle(); Entity mount = entity.getVehicle();
if (mount instanceof LivingEntity) { if (mount instanceof LivingEntity) {
@ -84,91 +137,20 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return rotationYaw; 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() { public float getScaleFactor() {
return getModel().getSize().scaleFactor(); return getModels().body().getSize().scaleFactor();
} }
public float getShadowSize() { public float getShadowSize() {
return getModel().getSize().shadowSize(); return getModels().body().getSize().shadowSize();
} }
public double getNamePlateYOffset(T entity) { public double getNamePlateYOffset(T entity) {
// We start by negating the height calculation done by mahjong. // We start by negating the height calculation done by mahjong.
float y = -(entity.getHeight() + 0.5F); float y = -(entity.getHeight() + 0.5F);
// Then we add our own offsets. // Then we add our own offsets.
y += getModel().getAttributes().visualHeight * getScaleFactor() + 0.25F; y += getModels().body().getAttributes().visualHeight * getScaleFactor() + 0.25F;
if (entity.isSneaking()) { if (entity.isSneaking()) {
y -= 0.25F; y -= 0.25F;
@ -185,14 +167,48 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return y; return y;
} }
public interface Transformer<T extends LivingEntity> {
void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks);
}
public interface RegistrationHandler { public interface RegistrationHandler {
SyncedPony getSyncedPony(); SyncedPony getSyncedPony();
} }
public interface ModelHolder<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
void setModel(M model);
}
public static class SyncedPony { public static class SyncedPony {
@Nullable @Nullable
private Pony lastRenderedPony; private Pony lastRenderedPony;
@Nullable @Nullable
private Pony lastTransmittedPony; 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 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()); super(new Matrix4f(), new Matrix4f());
renderer = render; this.context = context;
} }
public Frustum withCamera(T entity, Frustum vanillaFrustrum) { public Frustum withCamera(T entity, Frustum vanillaFrustrum) {
@ -34,7 +34,7 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
@Override @Override
public boolean isVisible(Box bounds) { 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 @Override

View file

@ -1,13 +1,10 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.Gear; import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.util.MathUtil;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public interface PonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> { 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(); EquineRenderManager<T, M> getInternalRenderer();
/** void setModel(M model);
* 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);
}
}
} }

View file

@ -1,5 +1,6 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable; 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> { 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); 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) { public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) {
super(context, null, 0.5F); super(context, null, 0.5F);
this.model = manager.setModel(key).body(); this.manager = new EquineRenderManager<>(this, super::setupTransforms, key);
this.texture = texture; this.texture = texture;
this.scale = scale; this.scale = scale;
addFeatures(context); addFeatures(context);
@ -64,24 +65,14 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override @Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { 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); super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta); DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
} }
@Override @Override
protected void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) { protected void setupTransforms(T entity, MatrixStack stack, float ageInTicks, float rotationYaw, float partialTicks) {
manager.preRenderCallback(entity, stack, partialTicks); manager.setupTransforms(entity, stack, ageInTicks, rotationYaw, 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);
} }
@Override @Override
@ -117,8 +108,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override @Override
public Identifier getDefaultTexture(T entity, Wearable wearable) { public Identifier getDefaultTexture(T entity, Wearable wearable) {
return wearableTextures.computeIfAbsent(wearable, w -> { return wearableTextures.computeIfAbsent(wearable, w -> {
Identifier texture = getTexture(entity); Identifier texture = getTexture(entity).withPath(path -> path.split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
texture = new Identifier(texture.getNamespace(), texture.getPath().split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png");
if (MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent()) { if (MinecraftClient.getInstance().getResourceManager().getResource(texture).isPresent()) {
return texture; 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 @Override
public EquineRenderManager<T, M> getInternalRenderer() { public EquineRenderManager<T, M> getInternalRenderer() {
return manager; return manager;

View file

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

View file

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

View file

@ -11,7 +11,7 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.util.math.Vec3d; 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.PonyData;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
@ -60,7 +60,7 @@ public class PonyStandRenderer extends ArmorStandEntityRenderer {
} }
class Armour extends ArmorFeatureRenderer<ArmorStandEntity, ArmorStandArmorEntityModel, ArmorStandArmorEntityModel> { 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) { public Armour(FeatureRendererContext<ArmorStandEntity, ArmorStandArmorEntityModel> renderer, EntityRendererFactory.Context context) {
super(renderer, super(renderer,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.client.render.entity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.mixin.IResizeable; import com.minelittlepony.client.mixin.IResizeable;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.GuardianPonyModel; import com.minelittlepony.client.model.entity.GuardianPonyModel;
@ -52,7 +53,7 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
@Override @Override
public void render(GuardianEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { 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(); float height = entity.getStandingEyeHeight();
@ -61,4 +62,9 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
((IResizeable)entity).setStandingEyeHeight(height); ((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; 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.api.model.PonyModel;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
@ -45,10 +45,10 @@ public abstract class AbstractPonyFeature<T extends LivingEntity, M extends Enti
@Override @Override
public final M getContextModel() { public final M getContextModel() {
return context.getInternalRenderer().getModel(); return context.getInternalRenderer().getModels().body();
} }
protected ModelWrapper<T, M> getModelWrapper() { protected Models<T, M> getModelWrapper() {
return context.getInternalRenderer().getModelWrapper(); return context.getInternalRenderer().getModels();
} }
} }

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.render.entity.feature; 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.api.model.PonyModel;
import com.minelittlepony.client.model.armour.*; import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.client.render.ArmorRenderLayers; import com.minelittlepony.client.render.ArmorRenderLayers;
@ -29,7 +29,7 @@ public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & Po
@Override @Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { 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()) { for (EquipmentSlot i : EquipmentSlot.values()) {
if (i.getType() == EquipmentSlot.Type.ARMOR) { 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( 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, VertexConsumerProvider renderContext, int light, T entity,
float limbDistance, float limbAngle, float limbDistance, float limbAngle,
float age, float headYaw, float headPitch, 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); ItemStack right = getRightItem(entity);
if (!left.isEmpty() || !right.isEmpty()) { if (!left.isEmpty() || !right.isEmpty()) {
M model = context.getInternalRenderer().getModel(); M model = context.getInternalRenderer().getModels().body();
stack.push(); stack.push();

View file

@ -1,14 +1,13 @@
package com.minelittlepony.client.render.entity.npc; package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.village.VillagerDataContainer; import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.VillagerProfession; 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.model.gear.Gear;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Wearable; 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.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.*; 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>> { 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 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) { 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)); super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), SillyPonyTextureSupplier.create(textureSupplier, formatter));
clothing = new NpcClothingFeature<>(this, type); clothing = new NpcClothingFeature<>(this, type);
this.manager.setModelsLookup(entity -> models.apply(getEntityPony(entity).race()));
addFeature(clothing); addFeature(clothing);
} }
@ -54,20 +59,6 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
return super.shouldRender(model, entity, wearable, gear); 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) { protected void initializeModel(ClientPonyModel<T> model) {
} }