WIP update to 1.20.3

This commit is contained in:
Sollace 2024-11-09 15:51:59 +00:00
parent c8709ea1b8
commit 1b5a46b716
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
72 changed files with 1187 additions and 1095 deletions

View file

@ -4,7 +4,7 @@ buildscript {
} }
} }
plugins { plugins {
id 'fabric-loom' version '1.6-SNAPSHOT' id 'fabric-loom' version '1.7-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
id 'com.modrinth.minotaur' version '2.+' id 'com.modrinth.minotaur' version '2.+'
id 'org.ajoberstar.reckon' version '0.13.1' id 'org.ajoberstar.reckon' version '0.13.1'

View file

@ -3,10 +3,10 @@ org.gradle.daemon=false
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/develop # check these on https://fabricmc.net/develop
minecraft_version=1.21 minecraft_version=1.21.3
yarn_mappings=1.21+build.9 yarn_mappings=1.21.3+build.2
loader_version=0.15.11 loader_version=0.16.7
fabric_version=0.100.7+1.21 fabric_version=0.106.1+1.21.3
# Mod Properties # Mod Properties
group=com.minelittlepony group=com.minelittlepony
@ -19,7 +19,7 @@ org.gradle.daemon=false
modrinth_project_id=JBjInUXM modrinth_project_id=JBjInUXM
# Dependencies # Dependencies
modmenu_version=11.0.0-beta.1 modmenu_version=12.0.0-beta.1
kirin_version=1.19.1+1.21 kirin_version=1.19.1+1.21
hd_skins_version=6.13.0+1.21 hd_skins_version=6.13.0+1.21
mson_version=1.10.0+1.21 mson_version=1.11.0+1.21.3

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -2,7 +2,6 @@ package com.minelittlepony.api.events;
import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory; import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.Entity;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
@ -20,5 +19,5 @@ public interface PonyModelPrepareCallback {
} }
}); });
void onPonyModelPrepared(Entity entity, PonyModel<?> model, ModelAttributes.Mode mode); void onPonyModelPrepared(ModelAttributes attributes, PonyModel<?> model, ModelAttributes.Mode mode);
} }

View file

@ -1,17 +1,17 @@
package com.minelittlepony.api.model; package com.minelittlepony.api.model;
import net.minecraft.entity.LivingEntity; import com.minelittlepony.client.render.entity.state.PonyRenderState;
public interface HornedPonyModel<T extends LivingEntity> extends PonyModel<T> { public interface HornedPonyModel<T extends PonyRenderState> extends PonyModel<T> {
/** /**
* Returns true if this model is being applied to a race that can use magic. * Returns true if this model is being applied to a race that can use magic.
*/ */
default boolean hasMagic() { default boolean hasMagic(T state) {
return getRace().hasHorn() && getAttributes().metadata.glowColor() != 0; return state.getRace().hasHorn() && state.attributes.metadata.glowColor() != 0;
} }
/** /**
* Returns true if this model is currently using magic (horn is lit). * Returns true if this model is currently using magic (horn is lit).
*/ */
boolean isCasting(); boolean isCasting(T state);
} }

View file

@ -2,6 +2,7 @@ package com.minelittlepony.api.model;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.common.util.animation.Interpolator; import com.minelittlepony.common.util.animation.Interpolator;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -73,6 +74,11 @@ public class ModelAttributes {
*/ */
public boolean isHorsey; public boolean isHorsey;
/**
* Flag indicating whether the pony is a player
*/
public boolean isPlayer;
/** /**
* Vertical pitch whilst flying. * Vertical pitch whilst flying.
*/ */
@ -130,7 +136,7 @@ public class ModelAttributes {
isGoingFast = (isFlying && model instanceof WingedPonyModel) || isGliding; isGoingFast = (isFlying && model instanceof WingedPonyModel) || isGliding;
isGoingFast &= zMotion > 0.4F; isGoingFast &= zMotion > 0.4F;
isGoingFast |= entity.isUsingRiptide(); isGoingFast |= entity.isUsingRiptide();
isGoingFast |= entity.isFallFlying(); isGoingFast |= entity.isGliding();
motionLerp = MathUtil.clampLimit(zMotion * 30, 1); motionLerp = MathUtil.clampLimit(zMotion * 30, 1);
@ -148,18 +154,19 @@ public class ModelAttributes {
} }
public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) { public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) {
isPlayer = entity instanceof PlayerEntity;
visualHeight = entity.getHeight() + 0.125F; visualHeight = entity.getHeight() + 0.125F;
isSitting = PonyPosture.isSitting(entity); isSitting = PonyPosture.isSitting(entity);
isSleeping = entity.isAlive() && entity.isSleeping();; isSleeping = entity.isAlive() && entity.isSleeping();;
isLyingDown = isSleeping; isLyingDown = isSleeping;
if (entity instanceof PlayerEntity) { if (isPlayer) {
boolean moving = entity.getVelocity().multiply(1, 0, 1).length() == 0 && entity.isSneaking(); boolean moving = entity.getVelocity().multiply(1, 0, 1).length() == 0 && entity.isSneaking();
isLyingDown |= getMainInterpolator().interpolate("lyingDown", moving ? 10 : 0, 200) >= 9; isLyingDown |= getMainInterpolator().interpolate("lyingDown", moving ? 10 : 0, 200) >= 9;
} }
isCrouching = !isLyingDown && !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity); isCrouching = !isLyingDown && !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity);
isFlying = !isLyingDown && mode == Mode.THIRD_PERSON && PonyPosture.isFlying(entity); isFlying = !isLyingDown && mode == Mode.THIRD_PERSON && PonyPosture.isFlying(entity);
isGliding = entity.isFallFlying(); isGliding = entity.isGliding();
isSwimming = mode == Mode.THIRD_PERSON && PonyPosture.isSwimming(entity); isSwimming = mode == Mode.THIRD_PERSON && PonyPosture.isSwimming(entity);
isSwimmingRotated = isSwimming; isSwimmingRotated = isSwimming;
isRiptide = entity.isUsingRiptide(); isRiptide = entity.isUsingRiptide();
@ -185,6 +192,21 @@ public class ModelAttributes {
&& (complement != ArmPose.BLOCK && complement != ArmPose.CROSSBOW_HOLD); && (complement != ArmPose.BLOCK && complement != ArmPose.CROSSBOW_HOLD);
} }
/**
* Tests if this model is wearing the given piece of gear.
*/
public boolean isWearing(Wearable wearable) {
return isEmbedded(wearable) || featureSkins.contains(wearable.getId());
}
/**
* Tests if the chosen piece of gear is sourcing its texture from the main skin.
* i.e. Used to change wing rendering when using saddlebags.
*/
public boolean isEmbedded(Wearable wearable) {
return metadata.gear().matches(wearable);
}
public enum Mode { public enum Mode {
FIRST_PERSON, FIRST_PERSON,
THIRD_PERSON, THIRD_PERSON,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.ModelWithArms; import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose; import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
@ -10,5 +11,5 @@ public interface ModelWithHooves extends ModelWithArms {
ModelPart getHindLeg(Arm side); ModelPart getHindLeg(Arm side);
ArmPose getArmPoseForSide(Arm side); <S extends PlayerEntityRenderState> ArmPose getArmPoseForSide(S state, Arm side);
} }

View file

@ -2,84 +2,21 @@ package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.mson.api.MsonModel;
public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead { public interface PonyModel<T extends BipedEntityRenderState & PonyModel.AttributedHolder> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
void copyAttributes(BipedEntityModel<T> other);
void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode);
ModelPart getBodyPart(BodyPart part); ModelPart getBodyPart(BodyPart part);
/** /**
* Applies a transform particular to a certain body part. * Applies a transform particular to a certain body part.
*/ */
void transform(BodyPart part, MatrixStack stack); void transform(T state, BodyPart part, MatrixStack stack);
/** public interface AttributedHolder {
* Gets the transitive properties of this model.
*/
ModelAttributes getAttributes(); ModelAttributes getAttributes();
/**
* Sets the pony metadata object associated with this model.
*/
void setMetadata(PonyData meta);
/**
* Gets the active scaling profile used to lay out this model's parts.
*/
default Size getSize() {
return PonyConfig.getEffectiveSize(getAttributes().metadata.size());
} }
default Race getRace() {
return PonyConfig.getEffectiveRace(getAttributes().metadata.race());
}
/**
* Gets the current leg swing amount.
*/
float getSwingAmount();
/**
* Gets the step wobble used for various hair bits and animations.
*/
default float getWobbleAmount() {
if (getSwingAmount() <= 0) {
return 0;
}
return MathHelper.sin(MathHelper.sqrt(getSwingAmount()) * MathHelper.PI * 2) * 0.04F;
}
/**
* Gets the y-offset applied to entities riding this one.
*/
float getRiderYOffset();
/**
* Tests if this model is wearing the given piece of gear.
*/
default boolean isWearing(Wearable wearable) {
return isEmbedded(wearable) || getAttributes().featureSkins.contains(wearable.getId());
}
/**
* Tests if the chosen piece of gear is sourcing its texture from the main skin.
* i.e. Used to change wing rendering when using saddlebags.
*/
default boolean isEmbedded(Wearable wearable) {
return getAttributes().metadata.gear().matches(wearable);
}
} }

View file

@ -3,9 +3,9 @@ package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.model.ModelWithArms; import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose; import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
@ -14,7 +14,7 @@ import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter; import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter;
public interface PonyModelMixin<T extends LivingEntity, M extends PonyModel<T>> extends PonyModel<T> { public interface PonyModelMixin<T extends BipedEntityRenderState, M extends PonyModel<T>> extends PonyModel<T> {
M mixin(); M mixin();
@Override @Override
@ -108,7 +108,7 @@ public interface PonyModelMixin<T extends LivingEntity, M extends PonyModel<T>>
mixin().setHatVisible(hatVisible); mixin().setHatVisible(hatVisible);
} }
interface Caster<T extends LivingEntity, M extends PonyModel<T> & HornedPonyModel<T>, ArmModel> extends PonyModelMixin<T, M>, HornedPonyModel<T> { interface Caster<T extends BipedEntityRenderState, M extends PonyModel<T> & HornedPonyModel<T>, ArmModel> extends PonyModelMixin<T, M>, HornedPonyModel<T> {
@Override @Override
default boolean isCasting() { default boolean isCasting() {
return mixin().isCasting(); return mixin().isCasting();

View file

@ -1,12 +1,12 @@
package com.minelittlepony.api.model; package com.minelittlepony.api.model;
import net.minecraft.entity.LivingEntity; import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> { public interface WingedPonyModel<T extends BipedEntityRenderState & PonyModel.AttributedHolder> extends PonyModel<T> {
public static final float WINGS_HALF_SPREAD_ANGLE = MathUtil.Angles._270_DEG; public static final float WINGS_HALF_SPREAD_ANGLE = MathUtil.Angles._270_DEG;
public static final float WINGS_FULL_SPREAD_ANGLE = MathUtil.Angles._270_DEG + 0.4F; public static final float WINGS_FULL_SPREAD_ANGLE = MathUtil.Angles._270_DEG + 0.4F;
public static final float WINGS_RAISED_ANGLE = 4; public static final float WINGS_RAISED_ANGLE = 4;
@ -14,15 +14,15 @@ public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> {
/** /**
* Returns true if the wings are spread. * Returns true if the wings are spread.
*/ */
default boolean wingsAreOpen() { default boolean wingsAreOpen(T state) {
return (getAttributes().isSwimming || getAttributes().isFlying || getAttributes().isCrouching) return (state.getAttributes().isSwimming || state.getAttributes().isFlying || state.getAttributes().isCrouching)
&& (PonyConfig.getInstance().flappyElytras.get() || !getAttributes().isGliding); && (PonyConfig.getInstance().flappyElytras.get() || !state.getAttributes().isGliding);
} }
default boolean isBurdened() { default boolean isBurdened(T state) {
return isWearing(Wearable.SADDLE_BAGS_BOTH) return state.getAttributes().isWearing(Wearable.SADDLE_BAGS_BOTH)
|| isWearing(Wearable.SADDLE_BAGS_LEFT) || state.getAttributes().isWearing(Wearable.SADDLE_BAGS_LEFT)
|| isWearing(Wearable.SADDLE_BAGS_RIGHT); || state.getAttributes().isWearing(Wearable.SADDLE_BAGS_RIGHT);
} }
/** /**
@ -35,8 +35,8 @@ public interface WingedPonyModel<T extends LivingEntity> extends PonyModel<T> {
* *
* @param ticks Partial render ticks * @param ticks Partial render ticks
*/ */
default float getWingRotationFactor(float ticks) { default float getWingRotationFactor(T state, float ticks) {
return getAttributes().wingAngle; return state.getAttributes().wingAngle;
} }
} }

View file

@ -6,38 +6,22 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public abstract class AbstractGearModel extends Model implements Gear { public abstract class AbstractGearModel extends Model implements Gear {
private final List<ModelPart> parts = new ArrayList<>();
private final float stackingHeight; private final float stackingHeight;
public AbstractGearModel(float stackingHeight) { public AbstractGearModel(ModelPart root, float stackingHeight) {
super(RenderLayer::getEntitySolid); super(root, RenderLayer::getEntitySolid);
this.stackingHeight = stackingHeight; this.stackingHeight = stackingHeight;
} }
public AbstractGearModel addPart(ModelPart t) {
parts.add(t);
return this;
}
@Override @Override
public void render(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, UUID interpolatorId) { public void render(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, UUID interpolatorId) {
render(stack, vertices, overlay, light, color); render(stack, vertices, overlay, light, color);
} }
@Override
public void render(MatrixStack stack, VertexConsumer renderContext, int overlay, int light, int color) {
parts.forEach(part -> {
part.render(stack, renderContext, overlay, light, color);
});
}
@Override @Override
public boolean isStackable() { public boolean isStackable() {
return stackingHeight > 0; return stackingHeight > 0;

View file

@ -3,6 +3,7 @@ package com.minelittlepony.api.model.gear;
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.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -37,7 +38,7 @@ public interface Gear {
* *
* @return True to render this wearable * @return True to render this wearable
*/ */
boolean canRender(PonyModel<?> model, Entity entity); boolean canRender(PonyModel<?> model, EntityRenderState entity);
/** /**
* Gets the body location that this wearable appears on. * Gets the body location that this wearable appears on.
@ -62,12 +63,12 @@ public interface Gear {
* *
* If you need to use the player's own skin, use {@link IRenderContext#getDefaultTexture(entity, wearable)} * If you need to use the player's own skin, use {@link IRenderContext#getDefaultTexture(entity, wearable)}
*/ */
<T extends Entity> Identifier getTexture(T entity, Context<T, ?> context); <S extends EntityRenderState> Identifier getTexture(S entity, Context<S, ?> context);
/** /**
* Gets the layer used to render this piece of gear. * Gets the layer used to render this piece of gear.
*/ */
default <T extends Entity> RenderLayer getLayer(T entity, Context<T, ?> context) { default <S extends EntityRenderState> RenderLayer getLayer(S entity, Context<S, ?> context) {
return RenderLayer.getEntityTranslucent(getTexture(entity, context)); return RenderLayer.getEntityTranslucent(getTexture(entity, context));
} }
@ -100,7 +101,7 @@ public interface Gear {
* @param <T> The type of entity being rendered. * @param <T> The type of entity being rendered.
* @param <M> The type of the entity's primary model. * @param <M> The type of the entity's primary model.
*/ */
public interface Context<T extends Entity, M extends PonyModel<?>> { public interface Context<S extends EntityRenderState, M extends PonyModel<?>> {
/** /**
* The empty context. * The empty context.
*/ */
@ -109,7 +110,7 @@ public interface Gear {
/** /**
* Checks whether the given wearable and gear are able to render for this specific entity and its renderer. * Checks whether the given wearable and gear are able to render for this specific entity and its renderer.
*/ */
default boolean shouldRender(M model, T entity, Wearable wearable, Gear gear) { default boolean shouldRender(M model, S entity, Wearable wearable, Gear gear) {
return gear.canRender(model, entity); return gear.canRender(model, entity);
} }
@ -118,6 +119,6 @@ public interface Gear {
* *
* May be the entity's own texture or a specific texture allocated for that wearable. * May be the entity's own texture or a specific texture allocated for that wearable.
*/ */
Identifier getDefaultTexture(T entity, Wearable wearable); Identifier getDefaultTexture(S entity, Wearable wearable);
} }
} }

View file

@ -1,5 +1,6 @@
package com.minelittlepony.api.model.gear; package com.minelittlepony.api.model.gear;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -12,8 +13,8 @@ public class WearableGear extends AbstractGearModel {
protected final Wearable wearable; protected final Wearable wearable;
protected final BodyPart location; protected final BodyPart location;
public WearableGear(Wearable wearable, BodyPart location, float stackingHeight) { public WearableGear(ModelPart root, Wearable wearable, BodyPart location, float stackingHeight) {
super(stackingHeight); super(root, stackingHeight);
this.wearable = wearable; this.wearable = wearable;
this.location = location; this.location = location;
} }

View file

@ -32,7 +32,7 @@ public final class PonyPosture {
Vec3d motion = entity.getVelocity(); Vec3d motion = entity.getVelocity();
double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z); double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
return (isFlying(entity) && pony.race().hasWings()) || entity.isFallFlying() & zMotion > 0.4F; return (isFlying(entity) && pony.race().hasWings()) || entity.isGliding() & zMotion > 0.4F;
} }
public static boolean isFlying(LivingEntity entity) { public static boolean isFlying(LivingEntity entity) {

View file

@ -29,9 +29,9 @@ public interface TriggerPixel<T> {
MAX_COORDS.y = Math.max(MAX_COORDS.y, y); MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
Int2ObjectOpenHashMap<T> lookup = buildLookup(options); Int2ObjectOpenHashMap<T> lookup = buildLookup(options);
return image -> { return image -> {
int color = Color.abgrToArgb(image.getColor(x, y)); int color = image.getColor(x, y);
if (ColorHelper.Argb.getAlpha(color) < 255) { if (ColorHelper.getAlpha(color) < 255) {
return (T)def; return (T)def;
} }
return lookup.getOrDefault(color & 0x00FFFFFF, def); return lookup.getOrDefault(color & 0x00FFFFFF, def);
@ -55,15 +55,15 @@ public interface TriggerPixel<T> {
} }
}; };
return image -> { return image -> {
int color = Color.abgrToArgb(image.getColor(x, y)); int color = image.getColor(x, y);
if (ColorHelper.Argb.getAlpha(color) < 255) { if (ColorHelper.getAlpha(color) < 255) {
return def; return def;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Set<T> values = EnumSet.noneOf((Class<T>)def.def().getClass()); Set<T> values = EnumSet.noneOf((Class<T>)def.def().getClass());
if (flagReader.readFlag(ColorHelper.Argb.getRed(color), values) if (flagReader.readFlag(ColorHelper.getRed(color), values)
| flagReader.readFlag(ColorHelper.Argb.getGreen(color), values) | flagReader.readFlag(ColorHelper.getGreen(color), values)
| flagReader.readFlag(ColorHelper.Argb.getBlue(color), values)) { | flagReader.readFlag(ColorHelper.getBlue(color), values)) {
return new Flags<>(def.def(), values, color & 0x00FFFFFF); return new Flags<>(def.def(), values, color & 0x00FFFFFF);
} }
return def; return def;

View file

@ -54,6 +54,6 @@ public enum Wearable implements TValue<Wearable> {
@Override @Override
public int getChannelAdjustedColorCode() { public int getChannelAdjustedColorCode() {
return triggerValue == 0 ? 0 : ColorHelper.Argb.getArgb(255, triggerValue, triggerValue, triggerValue); return triggerValue == 0 ? 0 : ColorHelper.getArgb(255, triggerValue, triggerValue, triggerValue);
} }
} }

View file

@ -93,7 +93,7 @@ public class MineLPHDSkins extends ClientSkinsProxy implements ClientModInitiali
@Override @Override
public Optional<Identifier> getSkin(Identifier skinTypeId, PlayerEntity player) { public Optional<Identifier> getSkin(Identifier skinTypeId, PlayerEntity player) {
if (player instanceof AbstractClientPlayerEntity clientPlayer) { if (player instanceof AbstractClientPlayerEntity clientPlayer) {
return SkinType.REGISTRY.getOrEmpty(skinTypeId).flatMap(type -> getSkin(type, clientPlayer)); return SkinType.REGISTRY.getOptionalValue(skinTypeId).flatMap(type -> getSkin(type, clientPlayer));
} }

View file

@ -10,10 +10,10 @@ import org.jetbrains.annotations.Nullable;
import net.minecraft.client.render.item.HeldItemRenderer; import net.minecraft.client.render.item.HeldItemRenderer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
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.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;

View file

@ -3,6 +3,7 @@ package com.minelittlepony.client.model;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.events.PonyModelPrepareCallback; import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.meta.SizePreset; import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.transform.PonyTransformation; import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.mson.util.RenderList; import com.minelittlepony.mson.util.RenderList;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -14,15 +15,22 @@ import java.util.function.Supplier;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.consume.UseAction;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import org.jetbrains.annotations.Nullable;
/** /**
* Foundation class for all types of ponies. * Foundation class for all types of ponies.
*/ */
public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPonyModel<T> { public abstract class AbstractPonyModel<T extends PonyRenderState> extends ClientPonyModel<T> {
public static final float NECK_X = 0.166F; public static final float NECK_X = 0.166F;
public static final float LEG_SNEAKING_PITCH_ADJUSTMENT = 0.4F; public static final float LEG_SNEAKING_PITCH_ADJUSTMENT = 0.4F;
public static final float BODY_RIDING_PITCH = MathHelper.PI * 3.8F; public static final float BODY_RIDING_PITCH = MathHelper.PI * 3.8F;
@ -51,8 +59,11 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
private final List<SubModel> parts = new ArrayList<>(); private final List<SubModel> parts = new ArrayList<>();
public AbstractPonyModel(ModelPart tree) { @Nullable
super(tree); protected T currentState;
public AbstractPonyModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms);
neck = tree.getChild("neck"); neck = tree.getChild("neck");
mainRenderList = RenderList.of() mainRenderList = RenderList.of()
@ -71,14 +82,19 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
protected RenderList forPart(Supplier<SubModel> part) { protected RenderList forPart(Supplier<SubModel> part) {
return (stack, vertices, overlay, light, color) -> { return (stack, vertices, overlay, light, color) -> part.get().renderPart(stack, vertices, overlay, light, color, currentState.attributes);
part.get().renderPart(stack, vertices, overlay, light, color, attributes);
};
} }
protected RenderList forPart(SubModel part) { protected RenderList forPart(SubModel part) {
return (stack, vertices, overlay, light, color) -> part.renderPart(stack, vertices, overlay, light, color, currentState.attributes);
}
protected RenderList withStage(BodyPart part, RenderList action) {
return (stack, vertices, overlay, light, color) -> { return (stack, vertices, overlay, light, color) -> {
part.renderPart(stack, vertices, overlay, light, color, attributes); stack.push();
transform(currentState, part, stack);
action.accept(stack, vertices, overlay, light, color);
stack.pop();
}; };
} }
@ -87,27 +103,19 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
mainRenderList.accept(stack, vertices, overlay, light, color); mainRenderList.accept(stack, vertices, overlay, light, color);
} }
protected RenderList withStage(BodyPart part, RenderList action) {
return (stack, vertices, overlay, light, color) -> {
stack.push();
transform(part, stack);
action.accept(stack, vertices, overlay, light, color);
stack.pop();
};
}
/** /**
* Sets the model's various rotation angles. * Sets the model's various rotation angles.
*/ */
@SuppressWarnings("unchecked")
@Override @Override
public final void setAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) { public final void setAngles(PlayerEntityRenderState entity) {
attributes.checkRainboom(entity, this, animationProgress); currentState = (T)entity;
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, ModelAttributes.Mode.OTHER); super.setAngles((PlayerEntityRenderState)entity);
super.setAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch);
resetPivot(head, neck, leftArm, rightArm, leftLeg, rightLeg); resetPivot(head, neck, leftArm, rightArm, leftLeg, rightLeg);
setModelAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch); setModelVisibilities((T)entity);
setModelAngles((T)entity);
leftSleeve.copyTransform(leftArm); leftSleeve.copyTransform(leftArm);
rightSleeve.copyTransform(rightArm); rightSleeve.copyTransform(rightArm);
@ -117,57 +125,70 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
hat.copyTransform(head); hat.copyTransform(head);
} }
protected void setModelAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) { protected void setModelVisibilities(T state) {
float pitch = attributes.motionPitch * MathHelper.RADIANS_PER_DEGREE; hat.visible = head.visible && !state.attributes.isHorsey;
parts.forEach(part -> part.setVisible(body.visible, state.attributes));
}
protected void setModelAngles(T entity) {
setModelAngles((T)entity, entity.limbAmplitudeInverse, entity.limbAmplitudeMultiplier, entity.age, entity.yawDegrees, entity.pitch);
}
@Deprecated
protected final void setModelAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
float pitch = entity.attributes.motionPitch * MathHelper.RADIANS_PER_DEGREE;
head.setAngles( head.setAngles(
MathHelper.clamp(attributes.isSleeping ? 0.1f : headPitch / 57.29578F, -1.25f - pitch, 0.5f - pitch), MathHelper.clamp(entity.attributes.isSleeping ? 0.1f : headPitch / 57.29578F, -1.25f - pitch, 0.5f - pitch),
attributes.isSleeping ? (Math.signum(MathHelper.wrapDegrees(headYaw)) * 1.3F) : headYaw * MathHelper.RADIANS_PER_DEGREE, entity.attributes.isSleeping ? (Math.signum(MathHelper.wrapDegrees(headYaw)) * 1.3F) : headYaw * MathHelper.RADIANS_PER_DEGREE,
0 0
); );
float wobbleAmount = getWobbleAmount(); float wobbleAmount = entity.getWobbleAmount();
body.yaw = wobbleAmount; body.yaw = wobbleAmount;
neck.yaw = wobbleAmount; neck.yaw = wobbleAmount;
rotateLegs(limbAngle, limbSpeed, animationProgress, entity); rotateLegs(entity, limbAngle, limbSpeed, animationProgress, entity);
ArmPose left = getArmPose(entity, Arm.LEFT);
ArmPose right = getArmPose(entity, Arm.RIGHT);
if (onSetModelAngles != null) { if (onSetModelAngles != null) {
onSetModelAngles.poseModel(this, limbAngle, limbSpeed, animationProgress, entity); onSetModelAngles.poseModel(this, entity);
} }
if (!attributes.isSwimming && !attributes.isGoingFast) { if (!entity.attributes.isSwimming && !entity.attributes.isGoingFast) {
holdItem(limbSpeed); holdItem(entity, limbSpeed, left, right);
} }
swingItem(entity); swingItem(entity);
if (attributes.isCrouching) { if (entity.attributes.isCrouching) {
ponyCrouch(); ponyCrouch(entity);
} else if (riding) { } else if (entity.isInPose(EntityPose.SITTING)) {
ponySit(); ponySit();
} else { } else {
adjustBody(0, ORIGIN); adjustBody(entity, 0, ORIGIN);
if (!attributes.isLyingDown) { if (!entity.attributes.isLyingDown) {
animateBreathing(animationProgress); animateBreathing(entity, animationProgress, left, right);
} }
if (attributes.isSwimmingRotated) { if (entity.attributes.isSwimmingRotated) {
rightLeg.pivotZ -= 1.5F; rightLeg.pivotZ -= 1.5F;
leftLeg.pivotZ -= 1.5F; leftLeg.pivotZ -= 1.5F;
} }
} }
if (attributes.isLyingDown) { if (entity.attributes.isLyingDown) {
ponySleep(); ponySleep();
} }
if (attributes.isHorsey) { if (entity.attributes.isHorsey) {
head.pivotY -= 3; head.pivotY -= 3;
head.pivotZ -= 2; head.pivotZ -= 2;
head.pitch = 0.5F; head.pitch = 0.5F;
} }
parts.forEach(part -> part.setPartAngles(attributes, limbAngle, limbSpeed, wobbleAmount, animationProgress)); parts.forEach(part -> part.setPartAngles(entity.attributes, limbAngle, limbSpeed, wobbleAmount, animationProgress));
} }
public void setHeadRotation(float animationProgress, float yaw, float pitch) { public void setHeadRotation(float animationProgress, float yaw, float pitch) {
@ -179,8 +200,8 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
/** /**
* Aligns legs to a sneaky position. * Aligns legs to a sneaky position.
*/ */
protected void ponyCrouch() { protected void ponyCrouch(T state) {
adjustBody(BODY_SNEAKING_PITCH, BODY_SNEAKING); adjustBody(state, BODY_SNEAKING_PITCH, BODY_SNEAKING);
HEAD_SNEAKING.set(head); HEAD_SNEAKING.set(head);
rightArm.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT; rightArm.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT;
@ -232,11 +253,11 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles} * Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
* *
*/ */
protected void rotateLegs(float move, float swing, float ticks, T entity) { protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
if (attributes.isSwimming) { if (state.attributes.isSwimming) {
rotateLegsSwimming(move, swing, ticks, entity); rotateLegsSwimming(state, move, swing, ticks, entity);
} else { } else {
rotateLegsOnGround(move, swing, ticks, entity); rotateLegsOnGround(state, move, swing, ticks, entity);
} }
float sin = MathHelper.sin(body.yaw) * 5; float sin = MathHelper.sin(body.yaw) * 5;
@ -245,8 +266,8 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
rightArm.pivotZ = 2 + sin; rightArm.pivotZ = 2 + sin;
leftArm.pivotZ = 2 - sin; leftArm.pivotZ = 2 - sin;
float legRPX = attributes.getMainInterpolator().interpolate("legOffset", cos - getLegOutset() - 0.001F, 2); float legRPX = state.attributes.getMainInterpolator().interpolate("legOffset", cos - state.legOutset - 0.001F, 2);
if (attributes.isHorsey) { if (state.attributes.isHorsey) {
legRPX += 2; legRPX += 2;
} }
@ -259,7 +280,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
rightArm.yaw += body.yaw; rightArm.yaw += body.yaw;
leftArm.yaw += body.yaw; leftArm.yaw += body.yaw;
if (attributes.isHorsey) { if (state.attributes.isHorsey) {
rightArm.pivotZ = leftArm.pivotZ = -1; rightArm.pivotZ = leftArm.pivotZ = -1;
rightArm.pivotY = leftArm.pivotY = 6; rightArm.pivotY = leftArm.pivotY = 6;
rightLeg.pivotZ = leftLeg.pivotZ = 19; rightLeg.pivotZ = leftLeg.pivotZ = 19;
@ -272,9 +293,9 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* *
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles} * Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*/ */
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) { protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
float lerp = entity.isSwimming() ? (float)attributes.motionLerp : 1; float lerp = entity.isInPose(EntityPose.SWIMMING) ? (float)state.attributes.motionLerp : 1;
float legLeft = (MathUtil.Angles._90_DEG + MathHelper.sin((move / 3) + 2 * MathHelper.PI/3) / 2) * lerp; float legLeft = (MathUtil.Angles._90_DEG + MathHelper.sin((move / 3) + 2 * MathHelper.PI/3) / 2) * lerp;
@ -291,15 +312,15 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* Rotates legs in quopy fashion for walking. * Rotates legs in quopy fashion for walking.
* *
*/ */
protected void rotateLegsOnGround(float move, float swing, float ticks, T entity) { protected void rotateLegsOnGround(T state, float move, float swing, float ticks, T entity) {
float angle = MathHelper.PI * (float) Math.pow(swing, 16); float angle = MathHelper.PI * (float) Math.pow(swing, 16);
float baseRotation = move * 0.6662F; // magic number ahoy float baseRotation = move * 0.6662F; // magic number ahoy
float scale = swing / 4; float scale = swing / 4;
float rainboomLegLotation = attributes.getMainInterpolator().interpolate( float rainboomLegLotation = state.attributes.getMainInterpolator().interpolate(
"rainboom_leg_rotation", "rainboom_leg_rotation",
attributes.isGoingFast ? 1 : 0, state.attributes.isGoingFast ? 1 : 0,
5 5
); );
float yAngle = 0.2F * rainboomLegLotation; float yAngle = 0.2F * rainboomLegLotation;
@ -310,24 +331,12 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
rightLeg.setAngles(MathHelper.lerp(rainboomLegLotation, MathHelper.cos(baseRotation + angle / 5) * scale, MathUtil.Angles._90_DEG * rainboomLegLotation), -yAngle, rightLeg.roll); rightLeg.setAngles(MathHelper.lerp(rainboomLegLotation, MathHelper.cos(baseRotation + angle / 5) * scale, MathUtil.Angles._90_DEG * rainboomLegLotation), -yAngle, rightLeg.roll);
} }
protected float getLegOutset() {
if (attributes.isLyingDown) {
return 3.6f;
}
if (attributes.isCrouching) {
return 1;
}
return 5;
}
/** /**
* Adjusts legs as if holding an item. Delegates to the correct arm/leg/limb as necessary. * Adjusts legs as if holding an item. Delegates to the correct arm/leg/limb as necessary.
*/ */
protected void holdItem(float limbSpeed) { protected void holdItem(T state, float limbSpeed, ArmPose left, ArmPose right) {
alignArmForAction(getArm(Arm.LEFT), leftArmPose, rightArmPose, limbSpeed, 1); alignArmForAction(state, getArm(Arm.LEFT), left, right, limbSpeed, 1);
alignArmForAction(getArm(Arm.RIGHT), rightArmPose, leftArmPose, limbSpeed, -1); alignArmForAction(state, getArm(Arm.RIGHT), right, left, limbSpeed, -1);
} }
@Override @Override
@ -350,16 +359,16 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* @param pose The post to align to * @param pose The post to align to
* @param limbSpeed Degree to which each 'limb' swings. * @param limbSpeed Degree to which each 'limb' swings.
*/ */
protected void alignArmForAction(ModelPart arm, ArmPose pose, ArmPose complement, float limbSpeed, float sigma) { protected void alignArmForAction(T state, ModelPart arm, ArmPose pose, ArmPose complement, float limbSpeed, float sigma) {
switch (pose) { switch (pose) {
case ITEM: case ITEM:
arm.yaw = 0; arm.yaw = 0;
boolean both = pose == complement; boolean both = pose == complement;
if (attributes.shouldLiftArm(pose, complement, sigma)) { if (state.attributes.shouldLiftArm(pose, complement, sigma)) {
float swag = 1; float swag = 1;
if (!getAttributes().isFlying && both) { if (!state.attributes.isFlying && both) {
swag -= (float)Math.pow(limbSpeed, 2); swag -= (float)Math.pow(limbSpeed, 2);
} }
@ -368,7 +377,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
arm.roll = -sigma * (MathHelper.PI / 15); arm.roll = -sigma * (MathHelper.PI / 15);
arm.roll += 0.3F * -limbSpeed * sigma; arm.roll += 0.3F * -limbSpeed * sigma;
if (attributes.isCrouching) { if (state.attributes.isCrouching) {
arm.pivotX -= sigma * 2; arm.pivotX -= sigma * 2;
} }
} }
@ -386,21 +395,21 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
arm.pivotX += sigma; arm.pivotX += sigma;
arm.pivotZ += 3; arm.pivotZ += 3;
if (attributes.isCrouching) { if (state.attributes.isCrouching) {
arm.pivotY += 4; arm.pivotY += 4;
} }
break; break;
case BOW_AND_ARROW: case BOW_AND_ARROW:
aimBow(arm, limbSpeed); aimBow(state, arm, limbSpeed);
break; break;
case CROSSBOW_HOLD: case CROSSBOW_HOLD:
aimBow(arm, limbSpeed); aimBow(state, arm, limbSpeed);
arm.pitch = head.pitch - MathUtil.Angles._90_DEG; arm.pitch = head.pitch - MathUtil.Angles._90_DEG;
arm.yaw = head.yaw + 0.06F; arm.yaw = head.yaw + 0.06F;
break; break;
case CROSSBOW_CHARGE: case CROSSBOW_CHARGE:
aimBow(arm, limbSpeed); aimBow(state, arm, limbSpeed);
arm.pitch = -0.8F; arm.pitch = -0.8F;
arm.yaw = head.yaw + 0.06F; arm.yaw = head.yaw + 0.06F;
@ -412,20 +421,20 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
arm.pivotY ++; arm.pivotY ++;
break; break;
case SPYGLASS: case SPYGLASS:
float addedPitch = sneaking ? -0.2617994F : 0; float addedPitch = state.isInSneakingPose ? -0.2617994F : 0;
float minPitch = sneaking ? -1.8F : -2.4F; float minPitch = state.isInSneakingPose ? -1.8F : -2.4F;
arm.pitch = MathHelper.clamp(head.pitch - 1.9198622F - addedPitch, minPitch, 3.3F); arm.pitch = MathHelper.clamp(head.pitch - 1.9198622F - addedPitch, minPitch, 3.3F);
arm.yaw = head.yaw; arm.yaw = head.yaw;
if (sneaking) { if (state.isInSneakingPose) {
arm.pivotY += 9; arm.pivotY += 9;
arm.pivotX -= 6 * sigma; arm.pivotX -= 6 * sigma;
arm.pivotZ -= 2; arm.pivotZ -= 2;
} }
if (getSize() == SizePreset.TALL) { if (state.getSize() == SizePreset.TALL) {
arm.pivotY += 1; arm.pivotY += 1;
} }
if (getSize() == SizePreset.FOAL) { if (state.getSize() == SizePreset.FOAL) {
arm.pivotY -= 2; arm.pivotY -= 2;
} }
@ -446,26 +455,24 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
} }
} }
protected void aimBow(ModelPart arm, float limbSpeed) { protected void aimBow(T state, ModelPart arm, float limbSpeed) {
arm.pitch = MathUtil.Angles._270_DEG + head.pitch + (MathHelper.sin(limbSpeed * 0.067F) * 0.05F); arm.pitch = MathUtil.Angles._270_DEG + head.pitch + (MathHelper.sin(limbSpeed * 0.067F) * 0.05F);
arm.yaw = head.yaw - 0.06F; arm.yaw = head.yaw - 0.06F;
arm.roll = MathHelper.cos(limbSpeed * 0.09F) * 0.05F + 0.05F; arm.roll = MathHelper.cos(limbSpeed * 0.09F) * 0.05F + 0.05F;
if (sneaking) { if (state.isInSneakingPose) {
arm.pivotY += 4; arm.pivotY += 4;
} }
} }
/** /**
* Animates arm swinging. Delegates to the correct arm/leg/limb as neccessary. * Animates arm swinging. Delegates to the correct arm/leg/limb as necessary.
* *
* @param entity The entity we are being called for. * @param entity The entity we are being called for.
*/ */
protected void swingItem(T entity) { protected void swingItem(T state) {
if (getSwingAmount() > 0 && !attributes.isLyingDown) { if (state.getSwingAmount() > 0 && !state.attributes.isLyingDown) {
Arm mainSide = getPreferredArm(entity); swingArm(state, getArm(state.preferredArm));
swingArm(getArm(mainSide));
} }
} }
@ -474,11 +481,11 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* *
* @param arm The arm to swing * @param arm The arm to swing
*/ */
protected void swingArm(ModelPart arm) { protected void swingArm(T state, ModelPart arm) {
float swing = 1 - (float)Math.pow(1 - getSwingAmount(), 3); float swing = 1 - (float)Math.pow(1 - state.getSwingAmount(), 3);
float deltaX = MathHelper.sin(swing * MathHelper.PI); float deltaX = MathHelper.sin(swing * MathHelper.PI);
float deltaZ = MathHelper.sin(getSwingAmount() * MathHelper.PI); float deltaZ = MathHelper.sin(state.getSwingAmount() * MathHelper.PI);
float deltaAim = deltaZ * (0.7F - head.pitch) * 0.75F; float deltaAim = deltaZ * (0.7F - head.pitch) * 0.75F;
@ -493,26 +500,26 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* @param animationProgress Total whole and partial ticks since the entity's existence. * @param animationProgress Total whole and partial ticks since the entity's existence.
* Used in animations together with {@code swing} and {@code move}. * Used in animations together with {@code swing} and {@code move}.
*/ */
protected void animateBreathing(float animationProgress) { protected void animateBreathing(T state, float animationProgress, ArmPose left, ArmPose right) {
float cos = MathHelper.cos(animationProgress * 0.09F) * 0.05F + 0.05F; float cos = MathHelper.cos(animationProgress * 0.09F) * 0.05F + 0.05F;
float sin = MathHelper.sin(animationProgress * 0.067F) * 0.05F; float sin = MathHelper.sin(animationProgress * 0.067F) * 0.05F;
if (attributes.shouldLiftArm(rightArmPose, leftArmPose, -1)) { if (state.attributes.shouldLiftArm(right, left, -1)) {
ModelPart arm = getArm(Arm.RIGHT); ModelPart arm = getArm(Arm.RIGHT);
arm.roll += cos; arm.roll += cos;
arm.pitch += sin; arm.pitch += sin;
} }
if (attributes.shouldLiftArm(leftArmPose, rightArmPose, 1)) { if (state.attributes.shouldLiftArm(left, right, 1)) {
ModelPart arm = getArm(Arm.LEFT); ModelPart arm = getArm(Arm.LEFT);
arm.roll += cos; arm.roll += cos;
arm.pitch += sin; arm.pitch += sin;
} }
} }
protected void adjustBody(float pitch, Pivot pivot) { protected void adjustBody(T state, float pitch, Pivot pivot) {
adjustBodyComponents(pitch, pivot); adjustBodyComponents(pitch, pivot);
if (!attributes.isHorsey) { if (!state.attributes.isHorsey) {
neck.setPivot(NECK_X + pitch, pivot.y(), pivot.z()); neck.setPivot(NECK_X + pitch, pivot.y(), pivot.z());
rightLeg.pivotY = FRONT_LEGS_Y; rightLeg.pivotY = FRONT_LEGS_Y;
leftLeg.pivotY = FRONT_LEGS_Y; leftLeg.pivotY = FRONT_LEGS_Y;
@ -528,23 +535,11 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
body.pivotZ = pivot.z(); body.pivotZ = pivot.z();
} }
@Override
public float getRiderYOffset() {
switch ((SizePreset)getSize()) {
case NORMAL: return 0.4F;
case FOAL:
case TALL:
case BULKY:
default: return 0.25F;
}
}
@Override @Override
public void setVisible(boolean visible) { public void setVisible(boolean visible) {
super.setVisible(visible); super.setVisible(visible);
neck.visible = visible; neck.visible = visible;
hat.visible &= !attributes.isHorsey; hat.visible = false;
parts.forEach(part -> part.setVisible(visible, attributes));
} }
@Override @Override
@ -553,15 +548,15 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
positionheldItem(arm, matrices); positionheldItem(arm, matrices);
} }
protected void positionheldItem(Arm arm, MatrixStack matrices) { protected void positionheldItem(T state, Arm arm, MatrixStack matrices) {
float left = arm == Arm.LEFT ? -1 : 1; float left = arm == Arm.LEFT ? -1 : 1;
UseAction action = getAttributes().heldStack.getUseAction(); UseAction action = state.attributes.heldStack.getUseAction();
if (action == UseAction.SPYGLASS && getAttributes().itemUseTime > 0) { if (action == UseAction.SPYGLASS && state.attributes.itemUseTime > 0) {
Arm main = getAttributes().mainArm; Arm main = state.attributes.mainArm;
if (getAttributes().activeHand == Hand.OFF_HAND) { if (state.attributes.activeHand == Hand.OFF_HAND) {
main = main.getOpposite(); main = main.getOpposite();
} }
if (main == arm) { if (main == arm) {
@ -574,28 +569,28 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
matrices.translate(-left * 0.1F, 0.45F, 0); matrices.translate(-left * 0.1F, 0.45F, 0);
if (getAttributes().heldStack.getUseAction() == UseAction.BLOCK && getAttributes().itemUseTime == 0) { if (state.attributes.heldStack.getUseAction() == UseAction.BLOCK && state.attributes.itemUseTime == 0) {
matrices.translate(left * 0.02F, -0.25F, 0); matrices.translate(left * 0.02F, -0.25F, 0);
} }
} }
@Override @Override
public void transform(BodyPart part, MatrixStack stack) { public void transform(T state, BodyPart part, MatrixStack stack) {
if (attributes.isHorsey) { if (state.attributes.isHorsey) {
stack.translate(0, 0.1F, 0); stack.translate(0, 0.1F, 0);
} }
if (attributes.isSleeping || attributes.isRiptide) { if (state.attributes.isSleeping || state.attributes.isRiptide) {
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180)); stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180));
} }
if (attributes.isLyingDown && !attributes.isSleeping) { if (state.attributes.isLyingDown && !state.attributes.isSleeping) {
stack.translate(0, 1.35F, 0); stack.translate(0, 1.35F, 0);
} }
if (attributes.isHorsey) { if (state.attributes.isHorsey) {
if (part == BodyPart.BODY) { if (part == BodyPart.BODY) {
stack.scale(1.5F, 1, 1.5F); stack.scale(1.5F, 1, 1.5F);
} }
@ -605,6 +600,6 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
neck.hidden = !head.visible; neck.hidden = !head.visible;
} }
PonyTransformation.forSize(getSize()).transform(this, part, stack); PonyTransformation.forSize(state.getSize()).transform(this, part, stack);
} }
} }

View file

@ -2,19 +2,13 @@ package com.minelittlepony.client.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.entity.LivingEntity; import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.mson.api.MsonModel;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.mson.api.model.biped.MsonPlayer;
/** /**
* The raw pony model without any implementations. * The raw pony model without any implementations.
@ -23,75 +17,18 @@ import com.minelittlepony.mson.api.model.biped.MsonPlayer;
* *
* Modders can extend this class to make their own pony models if they wish. * Modders can extend this class to make their own pony models if they wish.
*/ */
public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer<T> implements PonyModel<T> { public abstract class ClientPonyModel<T extends PonyRenderState> extends PlayerEntityModel implements MsonModel, PonyModel<T> {
/**
* The model attributes.
*/
protected ModelAttributes attributes = new ModelAttributes();
@Nullable @Nullable
protected PosingCallback<T> onSetModelAngles; protected PosingCallback<T> onSetModelAngles;
public ClientPonyModel(ModelPart tree) { public ClientPonyModel(ModelPart tree, boolean smallArms) {
super(tree); super(tree, smallArms);
} }
public void onSetModelAngles(PosingCallback<T> callback) { public void onSetModelAngles(PosingCallback<T> callback) {
onSetModelAngles = callback; onSetModelAngles = callback;
} }
protected Arm getPreferredArm(T livingEntity) {
Arm arm = livingEntity.getMainArm();
return livingEntity.preferredHand == Hand.MAIN_HAND ? arm : arm.getOpposite();
}
@Override
public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
child = entity.isBaby();
attributes.updateLivingState(entity, pony, mode);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, mode);
sneaking = attributes.isCrouching && !attributes.isLyingDown;
riding = attributes.isSitting;
}
@Override
public final void copyAttributes(BipedEntityModel<T> other) {
copyStateTo(other);
}
/**
* Copies this model's attributes into the passed model.
*/
@Override
public void copyStateTo(EntityModel<T> model) {
super.copyStateTo(model);
if (model instanceof ClientPonyModel) {
((ClientPonyModel<T>)model).attributes = attributes;
}
}
@Override
public final ModelAttributes getAttributes() {
return attributes;
}
@Override
public Size getSize() {
return child ? SizePreset.FOAL : PonyModel.super.getSize();
}
@Override
public void setMetadata(PonyData meta) {
attributes.metadata = meta;
}
@Override
public float getSwingAmount() {
return handSwingProgress;
}
@Override @Override
public ModelPart getForeLeg(Arm side) { public ModelPart getForeLeg(Arm side) {
return getArm(side); return getArm(side);
@ -103,8 +40,8 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
} }
@Override @Override
public ArmPose getArmPoseForSide(Arm side) { public <S extends PlayerEntityRenderState> ArmPose getArmPoseForSide(S state, Arm side) {
return side == Arm.RIGHT ? rightArmPose : leftArmPose; return getArmPose(state, side);
} }
@Override @Override
@ -113,7 +50,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
} }
static void resetPivot(ModelPart part) { static void resetPivot(ModelPart part) {
part.setPivot(part.getDefaultTransform().pivotX, part.getDefaultTransform().pivotY, part.getDefaultTransform().pivotZ); part.setPivot(part.getDefaultTransform().pivotX(), part.getDefaultTransform().pivotY(), part.getDefaultTransform().pivotZ());
} }
static void resetPivot(ModelPart...parts) { static void resetPivot(ModelPart...parts) {
@ -122,7 +59,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
} }
} }
public interface PosingCallback<T extends LivingEntity> { public interface PosingCallback<S extends PonyRenderState> {
void poseModel(ClientPonyModel<T> model, float move, float swing, float ticks, T entity); void poseModel(ClientPonyModel<S> model, S state);
} }
} }

View file

@ -39,7 +39,7 @@ public final class ModelType {
public static final ModelKey<PiglinPonyModel> PIGLIN = register("piglin", PiglinPonyModel::new); public static final ModelKey<PiglinPonyModel> PIGLIN = register("piglin", PiglinPonyModel::new);
public static final ModelKey<SkeleponyModel<?>> SKELETON = register("skeleton", SkeleponyModel::new); public static final ModelKey<SkeleponyModel<?>> SKELETON = register("skeleton", SkeleponyModel::new);
public static final ModelKey<SkeleponyModel<?>> SKELETON_CLOTHES = register("skeleton_clothes", SkeleponyModel::new); public static final ModelKey<SkeleponyModel<?>> SKELETON_CLOTHES = register("skeleton_clothes", SkeleponyModel::new);
public static final ModelKey<PillagerPonyModel<?>> PILLAGER = register("pillager", PillagerPonyModel::new); public static final ModelKey<PillagerPonyModel> PILLAGER = register("pillager", PillagerPonyModel::new);
public static final ModelKey<IllagerPonyModel<?>> ILLAGER = register("illager", IllagerPonyModel::new); public static final ModelKey<IllagerPonyModel<?>> ILLAGER = register("illager", IllagerPonyModel::new);
public static final ModelKey<GuardianPonyModel> GUARDIAN = register("guardian", GuardianPonyModel::new); public static final ModelKey<GuardianPonyModel> GUARDIAN = register("guardian", GuardianPonyModel::new);
public static final ModelKey<EnderStallionModel> ENDERMAN = register("enderman", EnderStallionModel::new); public static final ModelKey<EnderStallionModel> ENDERMAN = register("enderman", EnderStallionModel::new);

View file

@ -2,13 +2,14 @@ package com.minelittlepony.client.model.armour;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T> { public class PonyArmourModel<T extends BipedEntityRenderState> extends AbstractPonyModel<T> {
public PonyArmourModel(ModelPart tree) { public PonyArmourModel(ModelPart tree) {
super(tree); super(tree);

View file

@ -2,24 +2,18 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.entity.LivingEntity; import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.entity.EntityPose;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.google.common.collect.ImmutableList; public class BreezieModel<T extends BipedEntityRenderState> extends BipedEntityModel<T> {
import com.google.common.collect.Iterables;
public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
private ModelPart neck;
private ModelPart leftWing; private ModelPart leftWing;
private ModelPart rightWing; private ModelPart rightWing;
public BreezieModel(ModelPart tree) { public BreezieModel(ModelPart tree) {
super(tree); super(tree);
neck = tree.getChild("neck");
leftWing = tree.getChild("left_wing"); leftWing = tree.getChild("left_wing");
rightWing = tree.getChild("right_wing"); rightWing = tree.getChild("right_wing");
} }
@ -31,15 +25,13 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
} }
@Override @Override
protected Iterable<ModelPart> getBodyParts() { public void setAngles(T state) {
return Iterables.concat(super.getBodyParts(), ImmutableList.of(neck, leftWing, rightWing));
}
@Override float move = state.limbFrequency;
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) { float swing = state.limbAmplitudeMultiplier;
head.yaw = headYaw * 0.017453292F; head.yaw = state.yawDegrees * 0.017453292F;
head.pitch = headPitch * 0.017453292F; head.pitch = state.pitch * 0.017453292F;
hat.copyTransform(head); hat.copyTransform(head);
@ -50,7 +42,7 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
leftLeg .setAngles(swing * MathHelper.cos(move * 0.6662F + MathHelper.PI) * 1.4F, 0, 0); leftLeg .setAngles(swing * MathHelper.cos(move * 0.6662F + MathHelper.PI) * 1.4F, 0, 0);
rightLeg.setAngles(swing * MathHelper.cos(move * 0.6662F) * 1.4F, 0, 0); rightLeg.setAngles(swing * MathHelper.cos(move * 0.6662F) * 1.4F, 0, 0);
if (riding) { if (state.isInPose(EntityPose.SITTING)) {
leftArm.pitch += -MathHelper.PI / 5; leftArm.pitch += -MathHelper.PI / 5;
rightArm.pitch += -MathHelper.PI / 5; rightArm.pitch += -MathHelper.PI / 5;
@ -58,15 +50,18 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
rotateLegRiding(rightLeg, 1); rotateLegRiding(rightLeg, 1);
} }
rotateArm(leftArm, leftArmPose, 1); ArmPose left = getArmPose(state, Arm.LEFT);
rotateArm(rightArm, rightArmPose, 1); ArmPose right = getArmPose(state, Arm.RIGHT);
if (handSwingProgress > 0) { rotateArm(leftArm, left, 1);
swingArms(getPreferredArm(entity)); rotateArm(rightArm, right, 1);
if (state.handSwingProgress > 0) {
swingArms(state, state.preferredArm);
} }
float rotX = MathHelper.sin(ticks * 0.067F) * 0.05F; float rotX = MathHelper.sin(state.age * 0.067F) * 0.05F;
float rotZ = MathHelper.cos(ticks * 0.09F) * 0.05F + 0.05F; float rotZ = MathHelper.cos(state.age * 0.09F) * 0.05F + 0.05F;
leftArm.pitch -= rotX; leftArm.pitch -= rotX;
leftArm.roll -= rotZ; leftArm.roll -= rotZ;
@ -74,8 +69,8 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
rightArm.pitch += rotX; rightArm.pitch += rotX;
rightArm.roll += rotZ; rightArm.roll += rotZ;
rotX = MathHelper.sin(ticks * 0.3F) * 0.05F; rotX = MathHelper.sin(state.age * 0.3F) * 0.05F;
rotZ = MathHelper.cos(ticks * 0.2F) * 0.05F + 0.05F; rotZ = MathHelper.cos(state.age * 0.2F) * 0.05F + 0.05F;
rotX -= 0.05F; rotX -= 0.05F;
@ -84,25 +79,19 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
rightWing.yaw = -rotX * 10; rightWing.yaw = -rotX * 10;
rightWing.pitch = rotZ; rightWing.pitch = rotZ;
if (rightArmPose == ArmPose.BOW_AND_ARROW) { if (right == ArmPose.BOW_AND_ARROW) {
raiseArm(rightArm, leftArm, -1); raiseArm(rightArm, leftArm, -1);
} else if (leftArmPose == ArmPose.BOW_AND_ARROW) { } else if (left == ArmPose.BOW_AND_ARROW) {
raiseArm(leftArm, rightArm, 1); raiseArm(leftArm, rightArm, 1);
} }
} }
private Arm getPreferredArm(T livingEntity) {
Arm arm = livingEntity.getMainArm();
return livingEntity.preferredHand == Hand.MAIN_HAND ? arm : arm.getOpposite();
}
protected void rotateLegRiding(ModelPart leg, float factor) { protected void rotateLegRiding(ModelPart leg, float factor) {
leg.setAngles(-1.4137167F, factor * MathHelper.PI / 10, factor * 0.07853982F); leg.setAngles(-1.4137167F, factor * MathHelper.PI / 10, factor * 0.07853982F);
} }
protected void swingArms(Arm mainHand) { protected void swingArms(T state, Arm mainHand) {
body.yaw = MathHelper.sin(MathHelper.sqrt(handSwingProgress) * MathHelper.TAU) / 5; body.yaw = MathHelper.sin(MathHelper.sqrt(state.handSwingProgress) * MathHelper.TAU) / 5;
if (mainHand == Arm.LEFT) { if (mainHand == Arm.LEFT) {
body.yaw *= -1; body.yaw *= -1;
@ -120,15 +109,15 @@ public class BreezieModel<T extends LivingEntity> extends BipedEntityModel<T> {
rightArm.pivotX = -cos; rightArm.pivotX = -cos;
rightArm.pivotZ = sin; rightArm.pivotZ = sin;
float swingAmount = 1 - (float)Math.pow(1 - handSwingProgress, 4); float swingAmount = 1 - (float)Math.pow(1 - state.handSwingProgress, 4);
float swingFactorX = MathHelper.sin(swingAmount * MathHelper.PI); float swingFactorX = MathHelper.sin(swingAmount * MathHelper.PI);
float swingX = MathHelper.sin(handSwingProgress * MathHelper.PI) * (0.7F - head.pitch) * 0.75F; float swingX = MathHelper.sin(state.handSwingProgress * MathHelper.PI) * (0.7F - head.pitch) * 0.75F;
ModelPart mainArm = getArm(mainHand); ModelPart mainArm = getArm(mainHand);
mainArm.pitch -= swingFactorX * 1.2F + swingX; mainArm.pitch -= swingFactorX * 1.2F + swingX;
mainArm.yaw += body.yaw * 2; mainArm.yaw += body.yaw * 2;
mainArm.roll -= MathHelper.sin(handSwingProgress * MathHelper.PI) * 0.4F; mainArm.roll -= MathHelper.sin(state.handSwingProgress * MathHelper.PI) * 0.4F;
} }
protected void rotateArm(ModelPart arm, ArmPose pose, float factor) { protected void rotateArm(ModelPart arm, ArmPose pose, float factor) {

View file

@ -3,18 +3,11 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.EndermanEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.client.render.entity.EnderStallionRenderer;
public class EnderStallionModel extends SkeleponyModel<EndermanEntity> { public class EnderStallionModel extends SkeleponyModel<EnderStallionRenderer.State> {
public boolean isCarrying;
public boolean isAttacking;
public boolean isAlicorn;
public boolean isBoss;
private final ModelPart leftHorn; private final ModelPart leftHorn;
private final ModelPart rightHorn; private final ModelPart rightHorn;
@ -26,23 +19,19 @@ public class EnderStallionModel extends SkeleponyModel<EndermanEntity> {
} }
@Override @Override
public void animateModel(EndermanEntity entity, float move, float swing, float ticks) { protected void setModelVisibilities(EnderStallionRenderer.State state) {
rightArmPose = isCarrying ? ArmPose.BLOCK : ArmPose.EMPTY; super.setModelVisibilities(state);
leftArmPose = rightArmPose; tail.setVisible(false, state.attributes);
snout.setVisible(false, state.attributes);
isUnicorn = true; horn.setVisible(!state.isBoss, state.attributes);
isAlicorn = entity.getUuid().getLeastSignificantBits() % 3 == 0; leftHorn.visible = rightHorn.visible = state.isBoss;
isBoss = !isAlicorn && entity.getUuid().getLeastSignificantBits() % 90 == 0;
leftHorn.visible = rightHorn.visible = isBoss;
horn.setVisible(!isBoss, attributes);
} }
@Override @Override
public void setModelAngles(EndermanEntity entity, float move, float swing, float ticks, float headYaw, float headPitch) { public void setModelAngles(EnderStallionRenderer.State state) {
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch); super.setModelAngles(state);
if (isAttacking) { if (state.isAttacking) {
head.pivotY -= 5; head.pivotY -= 5;
} }
} }
@ -55,24 +44,10 @@ public class EnderStallionModel extends SkeleponyModel<EndermanEntity> {
stack.pop(); stack.pop();
} }
@Override
public Race getRace() {
return isAlicorn ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
}
@Override
public void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) {
arm.pitch = -0.3707964F;
arm.pitch += 0.4F + MathHelper.sin(ticks * 0.067F) / 10;
}
@Override @Override
public void setVisible(boolean visible) { public void setVisible(boolean visible) {
super.setVisible(visible); super.setVisible(visible);
tail.setVisible(false, attributes);
snout.setVisible(false, attributes);
leftSleeve.visible = false; leftSleeve.visible = false;
rightSleeve.visible = false; rightSleeve.visible = false;
@ -81,12 +56,12 @@ public class EnderStallionModel extends SkeleponyModel<EndermanEntity> {
} }
@Override @Override
public boolean wingsAreOpen() { public boolean wingsAreOpen(EnderStallionRenderer.State state) {
return isAttacking; return state.isAttacking;
} }
@Override @Override
public float getWingRotationFactor(float ticks) { public float getWingRotationFactor(EnderStallionRenderer.State state, float ticks) {
return MathHelper.sin(ticks) + WINGS_HALF_SPREAD_ANGLE; return MathHelper.sin(ticks) + WINGS_HALF_SPREAD_ANGLE;
} }
} }

View file

@ -1,18 +1,21 @@
package com.minelittlepony.client.model.entity; package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.entity.mob.AbstractPiglinEntity; import net.minecraft.entity.mob.AbstractPiglinEntity;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.mob.PiglinActivity; import net.minecraft.entity.mob.PiglinActivity;
import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.render.entity.PonyPiglinRenderer;
public class PiglinPonyModel extends ZomponyModel<HostileEntity> { public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
private PiglinActivity activity;
private final ModelPart leftFlap; private final ModelPart leftFlap;
private final ModelPart rightFlap; private final ModelPart rightFlap;
@ -23,24 +26,22 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
} }
@Override @Override
public void updateLivingState(HostileEntity entity, Pony pony, ModelAttributes.Mode mode) { protected ArmPose getArmPose(PlayerEntityRenderState p, Arm arm) {
super.updateLivingState(entity, pony, mode); if (p instanceof PonyPiglinRenderer.State state) {
leftArmPose = ArmPose.EMPTY; return switch (arm) {
rightArmPose = entity.getMainHandStack().isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM; case LEFT -> switch (state.activity) {
case CROSSBOW_HOLD -> ArmPose.CROSSBOW_HOLD;
if (entity instanceof AbstractPiglinEntity) { case CROSSBOW_CHARGE -> ArmPose.CROSSBOW_CHARGE;
activity = ((AbstractPiglinEntity)entity).getActivity(); default -> ArmPose.EMPTY;
};
if (activity == PiglinActivity.CROSSBOW_HOLD) { case RIGHT -> switch (state.activity) {
rightArmPose = ArmPose.CROSSBOW_HOLD; case ADMIRING_ITEM -> ArmPose.ITEM;
} else if (activity == PiglinActivity.CROSSBOW_CHARGE) { default -> ArmPose.EMPTY;
rightArmPose = ArmPose.CROSSBOW_CHARGE; };
} else if (activity == PiglinActivity.ADMIRING_ITEM) { };
leftArmPose = ArmPose.ITEM;
}
} else {
activity = PiglinActivity.DEFAULT;
} }
return super.getArmPose(p, arm);
} }
@Override @Override

View file

@ -1,31 +1,33 @@
package com.minelittlepony.client.model.entity; package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.entity.mob.IllagerEntity; import net.minecraft.entity.mob.IllagerEntity;
import net.minecraft.entity.mob.PillagerEntity;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import com.minelittlepony.client.model.entity.race.ChangelingModel; import com.minelittlepony.client.model.entity.race.ChangelingModel;
import com.minelittlepony.client.render.entity.npc.PillagerRenderer;
public class PillagerPonyModel<T extends PillagerEntity> extends ChangelingModel<T> { public class PillagerPonyModel extends ChangelingModel<PillagerRenderer.State> {
public PillagerPonyModel(ModelPart tree) { public PillagerPonyModel(ModelPart tree) {
super(tree, false); super(tree, false);
} }
@Override @Override
public void animateModel(T entity, float move, float swing, float ticks) { protected BipedEntityModel.ArmPose getArmPose(PlayerEntityRenderState state, Arm arm) {
ArmPose holdingPose = getHoldingPose(entity.getState()); ArmPose holdingPose = getHoldingPose(((PillagerRenderer.State)state).state);
if (holdingPose != ArmPose.EMPTY) { if (holdingPose != ArmPose.EMPTY) {
boolean rightHanded = entity.getMainArm() == Arm.RIGHT; boolean isMain = state.mainArm == Arm.RIGHT;
leftArmPose = rightHanded ? ArmPose.EMPTY : holdingPose; return isMain ? holdingPose : ArmPose.EMPTY;
rightArmPose = rightHanded ? holdingPose : ArmPose.EMPTY;
}
} }
protected ArmPose getHoldingPose(IllagerEntity.State state) { return super.getArmPose(state, arm);
}
static ArmPose getHoldingPose(IllagerEntity.State state) {
switch (state) { switch (state) {
case BOW_AND_ARROW: return ArmPose.BOW_AND_ARROW; case BOW_AND_ARROW: return ArmPose.BOW_AND_ARROW;
case CROSSBOW_CHARGE: return ArmPose.CROSSBOW_CHARGE; case CROSSBOW_CHARGE: return ArmPose.CROSSBOW_CHARGE;

View file

@ -2,43 +2,30 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.ArmorStandEntityModel; import net.minecraft.client.render.entity.model.ArmorStandEntityModel;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.state.ArmorStandEntityRenderState;
import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.util.math.EulerAngle;
import com.minelittlepony.mson.util.PartUtil; import com.minelittlepony.mson.util.PartUtil;
public class PonyArmourStandModel extends ArmorStandEntityModel { public class PonyArmourStandModel extends ArmorStandEntityModel {
private static final EulerAngle DEFAULT_LEFT_LEG_ROTATION = new EulerAngle(-1, 0, -1);
private static final EulerAngle DEFAULT_RIGHT_LEG_ROTATION = new EulerAngle(1, 0, 1);
public PonyArmourStandModel(ModelPart modelPart) { public PonyArmourStandModel(ModelPart modelPart) {
super(modelPart); super(modelPart);
} }
@Override @Override
public void setAngles(ArmorStandEntity entity, float move, float swing, float ticks, float headYaw, float headPitch) { public void setAngles(ArmorStandEntityRenderState state) {
super.setAngles(entity, move, swing, ticks, headYaw, headPitch); super.setAngles(state);
leftArm.visible = true; leftArm.visible = true;
rightArm.visible = true; rightArm.visible = true;
if (entity.getLeftLegRotation().equals(DEFAULT_LEFT_LEG_ROTATION)) { if (state.leftLegRotation.equals(ArmorStandEntity.DEFAULT_LEFT_LEG_ROTATION)) {
PartUtil.copyAngles(leftArm, leftLeg); PartUtil.copyAngles(leftArm, leftLeg);
leftLeg.pitch *= -1; leftLeg.pitch *= -1;
} }
if (entity.getRightLegRotation().equals(DEFAULT_RIGHT_LEG_ROTATION)) { if (state.rightLegRotation.equals(ArmorStandEntity.DEFAULT_RIGHT_LEG_ROTATION)) {
PartUtil.copyAngles(rightArm, rightLeg); PartUtil.copyAngles(rightArm, rightLeg);
rightLeg.pitch *= -1; rightLeg.pitch *= -1;
} }
} }
public void applyAnglesTo(BipedEntityModel<ArmorStandEntity> dest) {
PartUtil.copyAngles(head, dest.head);
PartUtil.copyAngles(hat, dest.hat);
PartUtil.copyAngles(leftLeg, dest.leftLeg);
PartUtil.copyAngles(rightLeg, dest.rightLeg);
PartUtil.copyAngles(leftArm, dest.leftArm);
PartUtil.copyAngles(rightArm, dest.rightArm);
}
} }

View file

@ -1,27 +1,17 @@
package com.minelittlepony.client.model.entity; package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
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.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SaddleModel<T extends LivingEntity> extends EntityModel<T> { public class SaddleModel<T extends LivingEntityRenderState> extends EntityModel<T> {
private ModelPart root;
public SaddleModel(ModelPart tree) { public SaddleModel(ModelPart tree) {
root = tree; super(tree);
} }
@Override @Override
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) { public void setAngles(T entity) {
root.pivotY = 2 - MathHelper.cos(move * 1.5f) * 3.0f * swing; root.pivotY = 2 - MathHelper.cos(entity.limbFrequency * 1.5F) * 3 * entity.limbAmplitudeMultiplier;
}
@Override
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, int color) {
root.render(matrices, vertices, light, overlay, color);
} }
} }

View file

@ -1,86 +1,34 @@
package com.minelittlepony.client.model.entity; package com.minelittlepony.client.model.entity;
import net.minecraft.entity.mob.WitherSkeletonEntity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import com.minelittlepony.api.model.MobPosingHelper;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.entity.race.AlicornModel; import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.entity.state.SkeletonPonyRenderState;
public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> { public class SkeleponyModel<T extends SkeletonPonyRenderState> extends AlicornModel<T> {
public boolean isUnicorn;
public boolean isWithered;
public SkeleponyModel(ModelPart tree) { public SkeleponyModel(ModelPart tree) {
super(tree, false); super(tree, false);
this.vestRenderList.clear(); vestRenderList.clear();
this.sleevesRenderList.clear(); sleevesRenderList.clear();
} }
@SuppressWarnings("unchecked")
@Override @Override
public void animateModel(T entity, float move, float swing, float ticks) { protected BipedEntityModel.ArmPose getArmPose(PlayerEntityRenderState state, Arm arm) {
isUnicorn = entity.getUuid().getLeastSignificantBits() % 3 != 0; boolean isMain = arm == state.mainArm;
isWithered = entity instanceof WitherSkeletonEntity;
rightArmPose = ArmPose.EMPTY;
leftArmPose = ArmPose.EMPTY;
ItemStack mainHand = entity.getStackInHand(Hand.MAIN_HAND);
ItemStack offHand = entity.getStackInHand(Hand.OFF_HAND);
boolean right = entity.getMainArm() == Arm.RIGHT;
if (!offHand.isEmpty()) {
if (right) {
leftArmPose = ArmPose.ITEM;
} else {
rightArmPose = ArmPose.ITEM;
}
}
if (isMain) {
ItemStack mainHand = state.getMainHandStack();
if (!mainHand.isEmpty()) { if (!mainHand.isEmpty()) {
ArmPose pose = mainHand.getItem() == Items.BOW && entity.isAttacking() ? ArmPose.BOW_AND_ARROW : ArmPose.ITEM; return mainHand.getItem() == Items.BOW && ((T)state).isAttacking ? ArmPose.BOW_AND_ARROW : ArmPose.ITEM;
if (right) {
rightArmPose = pose;
} else {
leftArmPose = pose;
}
}
}
@Override
protected void rotateLegs(float move, float swing, float ticks, T entity) {
super.rotateLegs(move, swing, ticks, entity);
if (rightArmPose != ArmPose.EMPTY && entity.isAttacking()) {
rotateArmHolding(getArm(Arm.RIGHT), -1, getSwingAmount(), ticks);
}
if (leftArmPose != ArmPose.EMPTY && entity.isAttacking()) {
rotateArmHolding(getArm(Arm.LEFT), -1, getSwingAmount(), ticks);
} }
} }
protected void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) { return super.getArmPose(state, arm);
MobPosingHelper.rotateArmHolding(arm, direction, swingProgress, ticks);
}
@Override
public Race getRace() {
return isUnicorn ? super.getRace() : Race.EARTH;
}
@Override
protected float getLegOutset() {
if (attributes.isLyingDown) return 2.6f;
if (attributes.isCrouching) return 0;
return 4;
} }
} }

View file

@ -2,11 +2,12 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.*;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.StriderEntity; import net.minecraft.entity.passive.StriderEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SpikeModel<T extends LivingEntity> extends BipedEntityModel<T> { public class SpikeModel<T extends LivingEntityRenderState> extends BipedEntityModel<T> {
private final ModelPart tail; private final ModelPart tail;
private final ModelPart tail2; private final ModelPart tail2;
@ -20,22 +21,22 @@ public class SpikeModel<T extends LivingEntity> extends BipedEntityModel<T> {
} }
@Override @Override
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) { public void setAngles(T entity) {
swing *= 2; entity.limbFrequency *= 2;
move *= 1.5F; entity.limbAmplitudeMultiplier *= 1.5F;
child = false; entity.baby = false;
head.pivotX = 0; head.pivotX = 0;
head.pivotZ = 0; head.pivotZ = 0;
head.pivotY = 0; head.pivotY = 0;
super.setAngles(entity, move, swing, ticks, headYaw, headPitch); super.setAngles(entity);
leftArm.pivotY++; leftArm.pivotY++;
rightArm.pivotY++; rightArm.pivotY++;
body.pitch += 0.15F; body.pitch += 0.15F;
if ((entity instanceof StriderEntity strider && strider.isSaddled())) { if ((entity instanceof SaddleableRenderState strider && strider.isSaddled())) {
leftArm.pitch = 3.15F; leftArm.pitch = 3.15F;
leftArm.yaw = 1; leftArm.yaw = 1;
rightArm.pitch = 3.15F; rightArm.pitch = 3.15F;
@ -60,8 +61,8 @@ public class SpikeModel<T extends LivingEntity> extends BipedEntityModel<T> {
rightArm.pivotZ += 2; rightArm.pivotZ += 2;
rightArm.pitch -= 0.3F; rightArm.pitch -= 0.3F;
if (entity instanceof StriderEntity strider && strider.isCold()) { if (entity instanceof StriderEntityRenderState strider && strider.cold) {
float armMotion = (float)Math.sin(ticks / 10F) / 10F; float armMotion = (float)Math.sin(entity.age / 10F) / 10F;
leftArm.pitch = -1 - armMotion; leftArm.pitch = -1 - armMotion;
rightArm.pitch = -1 + armMotion; rightArm.pitch = -1 + armMotion;
@ -74,21 +75,15 @@ public class SpikeModel<T extends LivingEntity> extends BipedEntityModel<T> {
} }
} }
tail.pitch = (float)Math.sin(move) / 3F - 0.5F; tail.pitch = (float)Math.sin(entity.limbFrequency) / 3F - 0.5F;
tail2.pitch = -tail.pitch / 2; tail2.pitch = -tail.pitch / 2;
tail3.pitch = tail2.pitch / 2; tail3.pitch = tail2.pitch / 2;
tail.yaw = (float)Math.sin(ticks / 20F) / 40 + (float)Math.sin(move / 20F) / 4; tail.yaw = (float)Math.sin(entity.age / 20F) / 40 + (float)Math.sin(entity.limbFrequency / 20F) / 4;
tail2.yaw = tail.yaw / 2; tail2.yaw = tail.yaw / 2;
tail3.yaw = tail2.yaw / 2; tail3.yaw = tail2.yaw / 2;
for (var part : getHeadParts()) { getRootPart().pivotY += 7;
part.pivotY += 7;
}
for (var part : getBodyParts()) {
part.pivotY += 7;
}
} }
} }

View file

@ -2,39 +2,23 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.WitchEntity;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.model.entity.race.EarthPonyModel; import com.minelittlepony.client.model.entity.race.EarthPonyModel;
import com.minelittlepony.client.render.entity.WitchRenderer;
public class WitchPonyModel extends EarthPonyModel<WitchEntity> { public class WitchPonyModel extends EarthPonyModel<WitchRenderer.State> {
public WitchPonyModel(ModelPart tree) { public WitchPonyModel(ModelPart tree) {
super(tree, false); super(tree, false);
} }
@Override @Override
public void updateLivingState(WitchEntity entity, Pony pony, ModelAttributes.Mode mode) { public void setModelAngles(WitchRenderer.State entity) {
super.updateLivingState(entity, pony, mode); super.setModelAngles(entity);
if (entity.hasCustomName() && "Filly".equals(entity.getCustomName().getString())) { if (entity.drinking) {
child = true;
}
attributes.visualHeight += 0.5F;
leftArmPose = ArmPose.EMPTY;
rightArmPose = entity.getMainHandStack().isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM;
}
@Override
public void setModelAngles(WitchEntity entity, float move, float swing, float ticks, float headYaw, float headPitch) {
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch);
if (entity.isDrinking()) {
float noseRot = MathHelper.sin(entity.age); float noseRot = MathHelper.sin(entity.age);
snout.rotate(noseRot * 4.5F * 0.02F, 0, noseRot * 2.5F * 0.02F); snout.rotate(noseRot * 4.5F * 0.02F, 0, noseRot * 2.5F * 0.02F);
@ -42,12 +26,12 @@ public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
snout.rotate(0, 0, 0); snout.rotate(0, 0, 0);
} }
if (rightArmPose != ArmPose.EMPTY) { if (!entity.getMainHandStack().isEmpty()) {
float rot = (float)(Math.tan(ticks / 7) + Math.sin(ticks / 3)); float rot = (float)(Math.tan(entity.age / 7) + Math.sin(entity.age / 3));
if (rot > 1) rot = 1; if (rot > 1) rot = 1;
if (rot < -1) rot = -1; if (rot < -1) rot = -1;
float legDrinkingAngle = -1 * MathHelper.PI/3 + rot; float legDrinkingAngle = -1 * MathHelper.PI / 3F + rot;
rightArm.pitch = legDrinkingAngle; rightArm.pitch = legDrinkingAngle;
rightArm.yaw = 0.1F; rightArm.yaw = 0.1F;
@ -64,13 +48,8 @@ public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
} }
@Override @Override
protected void positionheldItem(Arm arm, MatrixStack matrices) { protected void positionheldItem(WitchRenderer.State state, Arm arm, MatrixStack matrices) {
super.positionheldItem(arm, matrices); super.positionheldItem(state, arm, matrices);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(10)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(10));
} }
@Override
public boolean isWearing(Wearable wearable) {
return wearable == Wearable.HAT || super.isWearing(wearable);
}
} }

View file

@ -3,12 +3,13 @@ package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.SubModel; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.WingedPonyModel; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public class AlicornModel<T extends LivingEntity> extends UnicornModel<T> implements WingedPonyModel<T> { public class AlicornModel<T extends PonyRenderState> extends UnicornModel<T> implements WingedPonyModel<T> {
private PonyWings<AlicornModel<T>> wings; private PonyWings<AlicornModel<T>> wings;

View file

@ -1,23 +1,25 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class ChangelingModel<T extends LivingEntity> extends AlicornModel<T> { import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class ChangelingModel<T extends PonyRenderState> extends AlicornModel<T> {
public ChangelingModel(ModelPart tree, boolean smallArms) { public ChangelingModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms); super(tree, smallArms);
} }
@Override @Override
public boolean wingsAreOpen() { public boolean wingsAreOpen(ModelAttributes state) {
return (getAttributes().isFlying || getAttributes().isCrouching) && !getAttributes().isGliding; return (state.isFlying || state.isCrouching) && !state.isGliding;
} }
@Override @Override
public float getWingRotationFactor(float ticks) { public float getWingRotationFactor(ModelAttributes state, float ticks) {
if (getAttributes().isFlying) { if (state.isFlying) {
return MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE; return MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE;
} }
return WINGS_RAISED_ANGLE; return WINGS_RAISED_ANGLE;

View file

@ -3,14 +3,12 @@ package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.SubModel; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.part.*; import com.minelittlepony.client.model.part.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
public class EarthPonyModel<T extends LivingEntity> extends AbstractPonyModel<T> { public class EarthPonyModel<T extends PonyRenderState> extends AbstractPonyModel<T> {
private final boolean smallArms;
protected SubModel tail; protected SubModel tail;
protected PonySnout snout; protected PonySnout snout;
@ -21,11 +19,10 @@ public class EarthPonyModel<T extends LivingEntity> extends AbstractPonyModel<T>
private final ModelPart tailStub; private final ModelPart tailStub;
public EarthPonyModel(ModelPart tree, boolean smallArms) { public EarthPonyModel(ModelPart tree, boolean smallArms) {
super(tree); super(tree, smallArms);
mane = neck.getChild("mane"); mane = neck.getChild("mane");
nose = head.getChild("nose"); nose = head.getChild("nose");
tailStub = body.getChild("tail_stub"); tailStub = body.getChild("tail_stub");
this.smallArms = smallArms;
} }
@Override @Override
@ -39,25 +36,18 @@ public class EarthPonyModel<T extends LivingEntity> extends AbstractPonyModel<T>
bodyRenderList.add(forPart(tail)); bodyRenderList.add(forPart(tail));
} }
@Override protected void setModelVisibilities(T state) {
public void setModelAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) { super.setModelVisibilities(state);
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch); mane.visible = state.attributes.isHorsey;
cape.pivotY = sneaking ? 2 : riding ? -4 : 0; nose.visible = state.attributes.isHorsey;
} tailStub.visible = !state.attributes.isHorsey;
@Override
protected float getLegOutset() {
if (smallArms) {
return Math.max(1, super.getLegOutset() - 1);
}
return super.getLegOutset();
} }
@Override @Override
public void setVisible(boolean visible) { public void setVisible(boolean visible) {
super.setVisible(visible); super.setVisible(visible);
mane.visible = attributes.isHorsey; mane.visible = visible;
nose.visible = attributes.isHorsey; nose.visible = visible;
tailStub.visible = !attributes.isHorsey; tailStub.visible = visible;
} }
} }

View file

@ -1,11 +1,11 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.Pivot; import com.minelittlepony.api.model.Pivot;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class KirinModel<T extends LivingEntity> extends UnicornModel<T> { public class KirinModel<T extends PonyRenderState> extends UnicornModel<T> {
private final ModelPart beard; private final ModelPart beard;
@ -15,8 +15,8 @@ public class KirinModel<T extends LivingEntity> extends UnicornModel<T> {
} }
@Override @Override
protected void adjustBody(float pitch, Pivot pivot) { protected void adjustBody(T state, float pitch, Pivot pivot) {
super.adjustBody(pitch, pivot); super.adjustBody(state, pitch, pivot);
beard.resetTransform(); beard.resetTransform();
beard.pitch -= neck.pitch; beard.pitch -= neck.pitch;
} }

View file

@ -3,12 +3,12 @@ package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.SubModel; import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.WingedPonyModel; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
public class PegasusModel<T extends LivingEntity> extends EarthPonyModel<T> implements WingedPonyModel<T> { public class PegasusModel<T extends PonyRenderState> extends EarthPonyModel<T> implements WingedPonyModel<T> {
private PonyWings<PegasusModel<T>> wings; private PonyWings<PegasusModel<T>> wings;

View file

@ -4,13 +4,14 @@ import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> { public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
private static final float FIN_Y_ANGLE = MathHelper.PI / 6; private static final float FIN_Y_ANGLE = MathHelper.PI / 6;
@ -60,12 +61,12 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
protected void ponySit() {} protected void ponySit() {}
@Override @Override
public void setModelAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) { protected void setModelAngles(T entity) {
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch); super.setModelAngles(entity);
float flapMotion = MathHelper.cos(ticks / 10) / 5; float flapMotion = MathHelper.cos(entity.age / 10) / 5;
if (attributes.isLyingDown) { if (entity.attributes.isLyingDown) {
flapMotion /= 2; flapMotion /= 2;
} }
@ -75,20 +76,20 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
rightFin.yaw = -finAngle; rightFin.yaw = -finAngle;
centerFin.roll = flapMotion; centerFin.roll = flapMotion;
if (!entity.isSubmergedInWater()) { if (!entity.submergedInWater) {
leftArm.pitch -= 0.5F; leftArm.pitch -= 0.5F;
rightArm.pitch -= 0.5F; rightArm.pitch -= 0.5F;
} }
if (!entity.isSubmergedInWater() || entity.isOnGround()) { if (!entity.submergedInWater || entity.onGround) {
leftArm.yaw -= 0.5F; leftArm.yaw -= 0.5F;
rightArm.yaw += 0.5F; rightArm.yaw += 0.5F;
} }
} }
@Override @Override
protected void rotateLegs(float move, float swing, float ticks, T entity) { protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(move, swing, ticks, entity); super.rotateLegs(state, move, swing, ticks, entity);
leftArm.pitch -= 1.4F; leftArm.pitch -= 1.4F;
leftArm.yaw -= 0.3F; leftArm.yaw -= 0.3F;
rightArm.pitch -= 1.4F; rightArm.pitch -= 1.4F;
@ -96,8 +97,8 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
} }
@Override @Override
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) { protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(move, swing, ticks, entity); super.rotateLegsOnGround(state, move, swing, ticks, entity);
} }
@Override @Override
@ -114,7 +115,7 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
rightFin.visible = visible; rightFin.visible = visible;
} }
public static class Armour<T extends LivingEntity> extends PonyArmourModel<T> { public static class Armour<T extends PonyRenderState> extends PonyArmourModel<T> {
public Armour(ModelPart tree) { public Armour(ModelPart tree) {
super(tree); super(tree);
@ -131,14 +132,13 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
} }
@Override @Override
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) { protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(move, swing, ticks, entity); super.rotateLegsOnGround(state, move, swing, ticks, entity);
} }
@Override @Override
public void transform(BodyPart part, MatrixStack stack) { public void transform(BodyPart part, MatrixStack stack) {
stack.translate(0, 0.6F, 0); stack.translate(0, 0.6F, 0);
super.transform(part, stack); super.transform(part, stack);
} }
} }

View file

@ -5,19 +5,21 @@ import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.SizePreset; import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.model.part.UnicornHorn; import com.minelittlepony.client.model.part.UnicornHorn;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.util.RenderList; import com.minelittlepony.mson.util.RenderList;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.consume.UseAction;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.util.*; import net.minecraft.util.*;
/** /**
* Used for both unicorns and alicorns since there's no logical way to keep them distinct and not duplicate stuff. * Used for both unicorns and alicorns since there's no logical way to keep them distinct and not duplicate stuff.
*/ */
public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> implements HornedPonyModel<T> { public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> implements HornedPonyModel<T> {
protected final ModelPart unicornArmRight; protected final ModelPart unicornArmRight;
protected final ModelPart unicornArmLeft; protected final ModelPart unicornArmLeft;
@ -34,20 +36,20 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
public void init(ModelView context) { public void init(ModelView context) {
super.init(context); super.init(context);
horn = addPart(context.findByName("horn")); horn = addPart(context.findByName("horn"));
headRenderList.add(RenderList.of().add(head::rotate).add(forPart(horn)).checked(() -> getRace().hasHorn())); headRenderList.add(RenderList.of().add(head::rotate).add(forPart(horn)).checked(() -> currentState.getRace().hasHorn()));
this.mainRenderList.add(withStage(BodyPart.HEAD, RenderList.of().add(head::rotate).add((stack, vertices, overlay, light, color) -> { this.mainRenderList.add(withStage(BodyPart.HEAD, RenderList.of().add(head::rotate).add((stack, vertices, overlay, light, color) -> {
horn.renderMagic(stack, vertices, getAttributes().metadata.glowColor()); horn.renderMagic(stack, vertices, currentState.attributes.metadata.glowColor());
})).checked(() -> hasMagic() && isCasting())); })).checked(() -> hasMagic(currentState) && isCasting(currentState)));
} }
@Override @Override
public float getWobbleAmount() { public float getWobbleAmount() {
return isCasting() ? 0 : super.getWobbleAmount(); return isCasting(currentState) ? 0 : super.getWobbleAmount();
} }
@Override @Override
protected void rotateLegs(float move, float swing, float ticks, T entity) { protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(move, swing, ticks, entity); super.rotateLegs(state, move, swing, ticks, entity);
unicornArmRight.setAngles(0, 0, 0); unicornArmRight.setAngles(0, 0, 0);
unicornArmRight.setPivot(-7, 12, -2); unicornArmRight.setPivot(-7, 12, -2);
@ -57,31 +59,30 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
} }
@Override @Override
public boolean isCasting() { public boolean isCasting(T state) {
return PonyConfig.getInstance().tpsmagic.get() return PonyConfig.getInstance().tpsmagic.get() && (!state.leftHandStack.isEmpty() || !state.rightHandStack.isEmpty());
&& (rightArmPose != ArmPose.EMPTY || leftArmPose != ArmPose.EMPTY);
} }
@Override @Override
protected void ponyCrouch() { protected void ponyCrouch(T state) {
super.ponyCrouch(); super.ponyCrouch(state);
unicornArmRight.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT; unicornArmRight.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT;
unicornArmLeft.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT; unicornArmLeft.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT;
} }
@Override @Override
public ModelPart getArm(Arm side) { public ModelPart getArm(Arm side) {
if (hasMagic() && getArmPoseForSide(side) != ArmPose.EMPTY && PonyConfig.getInstance().tpsmagic.get()) { if (hasMagic(currentState) && getArmPoseForSide(currentState, side) != ArmPose.EMPTY && PonyConfig.getInstance().tpsmagic.get()) {
return side == Arm.LEFT ? unicornArmLeft : unicornArmRight; return side == Arm.LEFT ? unicornArmLeft : unicornArmRight;
} }
return super.getArm(side); return super.getArm(side);
} }
@Override @Override
protected void positionheldItem(Arm arm, MatrixStack matrices) { protected void positionheldItem(T state, Arm arm, MatrixStack matrices) {
super.positionheldItem(arm, matrices); super.positionheldItem(state, arm, matrices);
if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic()) { if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic(state)) {
return; return;
} }
@ -89,19 +90,19 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
matrices.translate(0.4F - (0.3F * left), -0.675F, -0.3F); matrices.translate(0.4F - (0.3F * left), -0.675F, -0.3F);
UseAction action = getAttributes().heldStack.getUseAction(); UseAction action = state.attributes.heldStack.getUseAction();
boolean shouldAimItem = boolean shouldAimItem =
(action == UseAction.SPYGLASS || action == UseAction.BOW) && getAttributes().itemUseTime > 0 (action == UseAction.SPYGLASS || action == UseAction.BOW) && state.attributes.itemUseTime > 0
|| PonyConfig.getInstance().forwardHoldingItems.get().contains(Registries.ITEM.getId(getAttributes().heldStack.getItem())); || PonyConfig.getInstance().forwardHoldingItems.get().contains(Registries.ITEM.getId(state.attributes.heldStack.getItem()));
if (shouldAimItem) { if (shouldAimItem) {
Arm main = getAttributes().mainArm; Arm main = state.attributes.mainArm;
if (getAttributes().activeHand == Hand.OFF_HAND) { if (state.attributes.activeHand == Hand.OFF_HAND) {
main = main.getOpposite(); main = main.getOpposite();
} }
if (main == arm) { if (main == arm) {
if (action == UseAction.SPYGLASS) { if (action == UseAction.SPYGLASS) {
Size size = getSize(); Size size = state.getSize();
float x = 0.3F; float x = 0.3F;
float z = -0.4F; float z = -0.4F;

View file

@ -6,6 +6,7 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
@ -15,34 +16,32 @@ import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.RenderPass; import com.minelittlepony.api.model.RenderPass;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.PonyBounds; import com.minelittlepony.client.PonyBounds;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public final class DebugBoundingBoxRenderer { public final class DebugBoundingBoxRenderer {
public static <T extends LivingEntity> void render(Pony pony, EntityRenderer<T> renderer, T entity, MatrixStack stack, VertexConsumerProvider renderContext, float tickDelta) { public static <T extends PonyRenderState> void render(T state, MatrixStack stack, VertexConsumerProvider matrices) {
if (RenderPass.getCurrent() != RenderPass.WORLD) { if (RenderPass.getCurrent() != RenderPass.WORLD) {
return; return;
} }
MinecraftClient client = MinecraftClient.getInstance(); MinecraftClient client = MinecraftClient.getInstance();
if (!client.getEntityRenderDispatcher().shouldRenderHitboxes() || entity.isInvisible() || client.hasReducedDebugInfo()) { if (!client.getEntityRenderDispatcher().shouldRenderHitboxes() || state.invisible || client.hasReducedDebugInfo()) {
return; return;
} }
Vec3d offset = renderer.getPositionOffset(entity, tickDelta); Vec3d offset = state.positionOffset;
stack.push(); stack.push();
stack.translate(-offset.x, -offset.y, -offset.z); stack.translate(-offset.x, -offset.y, -offset.z);
Box boundingBox = PonyBounds.getBoundingBox(pony, entity); Box boundingBox = PonyBounds.getBoundingBox(state.pony, state);
Vec3d pos = entity.getPos(); double x = -state.x;
double y = -state.y;
double z = -state.z;
double x = - MathHelper.lerp(tickDelta, entity.lastRenderX, pos.x); VertexConsumer vertices = matrices.getBuffer(RenderLayer.getLines());
double y = - MathHelper.lerp(tickDelta, entity.lastRenderY, pos.y);
double z = - MathHelper.lerp(tickDelta, entity.lastRenderZ, pos.z);
VertexConsumer vertices = renderContext.getBuffer(RenderLayer.getLines());
WorldRenderer.drawBox(stack, vertices, boundingBox.offset(x, y, z), 1, 1, 0, 1); WorldRenderer.drawBox(stack, vertices, boundingBox.offset(x, y, z), 1, 1, 0, 1);
stack.pop(); stack.pop();

View file

@ -7,6 +7,7 @@ import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.client.PonyDataLoader; import com.minelittlepony.client.PonyDataLoader;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.transform.PonyPosture; import com.minelittlepony.client.transform.PonyPosture;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -20,20 +21,26 @@ import net.fabricmc.api.EnvType;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Frustum; import net.minecraft.client.render.Frustum;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> { public class EquineRenderManager<
T extends LivingEntity,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>> {
private Models<T, M> models; private Models<T, M> models;
@Nullable @Nullable
private Function<T, Models<T, M>> modelsLookup; private Function<S, Models<T, M>> modelsLookup;
private final PonyRenderContext<T, M> context; private final PonyRenderContext<T, S, M> context;
private final Transformer<T> transformer; private final Transformer<? super S> transformer;
private final FrustrumCheck<T> frustrum; private final FrustrumCheck<T> frustrum;
@ -41,7 +48,7 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
RenderSystem.disableBlend(); RenderSystem.disableBlend();
} }
public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, Models<T, M> models) { public EquineRenderManager(PonyRenderContext<T, S, M> context, Transformer<? super S> transformer, Models<T, M> models) {
this.context = context; this.context = context;
this.transformer = transformer; this.transformer = transformer;
this.models = models; this.models = models;
@ -50,11 +57,11 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public EquineRenderManager(PonyRenderContext<T, M> context, Transformer<T> transformer, ModelKey<? super M> key) { public EquineRenderManager(PonyRenderContext<T, S, M> context, Transformer<? super S> transformer, ModelKey<? super M> key) {
this(context, transformer, new Models(key)); this(context, transformer, new Models(key));
} }
public void setModelsLookup(@Nullable Function<T, Models<T, M>> modelsLookup) { public void setModelsLookup(@Nullable Function<S, Models<T, M>> modelsLookup) {
this.modelsLookup = modelsLookup; this.modelsLookup = modelsLookup;
} }
@ -73,78 +80,40 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return frustrum.withCamera(entity, vanilla); return frustrum.withCamera(entity, vanilla);
} }
public void preRender(T entity, ModelAttributes.Mode mode) { public void preRender(T entity, S state, ModelAttributes.Mode mode) {
Pony pony = context.getEntityPony(entity); Pony pony = context.getEntityPony(entity);
if (modelsLookup != null) { if (modelsLookup != null) {
models = modelsLookup.apply(entity); models = modelsLookup.apply(state);
context.setModel(models.body()); context.setModel(models.body());
} }
models.applyMetadata(pony.metadata()); models.applyMetadata(pony.metadata());
models.body().updateLivingState(entity, pony, mode); state.updateState(entity, models.body(), pony, mode);
} }
public void setupTransforms(T entity, MatrixStack stack, float animationProgress, float bodyYaw, float tickDelta, float scale) { public void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw) {
float s = getScaleFactor(); float s = state.getScaleFactor();
stack.scale(s, s, s); stack.scale(s, s, s);
if (entity instanceof PlayerEntity) { if (state instanceof PlayerEntityRenderState) {
if (getModels().body().getAttributes().isSitting) { if (state.attributes.isSitting) {
stack.translate(0, 0.125D, 0); stack.translate(0, 0.125D, 0);
} }
} }
bodyYaw = getMountedYaw(entity, bodyYaw, tickDelta); transformer.setupTransforms(state, stack, animationProgress, bodyYaw);
transformer.setupTransforms(entity, stack, animationProgress, bodyYaw, tickDelta, scale);
PonyPosture.of(getModels().body().getAttributes()).apply(entity, getModels().body(), stack, bodyYaw, tickDelta, 1); PonyPosture.of(state.attributes).apply(state, getModels().body(), stack, bodyYaw, state.age, 1);
} }
private float getMountedYaw(T entity, float bodyYaw, float tickDelta) { public interface Transformer<S extends BipedEntityRenderState> {
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity mount) { void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw);
return bodyYaw + MathUtil.interpolateDegress(mount.prevBodyYaw, mount.bodyYaw, tickDelta);
}
return bodyYaw;
}
public float getScaleFactor() {
return getModels().body().getSize().scaleFactor();
}
public float getShadowSize() {
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 += getModels().body().getAttributes().visualHeight * getScaleFactor() + 0.25F;
if (entity.isSneaking()) {
y -= 0.25F;
}
if (entity.hasVehicle()) {
y += entity.getVehicle().getEyeHeight(entity.getPose());
}
if (entity.isSleeping()) {
y /= 2;
}
return y;
}
public interface Transformer<T extends LivingEntity> {
void setupTransforms(T entity, MatrixStack stack, float animationProgress, float bodyYaw, float tickDelta, float scale);
} }
public interface RegistrationHandler { public interface RegistrationHandler {
SyncedPony getSyncedPony(); SyncedPony getSyncedPony();
} }
public interface ModelHolder<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> { public interface ModelHolder<S extends BipedEntityRenderState, M extends EntityModel<S> & PonyModel<S>> {
void setModel(M model); void setModel(M model);
} }

View file

@ -19,9 +19,9 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
private Frustum vanilla; private Frustum vanilla;
private final PonyRenderContext<T, ?> context; private final PonyRenderContext<T, ?, ?> context;
public FrustrumCheck(PonyRenderContext<T, ?> context) { public FrustrumCheck(PonyRenderContext<T, ?, ?> context) {
super(new Matrix4f(), new Matrix4f()); super(new Matrix4f(), new Matrix4f());
this.context = context; this.context = context;
} }

View file

@ -5,8 +5,7 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderPhase; import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.VertexFormats;
import net.minecraft.util.Identifier; import net.minecraft.util.*;
import net.minecraft.util.Util;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
@ -62,7 +61,7 @@ public abstract class MagicGlow extends RenderPhase {
private final float alpha; private final float alpha;
public Colored(Identifier texture, int color) { public Colored(Identifier texture, int color) {
super(texture, false, false); super(texture, TriState.FALSE, false);
this.red = Color.r(color); this.red = Color.r(color);
this.green = Color.g(color); this.green = Color.g(color);
this.blue = Color.b(color); this.blue = Color.b(color);

View file

@ -3,15 +3,20 @@ package com.minelittlepony.client.render;
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.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
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,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends Gear.Context<S, M> {
Pony getEntityPony(T entity); Pony getEntityPony(T entity);
EquineRenderManager<T, M> getInternalRenderer(); EquineRenderManager<T, S, M> getInternalRenderer();
void setModel(M model); void setModel(M model);
} }

View file

@ -8,6 +8,7 @@ import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.mixin.MixinEntityRenderers; import com.minelittlepony.client.mixin.MixinEntityRenderers;
import com.minelittlepony.client.render.entity.*; import com.minelittlepony.client.render.entity.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -16,6 +17,7 @@ import com.minelittlepony.mson.api.Mson;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.entity.*; import net.minecraft.client.render.entity.*;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.client.util.SkinTextures; import net.minecraft.client.util.SkinTextures;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@ -69,7 +71,7 @@ public class PonyRenderDispatcher {
* @param factory The replacement value * @param factory The replacement value
* @param <T> The entity type * @param <T> The entity type
*/ */
<T extends Entity, V extends T> void switchRenderer(MobRenderers state, EntityType<V> type, Function<EntityRendererFactory.Context, EntityRenderer<T>> factory) { <T extends Entity, S extends EntityRenderState, V extends T> void switchRenderer(MobRenderers state, EntityType<V> type, Function<EntityRendererFactory.Context, EntityRenderer<T, S>> factory) {
Mson.getInstance().getEntityRendererRegistry().registerEntityRenderer(type, ctx -> state.get() Mson.getInstance().getEntityRendererRegistry().registerEntityRenderer(type, ctx -> state.get()
? factory.apply(ctx) ? factory.apply(ctx)
: MixinEntityRenderers.getRendererFactories().get(type).create(ctx) : MixinEntityRenderers.getRendererFactories().get(type).create(ctx)
@ -78,7 +80,7 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> PonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) { public <T extends LivingEntity, S extends PonyRenderState, M extends EntityModel<S> & PonyModel<S>> PonyRenderContext<T, S, M> getPonyRenderer(@Nullable T entity) {
if (entity != null && MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity) instanceof PonyRenderContext c) { if (entity != null && MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity) instanceof PonyRenderContext c) {
return c; return c;
} }

View file

@ -10,11 +10,11 @@ import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.EquineRenderManager; import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.client.render.entity.feature.*; import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.*;
import java.util.function.Function;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Frustum; import net.minecraft.client.render.Frustum;
@ -23,29 +23,41 @@ import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.MobEntityRenderer; import net.minecraft.client.render.entity.MobEntityRenderer;
import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRenderer;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; 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,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends MobEntityRenderer<T, S, M> implements PonyRenderContext<T, S, M> {
protected final EquineRenderManager<T, M> manager; protected final EquineRenderManager<T, S, M> manager;
private final Map<Wearable, Identifier> wearableTextures = new EnumMap<>(Wearable.class); private final Map<Wearable, Identifier> wearableTextures = new EnumMap<>(Wearable.class);
private final TextureSupplier<T> texture; private final TextureSupplier<S> texture;
private final float scale; private final float scale;
public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) { public AbstractPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<S> texture, float scale) {
super(context, null, 0.5F); super(context, null, 0.5F);
this.manager = new EquineRenderManager<>(this, super::setupTransforms, key); this.manager = new EquineRenderManager<T, S, M>(this, super::setupTransforms, key);
this.texture = texture; this.texture = texture;
this.scale = scale; this.scale = scale;
addFeatures(context); addFeatures(context);
} }
@Override
public void updateRenderState(T entity, S state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
manager.preRender(entity, state, ModelAttributes.Mode.THIRD_PERSON);
}
protected void addFeatures(EntityRendererFactory.Context context) { protected void addFeatures(EntityRendererFactory.Context context) {
addFeature(new ArmourFeature<>(this, context.getModelManager())); addFeature(new ArmourFeature<>(this, context.getModelManager()));
addFeature(createHeldItemFeature(context)); addFeature(createHeldItemFeature(context));
@ -54,47 +66,48 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
addFeature(new GearFeature<>(this)); addFeature(new GearFeature<>(this));
} }
protected HeldItemFeature<T, M> createHeldItemFeature(EntityRendererFactory.Context context) { @SuppressWarnings({"unchecked", "rawtypes"})
return new HeldItemFeature<>(this, context.getHeldItemRenderer()); protected final boolean addPonyFeature(FeatureRenderer<? extends PlayerEntityRenderState, ? extends ClientPonyModel<? extends PlayerEntityRenderState>> feature) {
return ((List)features).add(feature);
}
protected HeldItemFeature createHeldItemFeature(EntityRendererFactory.Context context) {
return new HeldItemFeature(this, context.getItemRenderer());
} }
@Override @Override
public final Identifier getTexture(T entity) { public final Identifier getTexture(S entity) {
return texture.apply(entity); return texture.apply(entity);
} }
@Override @Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(S state, MatrixStack stack, VertexConsumerProvider vertices, int light) {
manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON); super.render(state, stack, vertices, light);
if (manager.getModels().body() instanceof BipedEntityModel model) { DebugBoundingBoxRenderer.render(getEntityPony(state), this, state, stack, vertices);
model.setVisible(true);
}
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
} }
@Override @Override
protected void setupTransforms(T entity, MatrixStack stack, float animationProgress, float bodyYaw, float tickDelta, float scale) { protected void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw) {
manager.setupTransforms(entity, stack, animationProgress, bodyYaw, tickDelta, scale); manager.setupTransforms(state, stack, animationProgress, bodyYaw);
} }
@Override @Override
public boolean shouldRender(T entity, Frustum visibleRegion, double camX, double camY, double camZ) { public boolean shouldRender(T state, Frustum visibleRegion, double camX, double camY, double camZ) {
return super.shouldRender(entity, manager.getFrustrum(entity, visibleRegion), camX, camY, camZ); return super.shouldRender(state, manager.getFrustrum(state, visibleRegion), camX, camY, camZ);
} }
@Override @Override
public void scale(T entity, MatrixStack stack, float tickDelta) { public void scale(S state, MatrixStack stack) {
shadowRadius = manager.getShadowSize(); shadowRadius = state.getShadowSize();
if (entity.isBaby()) { if (state.baby) {
shadowRadius *= 3; // undo vanilla shadow scaling shadowRadius *= 3; // undo vanilla shadow scaling
} }
if (!entity.hasVehicle()) { if (!state.hasVehicle) {
stack.translate(0, 0, -entity.getWidth() / 2); // move us to the center of the shadow stack.translate(0, 0, -state.width / 2); // move us to the center of the shadow
} else { } else {
if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) { if (state.attributes.isSitting && state.hasVehicle) {
stack.translate(0, 0.25F, 0); stack.translate(0, 0.25F, 0);
} }
} }
@ -103,17 +116,17 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
} }
@Override @Override
protected void renderLabelIfPresent(T entity, Text name, MatrixStack matrices, VertexConsumerProvider vertices, int light, float tickDelta) { protected void renderLabelIfPresent(S state, Text name, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
matrices.push(); matrices.push();
matrices.translate(0, manager.getNamePlateYOffset(entity), 0); matrices.translate(0, state.nameplateYOffset, 0);
super.renderLabelIfPresent(entity, name, matrices, vertices, light, tickDelta); super.renderLabelIfPresent(state, name, matrices, vertices, light);
matrices.pop(); matrices.pop();
} }
@Override @Override
public Identifier getDefaultTexture(T entity, Wearable wearable) { public Identifier getDefaultTexture(S state, Wearable wearable) {
return wearableTextures.computeIfAbsent(wearable, w -> { return wearableTextures.computeIfAbsent(wearable, w -> {
Identifier texture = getTexture(entity).withPath(path -> path.split("\\.")[0] + "_" + wearable.name().toLowerCase(Locale.ROOT) + ".png"); Identifier texture = getTexture(state).withPath(path -> path.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;
@ -128,7 +141,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
} }
@Override @Override
public EquineRenderManager<T, M> getInternalRenderer() { public EquineRenderManager<T, S, M> getInternalRenderer() {
return manager; return manager;
} }
@ -137,25 +150,39 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
return Pony.getManager().getPony(getTexture(entity)); return Pony.getManager().getPony(getTexture(entity));
} }
public static <E extends MobEntity, M extends ClientPonyModel<E>, T extends PonyRenderer<E, M>, F extends FeatureRenderer<E, M>> public static <E extends MobEntity, C extends PonyRenderState, M extends ClientPonyModel<C>, T extends PonyRenderer<E, C, M>, F extends FeatureRenderer<C, M>>
T appendFeature(T renderer, Function<T, F> featureFactory) { T appendFeature(T renderer, Function<T, F> featureFactory) {
renderer.addFeature(featureFactory.apply(renderer)); renderer.addFeature(featureFactory.apply(renderer));
return renderer; return renderer;
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public static <T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> AbstractPonyRenderer<T, M> proxy(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale, public static <
List exportedLayers, Consumer<M> modelConsumer) { T extends MobEntity,
var renderer = new AbstractPonyRenderer<T, M>(context, key, texture, scale) { S extends PonyRenderState,
M extends EntityModel<S> & PonyModel<S>> AbstractPonyRenderer<T, S, M> proxy(
EntityRendererFactory.Context context, ModelKey<? super M> key,
TextureSupplier<S> texture,
float scale,
List exportedLayers,
Consumer<M> modelConsumer,
Supplier<S> renderStateSupplier) {
return new AbstractPonyRenderer<T, S, M>(context, key, texture, scale) {
{
exportedLayers.clear();
exportedLayers.addAll(features);
modelConsumer.accept(getModel());
}
@Override @Override
protected void addFeatures(EntityRendererFactory.Context context) { protected void addFeatures(EntityRendererFactory.Context context) {
features.clear(); features.clear();
super.addFeatures(context); super.addFeatures(context);
} }
@Override
public S createRenderState() {
return renderStateSupplier.get();
}
}; };
exportedLayers.clear();
exportedLayers.addAll(renderer.features);
modelConsumer.accept(renderer.getModel());
return renderer;
} }
} }

View file

@ -1,11 +1,16 @@
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.pony.Pony;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.EnderStallionModel; import com.minelittlepony.client.model.entity.EnderStallionModel;
import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature; import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature;
import com.minelittlepony.client.render.entity.feature.HeldItemFeature; import com.minelittlepony.client.render.entity.feature.HeldItemFeature;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.SkeletonPonyRenderState;
import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature.IGlowingRenderer; import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature.IGlowingRenderer;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -13,13 +18,16 @@ import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.feature.StuckArrowsFeatureRenderer; import net.minecraft.client.render.entity.feature.StuckArrowsFeatureRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.EndermanEntity; import net.minecraft.entity.mob.EndermanEntity;
import net.minecraft.item.ItemStack; import net.minecraft.util.Arm;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Random; import java.util.Random;
public class EnderStallionRenderer extends PonyRenderer<EndermanEntity, EnderStallionModel> implements IGlowingRenderer { public class EnderStallionRenderer extends PonyRenderer<EndermanEntity, EnderStallionRenderer.State, EnderStallionModel> implements IGlowingRenderer {
public static final Identifier ENDERMAN = MineLittlePony.id("textures/entity/enderman/enderman_pony.png"); public static final Identifier ENDERMAN = MineLittlePony.id("textures/entity/enderman/enderman_pony.png");
private static final Identifier EYES = MineLittlePony.id("textures/entity/enderman/enderman_pony_eyes.png"); private static final Identifier EYES = MineLittlePony.id("textures/entity/enderman/enderman_pony_eyes.png");
@ -29,42 +37,67 @@ public class EnderStallionRenderer extends PonyRenderer<EndermanEntity, EnderSta
super(context, ModelType.ENDERMAN, TextureSupplier.of(ENDERMAN)); super(context, ModelType.ENDERMAN, TextureSupplier.of(ENDERMAN));
} }
@Override
public State createRenderState() {
return new State();
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override @Override
protected void addFeatures(EntityRendererFactory.Context context) { protected void addFeatures(EntityRendererFactory.Context context) {
addFeature(createHeldItemFeature(context)); addPonyFeature(createHeldItemFeature(context));
addFeature(new StuckArrowsFeatureRenderer<>(context, this)); addPonyFeature(new StuckArrowsFeatureRenderer<EnderStallionModel>((PonyRenderer)this, context));
addFeature(new GlowingEyesFeature<>(this)); addPonyFeature(new GlowingEyesFeature<EnderStallionRenderer.State, EnderStallionModel>(this));
} }
@Override @Override
protected HeldItemFeature<EndermanEntity, EnderStallionModel> createHeldItemFeature(EntityRendererFactory.Context context) { protected HeldItemFeature<State, EnderStallionModel> createHeldItemFeature(EntityRendererFactory.Context context) {
return new HeldItemFeature<EndermanEntity, EnderStallionModel>(this, context.getHeldItemRenderer()) { return new HeldItemFeature<State, EnderStallionModel>(this, context.getItemRenderer());
@Override
protected ItemStack getRightItem(EndermanEntity entity) {
BlockState state = entity.getCarriedBlock();
if (state == null) {
return ItemStack.EMPTY;
}
return new ItemStack(state.getBlock().asItem());
}
};
} }
@Override @Override
public void render(EndermanEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(State entity, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
model.isCarrying = entity.getCarriedBlock() != null; if (entity.angry) {
model.isAttacking = entity.isAngry(); matrices.translate(rnd.nextGaussian() / 50, 0, rnd.nextGaussian() / 50);
if (entity.isAngry()) {
stack.translate(rnd.nextGaussian() / 50, 0, rnd.nextGaussian() / 50);
} }
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); super.render(entity, matrices, vertices, light);
} }
@Override @Override
public Identifier getEyeTexture() { public Identifier getEyeTexture() {
return EYES; return EYES;
} }
public class State extends SkeletonPonyRenderState {
public boolean angry;
@Nullable
public BlockState carriedBlock;
public boolean isAlicorn;
public boolean isBoss;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
isUnicorn = true;
isAlicorn = entity.getUuid().getLeastSignificantBits() % 3 == 0;
isBoss = !isAlicorn && entity.getUuid().getLeastSignificantBits() % 90 == 0;
angry = ((EndermanEntity)entity).isAngry();
carriedBlock = ((EndermanEntity)entity).getCarriedBlock();
if (carriedBlock != null) {
if (mainArm == Arm.RIGHT) {
rightHandStack = carriedBlock.getBlock().asItem().getDefaultStack();
} else {
leftHandStack = carriedBlock.getBlock().asItem().getDefaultStack();
}
}
}
@Override
public Race getRace() {
return isAlicorn ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
}
}
} }

View file

@ -10,6 +10,8 @@ import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer; import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.feature.*; import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.render.entity.state.PlayerPonyRenderState;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.common.util.render.RenderLayerUtil; import com.minelittlepony.common.util.render.RenderLayerUtil;
import java.util.*; import java.util.*;
@ -24,19 +26,26 @@ import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.PlayerEntityRenderer; import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.entity.feature.*; import net.minecraft.client.render.entity.feature.*;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityPose;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.*; import net.minecraft.util.*;
import net.minecraft.util.math.Vec3d;
public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> { public class PlayerPonyRenderer
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache; extends PlayerEntityRenderer
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager; implements PonyRenderContext<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> {
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<PlayerPonyRenderState>>> modelsCache;
protected final EquineRenderManager<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> manager;
private ModelAttributes.Mode mode = ModelAttributes.Mode.THIRD_PERSON;
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 = new EquineRenderManager<>(this, super::setupTransforms, modelsCache.apply(Race.EARTH));
manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity, getEntityPony(entity)))); manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity)));
addPonyFeatures(context); addPonyFeatures(context);
} }
@ -53,7 +62,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
|| feature instanceof ShoulderParrotFeatureRenderer; || feature instanceof ShoulderParrotFeatureRenderer;
}); });
addPonyFeature(new ArmourFeature<>(this, context.getModelManager())); addPonyFeature(new ArmourFeature<>(this, context.getModelManager()));
addPonyFeature(new HeldItemFeature(this, context.getHeldItemRenderer())); addPonyFeature(new HeldItemFeature(this, context.getItemRenderer()));
addPonyFeature(new DJPon3Feature<>(this)); addPonyFeature(new DJPon3Feature<>(this));
addPonyFeature(new CapeFeature<>(this)); addPonyFeature(new CapeFeature<>(this));
addPonyFeature(new SkullFeature<>(this, context.getModelLoader(), context.getItemRenderer())); addPonyFeature(new SkullFeature<>(this, context.getModelLoader(), context.getItemRenderer()));
@ -63,29 +72,41 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
protected final boolean addPonyFeature(FeatureRenderer<AbstractClientPlayerEntity, ? extends ClientPonyModel<AbstractClientPlayerEntity>> feature) { protected final boolean addPonyFeature(FeatureRenderer<? extends PonyRenderState, ? extends ClientPonyModel<? extends PonyRenderState>> feature) {
return ((List)features).add(feature); return ((List)features).add(feature);
} }
@Override public Vec3d getPositionOffset(PlayerEntityRenderState state) {
protected void scale(AbstractClientPlayerEntity entity, MatrixStack stack, float tickDelta) { Vec3d offset = super.getPositionOffset(state);
if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) { return offset.multiply(((PonyRenderState)state).getScaleFactor());
stack.translate(0, -0.25F * manager.getScaleFactor(), 0);
}
super.scale(entity, stack, tickDelta);
}
protected void preRender(AbstractClientPlayerEntity player, ModelAttributes.Mode mode) {
manager.preRender(player, mode);
} }
@Override @Override
public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public PlayerEntityRenderState createRenderState() {
return new PlayerPonyRenderState();
}
@Override
public void updateRenderState(AbstractClientPlayerEntity entity, PlayerEntityRenderState state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
manager.preRender(entity, (PlayerPonyRenderState)state, mode);
}
public final PlayerPonyRenderState getAndUpdateRenderState(AbstractClientPlayerEntity entity, float tickDelta, ModelAttributes.Mode mode) {
try {
this.mode = mode;
return (PlayerPonyRenderState)getAndUpdateRenderState(entity, tickDelta);
} finally {
this.mode = ModelAttributes.Mode.THIRD_PERSON;
}
}
@Override
public void render(PlayerEntityRenderState state, MatrixStack stack, VertexConsumerProvider vertices, int light) {
// 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
preRender(entity, ModelAttributes.Mode.THIRD_PERSON); shadowRadius = ((PlayerPonyRenderState)state).getShadowSize();
shadowRadius = manager.getShadowSize(); super.render(state, stack, vertices, light);
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv); DebugBoundingBoxRenderer.render((PlayerPonyRenderState)state, stack, vertices);
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)
@ -102,13 +123,13 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
} }
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) { protected Race getPlayerRace(PlayerPonyRenderState state) {
return pony.race(); return state.getRace();
} }
@Override @Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack matrices, float animationProgress, float bodyYaw, float tickDelta, float scale) { protected void setupTransforms(PlayerEntityRenderState state, MatrixStack matrices, float animationProgress, float bodyYaw) {
manager.setupTransforms(entity, matrices, animationProgress, bodyYaw, tickDelta, scale); manager.setupTransforms((PlayerPonyRenderState)state, matrices, animationProgress, bodyYaw);
} }
@Override @Override
@ -121,71 +142,61 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
} }
@Override @Override
protected void renderLabelIfPresent(AbstractClientPlayerEntity entity, Text name, MatrixStack stack, VertexConsumerProvider renderContext, int light, float tickDelta) { protected void renderLabelIfPresent(PlayerEntityRenderState state, Text name, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
stack.push(); matrices.push();
if (state.isInPose(EntityPose.SLEEPING)) {
if (state.sleepingDirection != null && ((PlayerPonyRenderState)state).sleepingInBed) {
double bedRad = Math.toRadians(state.sleepingDirection.asRotation());
if (entity.isSleeping()) { matrices.translate(Math.cos(bedRad), 0, -Math.sin(bedRad));
if (entity.getSleepingPosition().isPresent() && entity.getEntityWorld().getBlockState(entity.getSleepingPosition().get()).getBlock() instanceof BedBlock) {
double bedRad = Math.toRadians(entity.getSleepingDirection().asRotation());
stack.translate(Math.cos(bedRad), 0, -Math.sin(bedRad));
} }
} }
stack.translate(0, manager.getNamePlateYOffset(entity), 0); matrices.translate(0, ((PlayerPonyRenderState)state).nameplateYOffset, 0);
super.renderLabelIfPresent(entity, name, stack, renderContext, light, tickDelta); super.renderLabelIfPresent(state, name, matrices, vertices, light);
stack.pop(); matrices.pop();
} }
@Override @Override
public final void renderRightArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player) { public final void renderRightArm(MatrixStack matrices, VertexConsumerProvider vertices, int light, Identifier skinTexture, boolean sleeveVisible) {
renderArm(stack, renderContext, lightUv, player, Arm.RIGHT); renderArm(matrices, vertices, light, skinTexture, sleeveVisible, Arm.RIGHT);
} }
@Override @Override
public final void renderLeftArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player) { public final void renderLeftArm(MatrixStack matrices, VertexConsumerProvider vertices, int light, Identifier skinTexture, boolean sleeveVisible) {
renderArm(stack, renderContext, lightUv, player, Arm.LEFT); renderArm(matrices, vertices, light, skinTexture, sleeveVisible, Arm.LEFT);
} }
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) { protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int light, Identifier skinTexture, boolean sleeveVisible, Arm side) {
preRender(player, ModelAttributes.Mode.FIRST_PERSON);
stack.push(); stack.push();
float reflect = side == Arm.LEFT ? 1 : -1; float reflect = side == Arm.LEFT ? 1 : -1;
stack.translate(reflect * 0.1F, -0.54F, 0); stack.translate(reflect * 0.1F, -0.54F, 0);
Identifier texture = getTexture(player);
Identifier playerSkin = player.getSkinTextures().texture();
VertexConsumerProvider interceptedContext = layer -> { VertexConsumerProvider interceptedContext = layer -> {
return renderContext.getBuffer(RenderLayerUtil return renderContext.getBuffer(RenderLayerUtil
.getTexture(layer) .getTexture(layer)
.filter(playerSkin::equals) .filter(skinTexture::equals)
.map(i -> RenderLayer.getEntityTranslucent(texture)) .map(i -> RenderLayer.getEntityTranslucent(skinTexture))
.orElse(layer) .orElse(layer)
); );
}; };
if (side == Arm.LEFT) { if (side == Arm.LEFT) {
super.renderLeftArm(stack, interceptedContext, lightUv, player); super.renderLeftArm(stack, interceptedContext, light, skinTexture, sleeveVisible);
} else { } else {
super.renderRightArm(stack, interceptedContext, lightUv, player); super.renderRightArm(stack, interceptedContext, light, skinTexture, sleeveVisible);
} }
stack.pop(); stack.pop();
} }
@Override @Override
public Identifier getTexture(AbstractClientPlayerEntity player) { public void setModel(ClientPonyModel<PlayerPonyRenderState> model) {
return getEntityPony(player).texture();
}
@Override
public void setModel(ClientPonyModel<AbstractClientPlayerEntity> model) {
this.model = model; this.model = model;
} }
@Override @Override
public EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> getInternalRenderer() { public EquineRenderManager<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> getInternalRenderer() {
return manager; return manager;
} }
@ -195,13 +206,20 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
} }
@Override @Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) { public Identifier getTexture(PlayerEntityRenderState state) {
return SkinsProxy.getInstance().getSkin(wearable.getId(), entity).orElseGet(() -> { return ((PonyRenderState)state).pony.texture();
if (wearable.isSaddlebags() && getInternalRenderer().getModels().body().getRace().supportsLegacySaddlebags()) { }
return getTexture(entity);
@Override
public Identifier getDefaultTexture(PlayerPonyRenderState state, Wearable wearable) {
if (state.wearabledTextures.containsKey(wearable)) {
return state.wearabledTextures.get(wearable);
}
if (wearable.isSaddlebags() && state.getRace().supportsLegacySaddlebags()) {
return getTexture(state);
} }
return wearable.getDefaultTexture(); return wearable.getDefaultTexture();
});
} }
} }

View file

@ -6,35 +6,32 @@ import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.PigEntityRenderer; import net.minecraft.client.render.entity.PigEntityRenderer;
import net.minecraft.client.render.entity.feature.*; import net.minecraft.client.render.entity.feature.*;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.render.entity.state.PigEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.passive.PigEntity;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class PonyPigRenderer extends PigEntityRenderer { public class PonyPigRenderer extends PigEntityRenderer {
public PonyPigRenderer(EntityRendererFactory.Context context) { public PonyPigRenderer(EntityRendererFactory.Context context) {
super(context); super(context);
addFeature(new CrownFeature(this)); addFeature(new CrownFeature(this));
} }
private final class CrownFeature extends FeatureRenderer<PigEntity, PigEntityModel<PigEntity>> { private final class CrownFeature extends FeatureRenderer<PigEntityRenderState, PigEntityModel> {
private final PigEntityModel<PigEntity> model; private final PigEntityModel model;
public CrownFeature(FeatureRendererContext<PigEntity, PigEntityModel<PigEntity>> context) { public CrownFeature(FeatureRendererContext<PigEntityRenderState, PigEntityModel> context) {
super(context); super(context);
model = new PigEntityModel<>(PigEntityModel.getTexturedModelData(new Dilation(0.5F)).createModel()); model = new PigEntityModel(PigEntityModel.getTexturedModelData(new Dilation(0.5F)).createModel());
} }
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, PigEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, PigEntityRenderState entity, float limbDistance, float limbAngle) {
if (!entity.hasCustomName() || !entity.getCustomName().getString().equalsIgnoreCase("technoblade")) { if (entity.customName == null || !entity.customName.getString().equalsIgnoreCase("technoblade")) {
return; return;
} }
getContextModel().copyStateTo(model); model.setAngles(entity);
model.animateModel(entity, limbAngle, limbDistance, tickDelta);
model.setAngles(entity, limbAngle, limbDistance, animationProgress, headYaw, headPitch);
VertexConsumer vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(Wearable.CROWN.getDefaultTexture())); VertexConsumer vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(Wearable.CROWN.getDefaultTexture()));
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 0xFFFFFFFF); model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 0xFFFFFFFF);
} }

View file

@ -1,16 +1,19 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.mob.AbstractPiglinEntity; import net.minecraft.client.render.entity.state.PiglinEntityRenderState;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.EntityType;
import net.minecraft.entity.mob.*;
import net.minecraft.item.CrossbowItem;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.PiglinPonyModel; 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;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyModel> { public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PonyPiglinRenderer.State, PiglinPonyModel> {
public static final Identifier PIGLIN = MineLittlePony.id("textures/entity/piglin/piglin_pony.png"); public static final Identifier PIGLIN = MineLittlePony.id("textures/entity/piglin/piglin_pony.png");
public static final Identifier PIGLIN_BRUTE = MineLittlePony.id("textures/entity/piglin/piglin_brute_pony.png"); public static final Identifier PIGLIN_BRUTE = MineLittlePony.id("textures/entity/piglin/piglin_brute_pony.png");
public static final Identifier ZOMBIFIED_PIGLIN = MineLittlePony.id("textures/entity/piglin/zombified_piglin_pony.png"); public static final Identifier ZOMBIFIED_PIGLIN = MineLittlePony.id("textures/entity/piglin/zombified_piglin_pony.png");
@ -32,7 +35,24 @@ public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyMo
} }
@Override @Override
protected boolean isShaking(HostileEntity entity) { public State createRenderState() {
return entity instanceof AbstractPiglinEntity && ((AbstractPiglinEntity)entity).shouldZombify(); return new State();
} }
public void updateRenderState(AbstractPiglinEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.activity = entity.getActivity();
state.shouldZombify = entity.shouldZombify();
}
@Override
protected boolean isShaking(State state) {
return super.isShaking(state) || state.shouldZombify;
}
public static class State extends PonyRenderState {
public boolean shouldZombify;
public PiglinActivity activity;
}
} }

View file

@ -2,26 +2,32 @@ package com.minelittlepony.client.render.entity;
import com.minelittlepony.client.model.ClientPonyModel; import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.feature.StuckArrowsFeatureRenderer; import net.minecraft.client.render.entity.feature.StuckArrowsFeatureRenderer;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
public class PonyRenderer<T extends MobEntity, M extends ClientPonyModel<T>> extends AbstractPonyRenderer<T, M> { public abstract class PonyRenderer<
T extends MobEntity,
S extends PonyRenderState,
M extends ClientPonyModel<S>
> extends AbstractPonyRenderer<T, S, M> {
protected static final float BASE_MODEL_SCALE = 15/16F; protected static final float BASE_MODEL_SCALE = 15/16F;
public PonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture) { public PonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<S> texture) {
this(context, key, texture, 1); this(context, key, texture, 1);
} }
public PonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale) { public PonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<S> texture, float scale) {
super(context, key, texture, scale); super(context, key, texture, scale);
} }
@SuppressWarnings({"rawtypes", "unchecked"})
@Override @Override
protected void addFeatures(EntityRendererFactory.Context context) { protected void addFeatures(EntityRendererFactory.Context context) {
super.addFeatures(context); super.addFeatures(context);
addFeature(new StuckArrowsFeatureRenderer<>(context, this)); addFeature(new StuckArrowsFeatureRenderer(this, context));
} }
} }

View file

@ -1,18 +1,48 @@
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.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.WitchPonyModel; import com.minelittlepony.client.model.entity.WitchPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.WitchEntity; import net.minecraft.entity.mob.WitchEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class WitchRenderer extends PonyRenderer<WitchEntity, WitchPonyModel> { public class WitchRenderer extends PonyRenderer<WitchEntity, WitchRenderer.State, WitchPonyModel> {
private static final Identifier WITCH_TEXTURES = MineLittlePony.id("textures/entity/witch_pony.png"); private static final Identifier WITCH_TEXTURES = MineLittlePony.id("textures/entity/witch_pony.png");
public WitchRenderer(EntityRendererFactory.Context context) { public WitchRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.WITCH, TextureSupplier.of(WITCH_TEXTURES), BASE_MODEL_SCALE); super(context, ModelType.WITCH, TextureSupplier.of(WITCH_TEXTURES), BASE_MODEL_SCALE);
} }
@Override
public State createRenderState() {
return new State();
}
public static class State extends PonyRenderState {
public boolean drinking;
@Override
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
drinking = entity instanceof WitchEntity w && w.isDrinking();
attributes.visualHeight += 0.5F;
if (customName != null && "Filly".equals(customName.getString())) {
baby = true;
}
}
@Override
public boolean isWearing(Wearable wearable) {
return wearable == Wearable.HAT || super.isWearing(wearable);
}
}
} }

View file

@ -12,31 +12,32 @@ import net.minecraft.util.Colors;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
// separate class in case I need it later // separate class in case I need it later
public abstract class AbstractClothingFeature<T extends LivingEntity, M extends BipedEntityModel<T> & PonyModel<T>> extends FeatureRenderer<T, M> { public abstract class AbstractClothingFeature<
T extends LivingEntity,
S extends PonyRenderState,
M extends BipedEntityModel<S> & PonyModel<S>
> extends FeatureRenderer<S, M> {
protected final FeatureRendererContext<T, M> renderer; protected final FeatureRendererContext<S, M> renderer;
public AbstractClothingFeature(FeatureRendererContext<T, M> render) { public AbstractClothingFeature(FeatureRendererContext<S, M> render) {
super(render); super(render);
renderer = render; renderer = render;
} }
@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 matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
M overlayModel = getOverlayModel(); M overlayModel = getOverlayModel();
renderer.getModel().copyStateTo(overlayModel); overlayModel.setAngles(state);
overlayModel.animateModel(entity, limbDistance, limbAngle, tickDelta); VertexConsumer buffer = vertices.getBuffer(overlayModel.getLayer(getOverlayTexture()));
overlayModel.setAngles(entity, limbDistance, limbAngle, age, headYaw, headPitch); overlayModel.render(matrices, buffer, light, OverlayTexture.DEFAULT_UV, Colors.WHITE);
VertexConsumer vertexConsumer = renderContext.getBuffer(overlayModel.getLayer(getOverlayTexture()));
overlayModel.render(stack, vertexConsumer, lightUv, OverlayTexture.DEFAULT_UV, Colors.WHITE);
} }
protected abstract M getOverlayModel(); protected abstract M getOverlayModel();
protected abstract Identifier getOverlayTexture(); protected abstract Identifier getOverlayTexture();
} }

View file

@ -3,43 +3,28 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.Models; 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;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.feature.FeatureRendererContext;
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 abstract class AbstractPonyFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends FeatureRenderer<T, M> { public abstract class AbstractPonyFeature<
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends FeatureRenderer<S, M> {
private final PonyRenderContext<T, M> context; private final PonyRenderContext<?, S, M> context;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public AbstractPonyFeature(PonyRenderContext<T, M> context) { public AbstractPonyFeature(PonyRenderContext<?, S, M> context) {
super((FeatureRendererContext<T, M>)context); super((FeatureRendererContext<S, M>)context);
this.context = context; this.context = context;
} }
/**
* Renders this layer.
*
* @param stack The GL transformation matrix
* @param vertices The output 3D vertex buffer
* @param lightUv The current light value
* @param entity The entity we're being called for.
* @param limbDistance Entity motion parameter - i.e. velocity in no specific direction used in bipeds to calculate step amount.
* @param limbAngle Degree to which each 'limb' swings.
* @param tickDelta Render partial ticks
* @param age Total whole and partial ticks since the entity's existance. Used in animations together with {@code swing} and {@code move}.
* @param headYaw Horizontal head motion in radians.
* @param headPitch Vertical head motion in radians.
*/
@Override
public abstract void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <C extends PonyRenderContext<T, M> & FeatureRendererContext<T, M>> C getContext() { protected <T extends LivingEntity, C extends PonyRenderContext<T, S, M> & FeatureRendererContext<S, M>> C getContext() {
return (C)context; return (C)context;
} }
@ -48,7 +33,7 @@ public abstract class AbstractPonyFeature<T extends LivingEntity, M extends Enti
return context.getInternalRenderer().getModels().body(); return context.getInternalRenderer().getModels().body();
} }
protected Models<T, M> getModelWrapper() { protected Models<?, M> getModelWrapper() {
return context.getInternalRenderer().getModels(); return context.getInternalRenderer().getModels();
} }
} }

View file

@ -10,6 +10,7 @@ import java.util.*;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
@ -19,19 +20,19 @@ import net.minecraft.item.*;
import net.minecraft.item.trim.ArmorTrim; import net.minecraft.item.trim.ArmorTrim;
import net.minecraft.util.Colors; import net.minecraft.util.Colors;
public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class ArmourFeature<T extends LivingEntity, S extends BipedEntityRenderState, M extends EntityModel<? super S> & PonyModel<S>> extends AbstractPonyFeature<S, M> {
public ArmourFeature(PonyRenderContext<T, M> context, BakedModelManager bakery) { public ArmourFeature(PonyRenderContext<T, S, M> context, BakedModelManager bakery) {
super(context); super(context);
} }
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, S entity, float limbDistance, float limbAngle) {
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch); renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle);
} }
public static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor( public static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices, Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, T entity, VertexConsumerProvider provider, int light, S entity,
float limbDistance, float limbAngle, float limbDistance, float limbAngle,
float age, float headYaw, float headPitch) { float age, float headYaw, float headPitch) {
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get(); ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
@ -44,9 +45,9 @@ public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & Po
} }
} }
private static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor( private static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices, Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, T entity, VertexConsumerProvider provider, int light, S entity,
float limbDistance, float limbAngle, float limbDistance, float limbAngle,
float age, float headYaw, float headPitch, float age, float headYaw, float headPitch,
EquipmentSlot armorSlot, ArmourLayer layer, ArmourRendererPlugin plugin) { EquipmentSlot armorSlot, ArmourLayer layer, ArmourRendererPlugin plugin) {

View file

@ -13,23 +13,28 @@ import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.DJPon3EarsModel; import com.minelittlepony.client.model.DJPon3EarsModel;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class DJPon3Feature<T extends AbstractClientPlayerEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class DJPon3Feature<
T extends AbstractClientPlayerEntity,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends AbstractPonyFeature<S, M> {
private final DJPon3EarsModel deadMau5 = ModelType.DJ_PON_3.createModel(); private final DJPon3EarsModel deadMau5 = ModelType.DJ_PON_3.createModel();
public DJPon3Feature(PonyRenderContext<T, M> context) { public DJPon3Feature(PonyRenderContext<T, S, M> context) {
super(context); super(context);
} }
@Override @Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, S state, float limbAngle, float limbDistance) {
if ("deadmau5".equals(entity.getName().getString())) { if ("deadmau5".equals(state.name)) {
stack.push(); stack.push();
M body = getModelWrapper().body(); M body = getModelWrapper().body();
body.transform(BodyPart.HEAD, stack); body.transform(state, BodyPart.HEAD, stack);
body.getHead().rotate(stack); body.getHead().rotate(stack);
stack.scale(1.3333334F, 1.3333334F, 1.3333334F); stack.scale(1.3333334F, 1.3333334F, 1.3333334F);
@ -37,7 +42,7 @@ public class DJPon3Feature<T extends AbstractClientPlayerEntity, M extends Entit
deadMau5.setVisible(true); deadMau5.setVisible(true);
VertexConsumer vertices = renderContext.getBuffer(deadMau5.getLayer(entity.getSkinTextures().texture())); VertexConsumer vertices = renderContext.getBuffer(deadMau5.getLayer(state.skinTextures.texture()));
deadMau5.render(stack, vertices, OverlayTexture.DEFAULT_UV, light, Colors.WHITE); deadMau5.render(stack, vertices, OverlayTexture.DEFAULT_UV, light, Colors.WHITE);

View file

@ -8,12 +8,14 @@ import com.minelittlepony.client.model.PonyElytra;
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.entity.state.PonyRenderState;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
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.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.SkinTextures; import net.minecraft.client.util.SkinTextures;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -23,17 +25,21 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Colors; import net.minecraft.util.Colors;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class ElytraFeature<
T extends LivingEntity,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends AbstractPonyFeature<S, M> {
private static final Identifier TEXTURE = Identifier.ofVanilla("textures/entity/elytra.png"); private static final Identifier TEXTURE = Identifier.ofVanilla("textures/entity/elytra.png");
private final PonyElytra<T> model = ModelType.ELYTRA.createModel(); private final PonyElytra<T> model = ModelType.ELYTRA.createModel();
public ElytraFeature(PonyRenderContext<T, M> context) { public ElytraFeature(PonyRenderContext<T, S, M> context) {
super(context); super(context);
} }
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, S entity, float limbAngle, float limbDistance) {
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get(); ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
for (ItemStack stack : plugin.getArmorStacks(entity, EquipmentSlot.CHEST, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA)) { for (ItemStack stack : plugin.getArmorStacks(entity, EquipmentSlot.CHEST, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA)) {
@ -50,9 +56,7 @@ public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & Po
matrices.push(); matrices.push();
preRenderCallback(matrices); preRenderCallback(matrices);
getContextModel().copyStateTo(model); model.setAngles(entity);
model.isSneaking = PonyPosture.isCrouching(getContext().getEntityPony(entity), entity);
model.setAngles(entity, limbDistance, limbAngle, age, headYaw, headPitch);
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, (Colors.WHITE & 0xFFFFFF) | (int)(alpha * 255) << 24); model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, (Colors.WHITE & 0xFFFFFF) | (int)(alpha * 255) << 24);
matrices.pop(); matrices.pop();
@ -61,10 +65,10 @@ public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & Po
plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA); plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA);
} }
protected void preRenderCallback(MatrixStack stack) { protected void preRenderCallback(S state, MatrixStack stack) {
M body = getModelWrapper().body(); M body = getModelWrapper().body();
stack.translate(0, body.getRiderYOffset(), 0.125); stack.translate(0, state.riderOffset, 0.125);
body.transform(BodyPart.BODY, stack); body.transform(state, BodyPart.BODY, stack);
} }
protected Identifier getElytraTexture(T entity) { protected Identifier getElytraTexture(T entity) {

View file

@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import net.minecraft.block.SkullBlock; import net.minecraft.block.SkullBlock;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -24,12 +25,17 @@ 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.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class GearFeature<
T extends LivingEntity,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>
> extends AbstractPonyFeature<S, M> {
private final List<Entry> gears = Streams.concat( private final List<Entry> gears = Streams.concat(
ModelType.getWearables().map(e -> new Entry(e.getValue().createModel(), e.getKey())), ModelType.getWearables().map(e -> new Entry(e.getValue().createModel(), e.getKey())),
@ -50,13 +56,13 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & Pony
return randomizedOrder; return randomizedOrder;
})); }));
public GearFeature(PonyRenderContext<T, M> renderer) { public GearFeature(PonyRenderContext<T, S, M> renderer) {
super(renderer); super(renderer);
} }
@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, S entity, float limbAngle, float limbDistance) {
if (entity.isInvisible()) { if (entity.invisible) {
return; return;
} }
@ -89,7 +95,7 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & Pony
renderStackingOffsets.put(part, v + gear.getStackingHeight()); renderStackingOffsets.put(part, v + gear.getStackingHeight());
} }
renderGear(model, entity, gear, stack, renderContext, lightUv, limbDistance, limbAngle, tickDelta); renderGear(model, entity, gear, stack, renderContext, lightUv, limbDistance, limbAngle, entity.age);
stack.pop(); stack.pop();
} }
} }

View file

@ -4,17 +4,22 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.entity.feature.EyesFeatureRenderer; import net.minecraft.client.render.entity.feature.EyesFeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.entity.LivingEntity; import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.PonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class GlowingEyesFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends EyesFeatureRenderer<T, M> { public class GlowingEyesFeature<
S extends PonyRenderState,
M extends EntityModel<PlayerEntityRenderState> & PonyModel<S>
> extends EyesFeatureRenderer<PlayerEntityRenderState, M> {
private final RenderLayer layer; private final RenderLayer layer;
public <V extends FeatureRendererContext<T, M> & PonyRenderContext<T, M> & IGlowingRenderer> GlowingEyesFeature(V renderer) { @SuppressWarnings({"rawtypes", "unchecked"})
public <V extends FeatureRendererContext & PonyRenderContext<?, S, M> & IGlowingRenderer> GlowingEyesFeature(V renderer) {
super(renderer); super(renderer);
layer = RenderLayer.getEyes(renderer.getEyeTexture()); layer = RenderLayer.getEyes(renderer.getEyeTexture());
} }

View file

@ -1,62 +1,53 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer; import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.ModelWithArms; import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.render.item.HeldItemRenderer; 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.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
public class HeldItemFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends HeldItemFeatureRenderer<T, M> { @SuppressWarnings(value = {"unchecked"})
public class HeldItemFeature<
S extends PonyRenderState,
M extends EntityModel<PlayerEntityRenderState> & PonyModel<S>
> extends HeldItemFeatureRenderer<PlayerEntityRenderState, M> {
private final PonyRenderContext<T, M> context; private final PonyRenderContext<?, S, M> context;
@SuppressWarnings("unchecked") public HeldItemFeature(PonyRenderContext<?, S, M> context, ItemRenderer renderer) {
public HeldItemFeature(PonyRenderContext<T, M> context, HeldItemRenderer renderer) { super((FeatureRendererContext<PlayerEntityRenderState, M>)context, renderer);
super((FeatureRendererContext<T, M>)context, renderer);
this.context = context; this.context = context;
} }
protected ItemStack getLeftItem(T entity) { public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
boolean main = entity.getMainArm() == Arm.LEFT; if (!state.leftHandStack.isEmpty() || !state.rightHandStack.isEmpty()) {
M model = context.getInternalRenderer().getModels().body();
return main ? entity.getMainHandStack() : entity.getOffHandStack(); matrices.push();
model.transform(state, BodyPart.LEGS, matrices);
ModelAttributes attributes = ((PonyModel.AttributedHolder)state).getAttributes();
attributes.heldStack = state.rightHandStack;
renderItem(state, state.rightHandItemModel, state.rightHandStack, ModelTransformationMode.THIRD_PERSON_RIGHT_HAND, Arm.RIGHT, matrices, vertices, light);
attributes.heldStack = state.leftHandStack;
renderItem(state, state.leftHandItemModel, state.leftHandStack, ModelTransformationMode.THIRD_PERSON_LEFT_HAND, Arm.LEFT, matrices, vertices, light);
attributes.heldStack = ItemStack.EMPTY;
matrices.pop();
} }
protected ItemStack getRightItem(T entity) {
boolean main = entity.getMainArm() == Arm.RIGHT;
return main ? entity.getMainHandStack() : entity.getOffHandStack();
} }
@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 final void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
render(matrices, vertices, light, (S)state, limbAngle, limbDistance);
ItemStack left = getLeftItem(entity);
ItemStack right = getRightItem(entity);
if (!left.isEmpty() || !right.isEmpty()) {
M model = context.getInternalRenderer().getModels().body();
stack.push();
model.transform(BodyPart.LEGS, stack);
model.getAttributes().heldStack = right;
renderItem(entity, right, ModelTransformationMode.THIRD_PERSON_RIGHT_HAND, Arm.RIGHT, stack, renderContext, lightUv);
model.getAttributes().heldStack = left;
renderItem(entity, left, ModelTransformationMode.THIRD_PERSON_LEFT_HAND, Arm.LEFT, stack, renderContext, lightUv);
model.getAttributes().heldStack = ItemStack.EMPTY;
stack.pop();
}
} }
} }

View file

@ -1,27 +0,0 @@
package com.minelittlepony.client.render.entity.feature;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.HeldItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.IllagerEntity;
import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.PonyRenderContext;
public class IllagerHeldItemFeature<T extends IllagerEntity, M extends AlicornModel<T>> extends HeldItemFeature<T, M> {
public IllagerHeldItemFeature(PonyRenderContext<T,M> livingPony, HeldItemRenderer renderer) {
super(livingPony, renderer);
}
@Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
if (shouldRender(entity)) {
super.render(stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch);
}
}
public boolean shouldRender(T entity) {
return entity.getState() != IllagerEntity.State.CROSSED;
}
}

View file

@ -1,64 +1,73 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.ParrotEntityRenderer; import net.minecraft.client.render.entity.ParrotEntityRenderer;
import net.minecraft.client.render.entity.model.EntityModelLayers; import net.minecraft.client.render.entity.model.EntityModelLayers;
import net.minecraft.client.render.entity.model.ParrotEntityModel; import net.minecraft.client.render.entity.model.ParrotEntityModel;
import net.minecraft.client.render.entity.state.ParrotEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.passive.ParrotEntity; import net.minecraft.entity.passive.ParrotEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.client.model.ClientPonyModel; import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.Optional; public class PassengerFeature<
T extends PlayerEntity,
public class PassengerFeature<T extends PlayerEntity, M extends ClientPonyModel<T>> extends AbstractPonyFeature<T, M> { S extends PonyRenderState,
M extends ClientPonyModel<S>
> extends AbstractPonyFeature<S, M> {
private final ParrotEntityModel model; private final ParrotEntityModel model;
private final ParrotEntityRenderState parrotState = new ParrotEntityRenderState();
public PassengerFeature(PonyRenderContext<T, M> renderer, EntityRendererFactory.Context context) { public PassengerFeature(PonyRenderContext<T, S, M> renderer, EntityRendererFactory.Context context) {
super(renderer); super(renderer);
model = new ParrotEntityModel(context.getPart(EntityModelLayers.PARROT)); model = new ParrotEntityModel(context.getPart(EntityModelLayers.PARROT));
parrotState.parrotPose = ParrotEntityModel.Pose.ON_SHOULDER;
} }
@Override @Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
getShoulderParrot(entity.getShoulderEntityLeft()).ifPresent(texture -> { if (state.leftShoulderParrotVariant != null) {
renderShoulderParrot(stack, renderContext, light, entity, limbDistance, limbAngle, headYaw, headPitch, texture, 1); render(matrices, vertices, light, state, state.leftShoulderParrotVariant, limbAngle, limbDistance, true);
});
getShoulderParrot(entity.getShoulderEntityRight()).ifPresent(texture -> {
renderShoulderParrot(stack, renderContext, light, entity, limbDistance, limbAngle, headYaw, headPitch, texture, -1);
});
} }
private Optional<Identifier> getShoulderParrot(NbtCompound tag) { if (state.rightShoulderParrotVariant != null) {
return EntityType.get(tag.getString("id")) render(matrices, vertices, light, state, state.rightShoulderParrotVariant, limbAngle, limbDistance, false);
.filter(p -> p == EntityType.PARROT) }
.map(type -> ParrotEntityRenderer.getTexture(ParrotEntity.Variant.byIndex(tag.getInt("Variant"))));
} }
private void renderShoulderParrot(MatrixStack stack, VertexConsumerProvider renderContext, int light, T entity, float limbDistance, float limbAngle, float headYaw, float headPitch, Identifier texture, int sigma) { private void render(
stack.push(); MatrixStack matrices,
VertexConsumerProvider vertexConsumers,
getContextModel().transform(BodyPart.BODY, stack); int light,
S state,
stack.translate( ParrotEntity.Variant parrotVariant,
sigma * 0.25, float headYaw,
entity.isInSneakingPose() ? -0.9 : -1.2, float headPitch,
0.45); boolean left
stack.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(sigma * -5)); ) {
matrices.push();
VertexConsumer buffer = renderContext.getBuffer(model.getLayer(texture)); getContextModel().transform(state, BodyPart.BACK, matrices);
model.poseOnShoulder(stack, buffer, light, OverlayTexture.DEFAULT_UV, limbDistance, limbAngle, headYaw, headPitch, entity.age); matrices.translate(
stack.pop(); left ? 0.25F : -0.25F,
state.isInSneakingPose ? -1.3F : -1.5F, 0.0F
);
matrices.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(left ? -5 : 5));
parrotState.age = state.age;
parrotState.limbFrequency = state.limbFrequency;
parrotState.limbAmplitudeMultiplier = state.limbAmplitudeMultiplier;
parrotState.yawDegrees = headYaw;
parrotState.pitch = headPitch;
model.setAngles(parrotState);
model.render(matrices, vertexConsumers.getBuffer(model.getLayer(ParrotEntityRenderer.getTexture(parrotVariant))), light, OverlayTexture.DEFAULT_UV);
matrices.pop();
} }
} }

View file

@ -6,37 +6,38 @@ 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 com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.block.AbstractSkullBlock; import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
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.entity.state.BipedEntityRenderState;
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.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
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.mob.ZombieVillagerEntity;
import net.minecraft.entity.passive.VillagerEntity; import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ArmorItem; import net.minecraft.item.*;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> { public class SkullFeature<
T extends LivingEntity,
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>> extends AbstractPonyFeature<S, M> {
private final ItemRenderer itemRenderer; private final ItemRenderer itemRenderer;
public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) { public SkullFeature(PonyRenderContext<T, S, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) {
super(renderPony); super(renderPony);
this.itemRenderer = itemRenderer; this.itemRenderer = itemRenderer;
} }
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, S state, float limbAngle, float limbDistance) {
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get(); ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
for (ItemStack stack : plugin.getArmorStacks(entity, EquipmentSlot.HEAD, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL)) { for (ItemStack stack : plugin.getArmorStacks(state, EquipmentSlot.HEAD, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL)) {
if (stack.isEmpty()) { if (stack.isEmpty()) {
continue; continue;
} }
@ -46,16 +47,16 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
matrices.push(); matrices.push();
if (entity.isBaby() && !(entity instanceof VillagerEntity)) { if (state.baby && !(state instanceof VillagerEntity)) {
matrices.translate(0, 0.03125F, 0); matrices.translate(0, 0.03125F, 0);
matrices.scale(0.7F, 0.7F, 0.7F); matrices.scale(0.7F, 0.7F, 0.7F);
matrices.translate(0, 1, 0); matrices.translate(0, 1, 0);
} }
model.transform(BodyPart.HEAD, matrices); model.transform(state, BodyPart.HEAD, matrices);
model.getHead().rotate(matrices); model.getHead().rotate(matrices);
boolean isVillager = entity instanceof VillagerEntity || entity instanceof ZombieVillagerEntity; boolean isVillager = state instanceof VillagerEntity || state instanceof ZombieVillagerEntity;
float f = 1.1F; float f = 1.1F;
matrices.scale(f, f, f); matrices.scale(f, f, f);
@ -65,16 +66,16 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
matrices.scale(n, -n, -n); matrices.scale(n, -n, -n);
matrices.translate(0, -0.1F, 0.1F); matrices.translate(0, -0.1F, 0.1F);
matrices.translate(-0.5, 0, -0.5); matrices.translate(-0.5, 0, -0.5);
PonySkullRenderer.INSTANCE.renderSkull(matrices, provider, stack, entity, tickDelta, light, true); PonySkullRenderer.INSTANCE.renderSkull(matrices, provider, stack, state, state.age, light, true);
} else if (!(item instanceof ArmorItem a) || a.getSlotType() != EquipmentSlot.HEAD) { } else if (!(item instanceof ArmorItem a) || a.getSlotType() != EquipmentSlot.HEAD) {
matrices.translate(0, 0.1F, -0.1F); matrices.translate(0, 0.1F, -0.1F);
HeadFeatureRenderer.translate(matrices, isVillager); HeadFeatureRenderer.translate(matrices, isVillager);
itemRenderer.renderItem(entity, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal()); itemRenderer.renderItem(state, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal());
} }
matrices.pop(); matrices.pop();
} }
plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL); plugin.onArmourRendered(state, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.SKULL);
} }
} }

View file

@ -14,12 +14,16 @@ import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.entity.PonyRenderer; import com.minelittlepony.client.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.npc.textures.*; import com.minelittlepony.client.render.entity.npc.textures.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.function.Function; import java.util.function.Function;
abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer> extends PonyRenderer<T, ClientPonyModel<T>> { abstract class AbstractNpcRenderer<
private final NpcClothingFeature<T, ClientPonyModel<T>, AbstractNpcRenderer<T>> clothing; T extends MobEntity & VillagerDataContainer,
private final Function<Race, Models<T, ClientPonyModel<T>>> models = Util.memoize(race -> { S extends PonyRenderState
> extends PonyRenderer<T, S, ClientPonyModel<S>> {
private final NpcClothingFeature<T, S, ClientPonyModel<S>, AbstractNpcRenderer<T, S>> clothing;
private final Function<Race, Models<T, ClientPonyModel<S>>> models = Util.memoize(race -> {
if (race.isHuman()) { if (race.isHuman()) {
race = Race.EARTH; race = Race.EARTH;
} }
@ -34,7 +38,7 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
} }
@Override @Override
public boolean shouldRender(ClientPonyModel<T> model, T entity, Wearable wearable, Gear gear) { public boolean shouldRender(ClientPonyModel<S> model, S entity, Wearable wearable, Gear gear) {
if (wearable == Wearable.SADDLE_BAGS_BOTH) { if (wearable == Wearable.SADDLE_BAGS_BOTH) {
VillagerProfession profession = entity.getVillagerData().getProfession(); VillagerProfession profession = entity.getVillagerData().getProfession();
return !SillyPonyTextureSupplier.isBestPony(entity) && profession != VillagerProfession.NONE && ( return !SillyPonyTextureSupplier.isBestPony(entity) && profession != VillagerProfession.NONE && (
@ -52,12 +56,12 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
return super.shouldRender(model, entity, wearable, gear); return super.shouldRender(model, entity, wearable, gear);
} }
protected void initializeModel(ClientPonyModel<T> model) { protected void initializeModel(ClientPonyModel<S> model) {
} }
@Override @Override
public Identifier getDefaultTexture(T villager, Wearable wearable) { public Identifier getDefaultTexture(S villager, Wearable wearable) {
if (wearable.isSaddlebags()) { if (wearable.isSaddlebags()) {
return clothing.createTexture(villager, "accessory"); return clothing.createTexture(villager, "accessory");
} }

View file

@ -19,6 +19,7 @@ import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.feature.AbstractPonyFeature; import com.minelittlepony.client.render.entity.feature.AbstractPonyFeature;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.util.render.TextureFlattener; import com.minelittlepony.client.util.render.TextureFlattener;
import com.minelittlepony.util.ResourceUtil; import com.minelittlepony.util.ResourceUtil;
@ -26,8 +27,9 @@ import java.util.*;
class NpcClothingFeature< class NpcClothingFeature<
T extends LivingEntity & VillagerDataContainer, T extends LivingEntity & VillagerDataContainer,
M extends EntityModel<T> & PonyModel<T>, S extends PonyRenderState,
C extends FeatureRendererContext<T, M> & PonyRenderContext<T, M>> extends AbstractPonyFeature<T, M> { M extends EntityModel<S> & PonyModel<S>,
C extends FeatureRendererContext<S, M> & PonyRenderContext<T, S, M>> extends AbstractPonyFeature<S, M> {
private static final Int2ObjectMap<Identifier> LEVEL_TO_ID = Util.make(new Int2ObjectOpenHashMap<>(), a -> { private static final Int2ObjectMap<Identifier> LEVEL_TO_ID = Util.make(new Int2ObjectOpenHashMap<>(), a -> {
a.put(1, Identifier.ofVanilla("stone")); a.put(1, Identifier.ofVanilla("stone"));
@ -46,22 +48,22 @@ class NpcClothingFeature<
} }
@Override @Override
public void render(MatrixStack matrixStack, VertexConsumerProvider provider, int i, T entity, float f, float g, float h, float j, float k, float l) { public void render(MatrixStack matrixStack, VertexConsumerProvider provider, int light, S entity, float limbAngle, float limbDistance) {
if (entity.isInvisible()) { if (entity.invisible) {
return; return;
} }
VillagerData data = entity.getVillagerData(); VillagerData data = entity.getVillagerData();
M entityModel = getContextModel(); M entityModel = getContextModel();
if (entity.isBaby() || data.getProfession() == VillagerProfession.NONE) { if (entity.baby || data.getProfession() == VillagerProfession.NONE) {
Identifier typeSkin = createTexture("type", Registries.VILLAGER_TYPE.getId(data.getType())); Identifier typeSkin = createTexture("type", Registries.VILLAGER_TYPE.getId(data.getType()));
if (!ResourceUtil.textureExists(typeSkin)) { if (!ResourceUtil.textureExists(typeSkin)) {
typeSkin = createTexture("type", Registries.VILLAGER_TYPE.getId(VillagerType.PLAINS)); typeSkin = createTexture("type", Registries.VILLAGER_TYPE.getId(VillagerType.PLAINS));
} }
renderModel(entityModel, typeSkin, matrixStack, provider, i, entity, Colors.WHITE); renderModel(entityModel, typeSkin, matrixStack, provider, light, entity, Colors.WHITE);
} else { } else {
renderModel(entityModel, getMergedTexture(data), matrixStack, provider, i, entity, Colors.WHITE); renderModel(entityModel, getMergedTexture(data), matrixStack, provider, light, entity, Colors.WHITE);
} }
} }

View file

@ -1,18 +1,28 @@
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.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.IllagerEntity;
import net.minecraft.entity.mob.PillagerEntity; import net.minecraft.entity.mob.PillagerEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.PillagerPonyModel; import com.minelittlepony.client.model.entity.PillagerPonyModel;
import com.minelittlepony.client.render.entity.feature.IllagerHeldItemFeature; import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.PonyRenderer; import com.minelittlepony.client.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.feature.HeldItemFeature; import com.minelittlepony.client.render.entity.feature.HeldItemFeature;
public class PillagerRenderer extends PonyRenderer<PillagerEntity, PillagerPonyModel<PillagerEntity>> { public class PillagerRenderer extends PonyRenderer<PillagerEntity, PillagerRenderer.State, PillagerPonyModel> {
private static final Identifier TEXTURE = MineLittlePony.id("textures/entity/illager/pillager_pony.png"); private static final Identifier TEXTURE = MineLittlePony.id("textures/entity/illager/pillager_pony.png");
public PillagerRenderer(EntityRendererFactory.Context context) { public PillagerRenderer(EntityRendererFactory.Context context) {
@ -20,7 +30,43 @@ public class PillagerRenderer extends PonyRenderer<PillagerEntity, PillagerPonyM
} }
@Override @Override
protected HeldItemFeature<PillagerEntity, PillagerPonyModel<PillagerEntity>> createHeldItemFeature(EntityRendererFactory.Context context) { protected HeldItemFeature<PillagerRenderer.State, PillagerPonyModel> createHeldItemFeature(EntityRendererFactory.Context context) {
return new IllagerHeldItemFeature<>(this, context.getHeldItemRenderer()); return new IllagerHeldItemFeature<>(this, context.getItemRenderer());
}
@Override
public State createRenderState() {
return new State();
}
public class State extends PonyRenderState {
public IllagerEntity.State state;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
state = ((IllagerEntity)entity).getState();
}
}
public class IllagerHeldItemFeature<
T extends IllagerEntity,
S extends PillagerRenderer.State,
M extends AlicornModel<S>
> extends HeldItemFeature<S, M> {
public IllagerHeldItemFeature(PonyRenderContext<T, S, M> livingPony, ItemRenderer renderer) {
super(livingPony, renderer);
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
if (shouldRender(state)) {
super.render(matrices, vertices, light, state, limbAngle, limbDistance);
}
}
protected boolean shouldRender(S state) {
return state.state != IllagerEntity.State.CROSSED;
}
} }
} }

View file

@ -9,11 +9,17 @@ import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.race.AlicornModel; import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.entity.PonyRenderer; import com.minelittlepony.client.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier; import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class TraderRenderer extends PonyRenderer<WanderingTraderEntity, AlicornModel<WanderingTraderEntity>> { public class TraderRenderer extends PonyRenderer<WanderingTraderEntity, PonyRenderState, AlicornModel<PonyRenderState>> {
public static final Identifier TEXTURE = MineLittlePony.id("textures/entity/wandering_trader_pony.png"); public static final Identifier TEXTURE = MineLittlePony.id("textures/entity/wandering_trader_pony.png");
public TraderRenderer(EntityRendererFactory.Context context) { public TraderRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.ALICORN.getKey(false), TextureSupplier.of(TEXTURE), BASE_MODEL_SCALE); super(context, ModelType.ALICORN.getKey(false), TextureSupplier.of(TEXTURE), BASE_MODEL_SCALE);
} }
@Override
public PonyRenderState createRenderState() {
return new PonyRenderState();
}
} }

View file

@ -0,0 +1,31 @@
package com.minelittlepony.client.render.entity.state;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.api.pony.meta.Wearable;
import java.util.HashMap;
import java.util.Map;
public class PlayerPonyRenderState extends PonyRenderState {
public final Map<Wearable, Identifier> wearabledTextures = new HashMap<>();
@Override
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
wearabledTextures.clear();
for (Wearable wearable : Wearable.REGISTRY.values()) {
if (isWearing(wearable)) {
SkinsProxy.getInstance().getSkin(wearable.getId(), (PlayerEntity)entity).ifPresent(skin -> {
wearabledTextures.put(wearable, skin);
});
}
}
}
}

View file

@ -0,0 +1,146 @@
package com.minelittlepony.client.render.entity.state;
import net.minecraft.block.BedBlock;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.*;
public class PonyRenderState extends PlayerEntityRenderState implements PonyModel.AttributedHolder {
public final ModelAttributes attributes = new ModelAttributes();
public float vehicleOffset;
public float riderOffset;
public float nameplateYOffset;
public float legOutset;
public boolean smallArms;
public boolean sleepingInBed;
public boolean submergedInWater;
public boolean onGround;
public Pony pony;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
attributes.updateLivingState(entity, pony, mode);
attributes.checkRainboom(entity, model, age);
this.pony = pony;
vehicleOffset = hasVehicle ? entity.getVehicle().getEyeHeight(pose) : 0;
riderOffset = getRiderYOffset();
nameplateYOffset = getNamePlateYOffset(entity);
legOutset = getLegOutset();
isInSneakingPose = attributes.isCrouching && !attributes.isLyingDown;
sleepingInBed = entity.getSleepingPosition().isPresent() && entity.getEntityWorld().getBlockState(entity.getSleepingPosition().get()).getBlock() instanceof BedBlock;
submergedInWater = entity.isSubmergedInWater();
if (attributes.isSitting) {
pose = EntityPose.SITTING;
}
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(attributes, model, ModelAttributes.Mode.OTHER);
}
/**
* Gets the active scaling profile used to lay out this model's parts.
*/
public Size getSize() {
return baby ? SizePreset.FOAL : PonyConfig.getEffectiveSize(attributes.metadata.size());
}
public Race getRace() {
return PonyConfig.getEffectiveRace(attributes.metadata.race());
}
public final float getScaleFactor() {
return getSize().scaleFactor();
}
public final float getShadowSize() {
return getSize().shadowSize();
}
/**
* Gets the current leg swing amount.
*/
public float getSwingAmount() {
return this.handSwingProgress;
}
/**
* Gets the step wobble used for various hair bits and animations.
*/
public float getWobbleAmount() {
if (getSwingAmount() <= 0) {
return 0;
}
return MathHelper.sin(MathHelper.sqrt(getSwingAmount()) * MathHelper.PI * 2) * 0.04F;
}
protected float getLegOutset() {
float outset = attributes.isLyingDown ? 3.6F : attributes.isCrouching ? 1 : 5;
if (smallArms) {
return Math.max(1, outset - 1);
}
return outset;
}
/**
* Gets the y-offset applied to entities riding this one.
*/
protected float getRiderYOffset() {
switch ((SizePreset)getSize()) {
case NORMAL: return 0.4F;
case FOAL:
case TALL:
case BULKY:
default: return 0.25F;
}
}
/**
* Tests if this model is wearing the given piece of gear.
*/
public boolean isWearing(Wearable wearable) {
return isEmbedded(wearable) || attributes.featureSkins.contains(wearable.getId());
}
/**
* Tests if the chosen piece of gear is sourcing its texture from the main skin.
* i.e. Used to change wing rendering when using saddlebags.
*/
public boolean isEmbedded(Wearable wearable) {
return attributes.metadata.gear().matches(wearable);
}
private float getNamePlateYOffset(LivingEntity entity) {
// We start by negating the height calculation done by mahjong.
float y = -(height + 0.5F);
// Then we add our own offsets.
y += attributes.visualHeight * getScaleFactor() + 0.25F;
y += vehicleOffset;
if (isInSneakingPose) {
y -= 0.25F;
}
if (isInPose(EntityPose.SLEEPING)) {
y /= 2;
}
return y;
}
@Override
public ModelAttributes getAttributes() {
return attributes;
}
}

View file

@ -0,0 +1,34 @@
package com.minelittlepony.client.render.entity.state;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.mob.WitherSkeletonEntity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Race;
public class SkeletonPonyRenderState extends PonyRenderState {
public boolean isUnicorn;
public boolean isWithered;
public boolean isAttacking;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
isUnicorn = entity.getUuid().getLeastSignificantBits() % 3 != 0;
isWithered = entity instanceof WitherSkeletonEntity;
isAttacking = entity instanceof HostileEntity h && h.isAttacking();
}
@Override
public Race getRace() {
return isUnicorn ? super.getRace() : Race.EARTH;
}
@Override
protected float getLegOutset() {
if (attributes.isLyingDown) return 2.6f;
if (attributes.isCrouching) return 0;
return 4;
}
}

View file

@ -50,7 +50,7 @@ public interface PonyPosture {
// this reverts the rotations done in PlayerEntityRenderer#setupTransforms // this reverts the rotations done in PlayerEntityRenderer#setupTransforms
if (player instanceof PlayerEntity) { if (player instanceof PlayerEntity) {
float leaningPitch = player.getLeaningPitch(tickDelta); float leaningPitch = player.getLeaningPitch(tickDelta);
if (player.isFallFlying()) { if (player.isGliding()) {
if (RenderPass.getCurrent() == RenderPass.GUI) { if (RenderPass.getCurrent() == RenderPass.GUI) {
Vec3d vec3d = player.getRotationVec(tickDelta); Vec3d vec3d = player.getRotationVec(tickDelta);
@ -64,7 +64,7 @@ public interface PonyPosture {
} }
} }
float roll = (float)player.getFallFlyingTicks() + tickDelta; float roll = (float)player.getGlidingTicks() + tickDelta;
float targetRoll = MathHelper.clamp(roll * roll / 100F, 0, 1); float targetRoll = MathHelper.clamp(roll * roll / 100F, 0, 1);
if (!player.isUsingRiptide()) { if (!player.isUsingRiptide()) {
stack.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(targetRoll * (-90 - player.getPitch()))); stack.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(targetRoll * (-90 - player.getPitch())));

View file

@ -107,7 +107,7 @@ public class NativeUtil {
if (loadedTexture instanceof NativeImageBackedTexture nibt) { if (loadedTexture instanceof NativeImageBackedTexture nibt) {
NativeImage image = nibt.getImage(); NativeImage image = nibt.getImage();
if (image != null) { if (image != null) {
consumer.accept(image::getColor); consumer.accept(image::getColorArgb);
return; return;
} }
} }
@ -115,7 +115,7 @@ public class NativeUtil {
Resource res = mc.getResourceManager().getResource(resource).orElse(null); Resource res = mc.getResourceManager().getResource(resource).orElse(null);
if (res != null) { if (res != null) {
try (InputStream inputStream = res.getInputStream()){ try (InputStream inputStream = res.getInputStream()){
consumer.accept(NativeImage.read(inputStream)::getColor); consumer.accept(NativeImage.read(inputStream)::getColorArgb);
return; return;
} }
} }
@ -128,10 +128,9 @@ public class NativeUtil {
private static void __reconstructNativeImage(Identifier resource, Consumer<TriggerPixel.Mat> consumer, Consumer<Exception> fail, int attempt) { private static void __reconstructNativeImage(Identifier resource, Consumer<TriggerPixel.Mat> consumer, Consumer<Exception> fail, int attempt) {
MinecraftClient mc = MinecraftClient.getInstance(); MinecraftClient mc = MinecraftClient.getInstance();
TextureManager textures = mc.getTextureManager();
// recreate NativeImage from the GL matrix // recreate NativeImage from the GL matrix
textures.bindTexture(resource); RenderSystem.setShaderTexture(GL_TEXTURE_2D, resource);
// TODO: This returns values that are too specific. // TODO: This returns values that are too specific.
// Can we change the level (0) here to something // Can we change the level (0) here to something
@ -158,7 +157,7 @@ public class NativeUtil {
// This allocates a new array to store the image every time. // This allocates a new array to store the image every time.
// Don't do this every time. Keep a cache and store it so we don't destroy memory. // Don't do this every time. Keep a cache and store it so we don't destroy memory.
image.loadFromTextureImage(0, false); image.loadFromTextureImage(0, false);
consumer.accept(image::getColor); consumer.accept(image::getColorArgb);
} }
} }
} }

View file

@ -51,9 +51,9 @@ public class TextureFlattener {
} }
public static void copy(NativeImage from, NativeImage to, int x, int y) { public static void copy(NativeImage from, NativeImage to, int x, int y) {
int color = from.getColor(x, y); int color = from.getColorArgb(x, y);
if (ColorHelper.Argb.getAlpha(color) > 0) { if (ColorHelper.getAlpha(color) > 0) {
to.setColor(x, y, color); to.setColorArgb(x, y, color);
} }
} }
} }