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 {
id 'fabric-loom' version '1.6-SNAPSHOT'
id 'fabric-loom' version '1.7-SNAPSHOT'
id 'maven-publish'
id 'com.modrinth.minotaur' version '2.+'
id 'org.ajoberstar.reckon' version '0.13.1'

View file

@ -3,10 +3,10 @@ org.gradle.daemon=false
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.21
yarn_mappings=1.21+build.9
loader_version=0.15.11
fabric_version=0.100.7+1.21
minecraft_version=1.21.3
yarn_mappings=1.21.3+build.2
loader_version=0.16.7
fabric_version=0.106.1+1.21.3
# Mod Properties
group=com.minelittlepony
@ -19,7 +19,7 @@ org.gradle.daemon=false
modrinth_project_id=JBjInUXM
# Dependencies
modmenu_version=11.0.0-beta.1
modmenu_version=12.0.0-beta.1
kirin_version=1.19.1+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
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
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.EventFactory;
import net.minecraft.entity.Entity;
import com.minelittlepony.api.model.PonyModel;
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;
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.
*/
default boolean hasMagic() {
return getRace().hasHorn() && getAttributes().metadata.glowColor() != 0;
default boolean hasMagic(T state) {
return state.getRace().hasHorn() && state.attributes.metadata.glowColor() != 0;
}
/**
* 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.pony.*;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.common.util.animation.Interpolator;
import com.minelittlepony.util.MathUtil;
@ -73,6 +74,11 @@ public class ModelAttributes {
*/
public boolean isHorsey;
/**
* Flag indicating whether the pony is a player
*/
public boolean isPlayer;
/**
* Vertical pitch whilst flying.
*/
@ -130,7 +136,7 @@ public class ModelAttributes {
isGoingFast = (isFlying && model instanceof WingedPonyModel) || isGliding;
isGoingFast &= zMotion > 0.4F;
isGoingFast |= entity.isUsingRiptide();
isGoingFast |= entity.isFallFlying();
isGoingFast |= entity.isGliding();
motionLerp = MathUtil.clampLimit(zMotion * 30, 1);
@ -148,18 +154,19 @@ public class ModelAttributes {
}
public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) {
isPlayer = entity instanceof PlayerEntity;
visualHeight = entity.getHeight() + 0.125F;
isSitting = PonyPosture.isSitting(entity);
isSleeping = entity.isAlive() && entity.isSleeping();;
isLyingDown = isSleeping;
if (entity instanceof PlayerEntity) {
if (isPlayer) {
boolean moving = entity.getVelocity().multiply(1, 0, 1).length() == 0 && entity.isSneaking();
isLyingDown |= getMainInterpolator().interpolate("lyingDown", moving ? 10 : 0, 200) >= 9;
}
isCrouching = !isLyingDown && !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity);
isFlying = !isLyingDown && mode == Mode.THIRD_PERSON && PonyPosture.isFlying(entity);
isGliding = entity.isFallFlying();
isGliding = entity.isGliding();
isSwimming = mode == Mode.THIRD_PERSON && PonyPosture.isSwimming(entity);
isSwimmingRotated = isSwimming;
isRiptide = entity.isUsingRiptide();
@ -185,6 +192,21 @@ public class ModelAttributes {
&& (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 {
FIRST_PERSON,
THIRD_PERSON,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart;
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.util.Arm;
@ -10,5 +11,5 @@ public interface ModelWithHooves extends ModelWithArms {
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.render.entity.model.*;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
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;
public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
void copyAttributes(BipedEntityModel<T> other);
void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode);
public interface PonyModel<T extends BipedEntityRenderState & PonyModel.AttributedHolder> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
ModelPart getBodyPart(BodyPart part);
/**
* Applies a transform particular to a certain body part.
*/
void transform(BodyPart part, MatrixStack stack);
void transform(T state, BodyPart part, MatrixStack stack);
/**
* Gets the transitive properties of this model.
*/
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());
public interface AttributedHolder {
ModelAttributes getAttributes();
}
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.render.entity.model.BipedEntityModel;
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.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Arm;
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.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();
@Override
@ -108,7 +108,7 @@ public interface PonyModelMixin<T extends LivingEntity, M extends PonyModel<T>>
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
default boolean isCasting() {
return mixin().isCasting();

View file

@ -1,12 +1,12 @@
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.pony.meta.Wearable;
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_FULL_SPREAD_ANGLE = MathUtil.Angles._270_DEG + 0.4F;
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.
*/
default boolean wingsAreOpen() {
return (getAttributes().isSwimming || getAttributes().isFlying || getAttributes().isCrouching)
&& (PonyConfig.getInstance().flappyElytras.get() || !getAttributes().isGliding);
default boolean wingsAreOpen(T state) {
return (state.getAttributes().isSwimming || state.getAttributes().isFlying || state.getAttributes().isCrouching)
&& (PonyConfig.getInstance().flappyElytras.get() || !state.getAttributes().isGliding);
}
default boolean isBurdened() {
return isWearing(Wearable.SADDLE_BAGS_BOTH)
|| isWearing(Wearable.SADDLE_BAGS_LEFT)
|| isWearing(Wearable.SADDLE_BAGS_RIGHT);
default boolean isBurdened(T state) {
return state.getAttributes().isWearing(Wearable.SADDLE_BAGS_BOTH)
|| state.getAttributes().isWearing(Wearable.SADDLE_BAGS_LEFT)
|| 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
*/
default float getWingRotationFactor(float ticks) {
return getAttributes().wingAngle;
default float getWingRotationFactor(T state, float ticks) {
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.util.math.MatrixStack;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public abstract class AbstractGearModel extends Model implements Gear {
private final List<ModelPart> parts = new ArrayList<>();
private final float stackingHeight;
public AbstractGearModel(float stackingHeight) {
super(RenderLayer::getEntitySolid);
public AbstractGearModel(ModelPart root, float stackingHeight) {
super(root, RenderLayer::getEntitySolid);
this.stackingHeight = stackingHeight;
}
public AbstractGearModel addPart(ModelPart t) {
parts.add(t);
return this;
}
@Override
public void render(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, UUID interpolatorId) {
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
public boolean isStackable() {
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.VertexConsumer;
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.entity.Entity;
import net.minecraft.util.Identifier;
@ -37,7 +38,7 @@ public interface Gear {
*
* @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.
@ -62,12 +63,12 @@ public interface Gear {
*
* 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.
*/
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));
}
@ -100,7 +101,7 @@ public interface Gear {
* @param <T> The type of entity being rendered.
* @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.
*/
@ -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.
*/
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);
}
@ -118,6 +119,6 @@ public interface Gear {
*
* 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;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
@ -12,8 +13,8 @@ public class WearableGear extends AbstractGearModel {
protected final Wearable wearable;
protected final BodyPart location;
public WearableGear(Wearable wearable, BodyPart location, float stackingHeight) {
super(stackingHeight);
public WearableGear(ModelPart root, Wearable wearable, BodyPart location, float stackingHeight) {
super(root, stackingHeight);
this.wearable = wearable;
this.location = location;
}

View file

@ -32,7 +32,7 @@ public final class PonyPosture {
Vec3d motion = entity.getVelocity();
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) {

View file

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

View file

@ -54,6 +54,6 @@ public enum Wearable implements TValue<Wearable> {
@Override
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
public Optional<Identifier> getSkin(Identifier skinTypeId, PlayerEntity player) {
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.VertexConsumerProvider;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.world.World;
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.events.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.mson.util.RenderList;
import com.minelittlepony.util.MathUtil;
@ -14,15 +15,22 @@ import java.util.function.Supplier;
import net.minecraft.client.model.ModelPart;
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.entity.EntityPose;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.consume.UseAction;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import org.jetbrains.annotations.Nullable;
/**
* 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 LEG_SNEAKING_PITCH_ADJUSTMENT = 0.4F;
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<>();
public AbstractPonyModel(ModelPart tree) {
super(tree);
@Nullable
protected T currentState;
public AbstractPonyModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms);
neck = tree.getChild("neck");
mainRenderList = RenderList.of()
@ -71,14 +82,19 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
}
protected RenderList forPart(Supplier<SubModel> part) {
return (stack, vertices, overlay, light, color) -> {
part.get().renderPart(stack, vertices, overlay, light, color, attributes);
};
return (stack, vertices, overlay, light, color) -> part.get().renderPart(stack, vertices, overlay, light, color, currentState.attributes);
}
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) -> {
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);
}
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.
*/
@SuppressWarnings("unchecked")
@Override
public final void setAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
attributes.checkRainboom(entity, this, animationProgress);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, ModelAttributes.Mode.OTHER);
super.setAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch);
public final void setAngles(PlayerEntityRenderState entity) {
currentState = (T)entity;
super.setAngles((PlayerEntityRenderState)entity);
resetPivot(head, neck, leftArm, rightArm, leftLeg, rightLeg);
setModelAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch);
setModelVisibilities((T)entity);
setModelAngles((T)entity);
leftSleeve.copyTransform(leftArm);
rightSleeve.copyTransform(rightArm);
@ -117,57 +125,70 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
hat.copyTransform(head);
}
protected void setModelAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
float pitch = attributes.motionPitch * MathHelper.RADIANS_PER_DEGREE;
protected void setModelVisibilities(T state) {
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(
MathHelper.clamp(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,
MathHelper.clamp(entity.attributes.isSleeping ? 0.1f : headPitch / 57.29578F, -1.25f - pitch, 0.5f - pitch),
entity.attributes.isSleeping ? (Math.signum(MathHelper.wrapDegrees(headYaw)) * 1.3F) : headYaw * MathHelper.RADIANS_PER_DEGREE,
0
);
float wobbleAmount = getWobbleAmount();
float wobbleAmount = entity.getWobbleAmount();
body.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) {
onSetModelAngles.poseModel(this, limbAngle, limbSpeed, animationProgress, entity);
onSetModelAngles.poseModel(this, entity);
}
if (!attributes.isSwimming && !attributes.isGoingFast) {
holdItem(limbSpeed);
if (!entity.attributes.isSwimming && !entity.attributes.isGoingFast) {
holdItem(entity, limbSpeed, left, right);
}
swingItem(entity);
if (attributes.isCrouching) {
ponyCrouch();
} else if (riding) {
if (entity.attributes.isCrouching) {
ponyCrouch(entity);
} else if (entity.isInPose(EntityPose.SITTING)) {
ponySit();
} else {
adjustBody(0, ORIGIN);
adjustBody(entity, 0, ORIGIN);
if (!attributes.isLyingDown) {
animateBreathing(animationProgress);
if (!entity.attributes.isLyingDown) {
animateBreathing(entity, animationProgress, left, right);
}
if (attributes.isSwimmingRotated) {
if (entity.attributes.isSwimmingRotated) {
rightLeg.pivotZ -= 1.5F;
leftLeg.pivotZ -= 1.5F;
}
}
if (attributes.isLyingDown) {
if (entity.attributes.isLyingDown) {
ponySleep();
}
if (attributes.isHorsey) {
if (entity.attributes.isHorsey) {
head.pivotY -= 3;
head.pivotZ -= 2;
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) {
@ -179,8 +200,8 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
/**
* Aligns legs to a sneaky position.
*/
protected void ponyCrouch() {
adjustBody(BODY_SNEAKING_PITCH, BODY_SNEAKING);
protected void ponyCrouch(T state) {
adjustBody(state, BODY_SNEAKING_PITCH, BODY_SNEAKING);
HEAD_SNEAKING.set(head);
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}
*
*/
protected void rotateLegs(float move, float swing, float ticks, T entity) {
if (attributes.isSwimming) {
rotateLegsSwimming(move, swing, ticks, entity);
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
if (state.attributes.isSwimming) {
rotateLegsSwimming(state, move, swing, ticks, entity);
} else {
rotateLegsOnGround(move, swing, ticks, entity);
rotateLegsOnGround(state, move, swing, ticks, entity);
}
float sin = MathHelper.sin(body.yaw) * 5;
@ -245,8 +266,8 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
rightArm.pivotZ = 2 + sin;
leftArm.pivotZ = 2 - sin;
float legRPX = attributes.getMainInterpolator().interpolate("legOffset", cos - getLegOutset() - 0.001F, 2);
if (attributes.isHorsey) {
float legRPX = state.attributes.getMainInterpolator().interpolate("legOffset", cos - state.legOutset - 0.001F, 2);
if (state.attributes.isHorsey) {
legRPX += 2;
}
@ -259,7 +280,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
rightArm.yaw += body.yaw;
leftArm.yaw += body.yaw;
if (attributes.isHorsey) {
if (state.attributes.isHorsey) {
rightArm.pivotZ = leftArm.pivotZ = -1;
rightArm.pivotY = leftArm.pivotY = 6;
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}
*/
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;
@ -291,15 +312,15 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* 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 baseRotation = move * 0.6662F; // magic number ahoy
float scale = swing / 4;
float rainboomLegLotation = attributes.getMainInterpolator().interpolate(
float rainboomLegLotation = state.attributes.getMainInterpolator().interpolate(
"rainboom_leg_rotation",
attributes.isGoingFast ? 1 : 0,
state.attributes.isGoingFast ? 1 : 0,
5
);
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);
}
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.
*/
protected void holdItem(float limbSpeed) {
alignArmForAction(getArm(Arm.LEFT), leftArmPose, rightArmPose, limbSpeed, 1);
alignArmForAction(getArm(Arm.RIGHT), rightArmPose, leftArmPose, limbSpeed, -1);
protected void holdItem(T state, float limbSpeed, ArmPose left, ArmPose right) {
alignArmForAction(state, getArm(Arm.LEFT), left, right, limbSpeed, 1);
alignArmForAction(state, getArm(Arm.RIGHT), right, left, limbSpeed, -1);
}
@Override
@ -350,16 +359,16 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
* @param pose The post to align to
* @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) {
case ITEM:
arm.yaw = 0;
boolean both = pose == complement;
if (attributes.shouldLiftArm(pose, complement, sigma)) {
if (state.attributes.shouldLiftArm(pose, complement, sigma)) {
float swag = 1;
if (!getAttributes().isFlying && both) {
if (!state.attributes.isFlying && both) {
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 += 0.3F * -limbSpeed * sigma;
if (attributes.isCrouching) {
if (state.attributes.isCrouching) {
arm.pivotX -= sigma * 2;
}
}
@ -386,21 +395,21 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
}
arm.pivotX += sigma;
arm.pivotZ += 3;
if (attributes.isCrouching) {
if (state.attributes.isCrouching) {
arm.pivotY += 4;
}
break;
case BOW_AND_ARROW:
aimBow(arm, limbSpeed);
aimBow(state, arm, limbSpeed);
break;
case CROSSBOW_HOLD:
aimBow(arm, limbSpeed);
aimBow(state, arm, limbSpeed);
arm.pitch = head.pitch - MathUtil.Angles._90_DEG;
arm.yaw = head.yaw + 0.06F;
break;
case CROSSBOW_CHARGE:
aimBow(arm, limbSpeed);
aimBow(state, arm, limbSpeed);
arm.pitch = -0.8F;
arm.yaw = head.yaw + 0.06F;
@ -412,20 +421,20 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
arm.pivotY ++;
break;
case SPYGLASS:
float addedPitch = sneaking ? -0.2617994F : 0;
float minPitch = sneaking ? -1.8F : -2.4F;
float addedPitch = state.isInSneakingPose ? -0.2617994F : 0;
float minPitch = state.isInSneakingPose ? -1.8F : -2.4F;
arm.pitch = MathHelper.clamp(head.pitch - 1.9198622F - addedPitch, minPitch, 3.3F);
arm.yaw = head.yaw;
if (sneaking) {
if (state.isInSneakingPose) {
arm.pivotY += 9;
arm.pivotX -= 6 * sigma;
arm.pivotZ -= 2;
}
if (getSize() == SizePreset.TALL) {
if (state.getSize() == SizePreset.TALL) {
arm.pivotY += 1;
}
if (getSize() == SizePreset.FOAL) {
if (state.getSize() == SizePreset.FOAL) {
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.yaw = head.yaw - 0.06F;
arm.roll = MathHelper.cos(limbSpeed * 0.09F) * 0.05F + 0.05F;
if (sneaking) {
if (state.isInSneakingPose) {
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.
*/
protected void swingItem(T entity) {
if (getSwingAmount() > 0 && !attributes.isLyingDown) {
Arm mainSide = getPreferredArm(entity);
swingArm(getArm(mainSide));
protected void swingItem(T state) {
if (state.getSwingAmount() > 0 && !state.attributes.isLyingDown) {
swingArm(state, getArm(state.preferredArm));
}
}
@ -474,11 +481,11 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
*
* @param arm The arm to swing
*/
protected void swingArm(ModelPart arm) {
float swing = 1 - (float)Math.pow(1 - getSwingAmount(), 3);
protected void swingArm(T state, ModelPart arm) {
float swing = 1 - (float)Math.pow(1 - state.getSwingAmount(), 3);
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;
@ -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.
* 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 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);
arm.roll += cos;
arm.pitch += sin;
}
if (attributes.shouldLiftArm(leftArmPose, rightArmPose, 1)) {
if (state.attributes.shouldLiftArm(left, right, 1)) {
ModelPart arm = getArm(Arm.LEFT);
arm.roll += cos;
arm.pitch += sin;
}
}
protected void adjustBody(float pitch, Pivot pivot) {
protected void adjustBody(T state, float pitch, Pivot pivot) {
adjustBodyComponents(pitch, pivot);
if (!attributes.isHorsey) {
if (!state.attributes.isHorsey) {
neck.setPivot(NECK_X + pitch, pivot.y(), pivot.z());
rightLeg.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();
}
@Override
public float getRiderYOffset() {
switch ((SizePreset)getSize()) {
case NORMAL: return 0.4F;
case FOAL:
case TALL:
case BULKY:
default: return 0.25F;
}
}
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
neck.visible = visible;
hat.visible &= !attributes.isHorsey;
parts.forEach(part -> part.setVisible(visible, attributes));
hat.visible = false;
}
@Override
@ -553,15 +548,15 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
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;
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;
if (getAttributes().activeHand == Hand.OFF_HAND) {
Arm main = state.attributes.mainArm;
if (state.attributes.activeHand == Hand.OFF_HAND) {
main = main.getOpposite();
}
if (main == arm) {
@ -574,28 +569,28 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
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);
}
}
@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);
}
if (attributes.isSleeping || attributes.isRiptide) {
if (state.attributes.isSleeping || state.attributes.isRiptide) {
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
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);
}
if (attributes.isHorsey) {
if (state.attributes.isHorsey) {
if (part == BodyPart.BODY) {
stack.scale(1.5F, 1, 1.5F);
}
@ -605,6 +600,6 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
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.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.Hand;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.mson.api.model.biped.MsonPlayer;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.MsonModel;
/**
* 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.
*/
public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer<T> implements PonyModel<T> {
/**
* The model attributes.
*/
protected ModelAttributes attributes = new ModelAttributes();
public abstract class ClientPonyModel<T extends PonyRenderState> extends PlayerEntityModel implements MsonModel, PonyModel<T> {
@Nullable
protected PosingCallback<T> onSetModelAngles;
public ClientPonyModel(ModelPart tree) {
super(tree);
public ClientPonyModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms);
}
public void onSetModelAngles(PosingCallback<T> 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
public ModelPart getForeLeg(Arm side) {
return getArm(side);
@ -103,8 +40,8 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
}
@Override
public ArmPose getArmPoseForSide(Arm side) {
return side == Arm.RIGHT ? rightArmPose : leftArmPose;
public <S extends PlayerEntityRenderState> ArmPose getArmPoseForSide(S state, Arm side) {
return getArmPose(state, side);
}
@Override
@ -113,7 +50,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
}
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) {
@ -122,7 +59,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
}
}
public interface PosingCallback<T extends LivingEntity> {
void poseModel(ClientPonyModel<T> model, float move, float swing, float ticks, T entity);
public interface PosingCallback<S extends PonyRenderState> {
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<SkeleponyModel<?>> SKELETON = register("skeleton", 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<GuardianPonyModel> GUARDIAN = register("guardian", GuardianPonyModel::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.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.PonyModel;
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) {
super(tree);

View file

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

View file

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

View file

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

View file

@ -1,31 +1,33 @@
package com.minelittlepony.client.model.entity;
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.PillagerEntity;
import net.minecraft.util.Arm;
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) {
super(tree, false);
}
@Override
public void animateModel(T entity, float move, float swing, float ticks) {
ArmPose holdingPose = getHoldingPose(entity.getState());
protected BipedEntityModel.ArmPose getArmPose(PlayerEntityRenderState state, Arm arm) {
ArmPose holdingPose = getHoldingPose(((PillagerRenderer.State)state).state);
if (holdingPose != ArmPose.EMPTY) {
boolean rightHanded = entity.getMainArm() == Arm.RIGHT;
boolean isMain = state.mainArm == Arm.RIGHT;
leftArmPose = rightHanded ? ArmPose.EMPTY : holdingPose;
rightArmPose = rightHanded ? holdingPose : ArmPose.EMPTY;
return isMain ? holdingPose : ArmPose.EMPTY;
}
return super.getArmPose(state, arm);
}
protected ArmPose getHoldingPose(IllagerEntity.State state) {
static ArmPose getHoldingPose(IllagerEntity.State state) {
switch (state) {
case BOW_AND_ARROW: return ArmPose.BOW_AND_ARROW;
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.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.util.math.EulerAngle;
import com.minelittlepony.mson.util.PartUtil;
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) {
super(modelPart);
}
@Override
public void setAngles(ArmorStandEntity entity, float move, float swing, float ticks, float headYaw, float headPitch) {
super.setAngles(entity, move, swing, ticks, headYaw, headPitch);
public void setAngles(ArmorStandEntityRenderState state) {
super.setAngles(state);
leftArm.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);
leftLeg.pitch *= -1;
}
if (entity.getRightLegRotation().equals(DEFAULT_RIGHT_LEG_ROTATION)) {
if (state.rightLegRotation.equals(ArmorStandEntity.DEFAULT_RIGHT_LEG_ROTATION)) {
PartUtil.copyAngles(rightArm, rightLeg);
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;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.util.math.MathHelper;
public class SaddleModel<T extends LivingEntity> extends EntityModel<T> {
private ModelPart root;
public class SaddleModel<T extends LivingEntityRenderState> extends EntityModel<T> {
public SaddleModel(ModelPart tree) {
root = tree;
super(tree);
}
@Override
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) {
root.pivotY = 2 - MathHelper.cos(move * 1.5f) * 3.0f * swing;
}
@Override
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, int color) {
root.render(matrices, vertices, light, overlay, color);
public void setAngles(T entity) {
root.pivotY = 2 - MathHelper.cos(entity.limbFrequency * 1.5F) * 3 * entity.limbAmplitudeMultiplier;
}
}

View file

@ -1,86 +1,34 @@
package com.minelittlepony.client.model.entity;
import net.minecraft.entity.mob.WitherSkeletonEntity;
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.ItemStack;
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.render.entity.state.SkeletonPonyRenderState;
public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> {
public boolean isUnicorn;
public boolean isWithered;
public class SkeleponyModel<T extends SkeletonPonyRenderState> extends AlicornModel<T> {
public SkeleponyModel(ModelPart tree) {
super(tree, false);
this.vestRenderList.clear();
this.sleevesRenderList.clear();
vestRenderList.clear();
sleevesRenderList.clear();
}
@SuppressWarnings("unchecked")
@Override
public void animateModel(T entity, float move, float swing, float ticks) {
isUnicorn = entity.getUuid().getLeastSignificantBits() % 3 != 0;
isWithered = entity instanceof WitherSkeletonEntity;
protected BipedEntityModel.ArmPose getArmPose(PlayerEntityRenderState state, Arm arm) {
boolean isMain = arm == state.mainArm;
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()) {
return mainHand.getItem() == Items.BOW && ((T)state).isAttacking ? ArmPose.BOW_AND_ARROW : ArmPose.ITEM;
}
}
if (!mainHand.isEmpty()) {
ArmPose pose = mainHand.getItem() == Items.BOW && entity.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) {
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;
return super.getArmPose(state, arm);
}
}

View file

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

View file

@ -2,39 +2,23 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.WitchEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.MathHelper;
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.render.entity.WitchRenderer;
public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
public class WitchPonyModel extends EarthPonyModel<WitchRenderer.State> {
public WitchPonyModel(ModelPart tree) {
super(tree, false);
}
@Override
public void updateLivingState(WitchEntity entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode);
public void setModelAngles(WitchRenderer.State entity) {
super.setModelAngles(entity);
if (entity.hasCustomName() && "Filly".equals(entity.getCustomName().getString())) {
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()) {
if (entity.drinking) {
float noseRot = MathHelper.sin(entity.age);
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);
}
if (rightArmPose != ArmPose.EMPTY) {
float rot = (float)(Math.tan(ticks / 7) + Math.sin(ticks / 3));
if (!entity.getMainHandStack().isEmpty()) {
float rot = (float)(Math.tan(entity.age / 7) + Math.sin(entity.age / 3));
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.yaw = 0.1F;
@ -64,13 +48,8 @@ public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
}
@Override
protected void positionheldItem(Arm arm, MatrixStack matrices) {
super.positionheldItem(arm, matrices);
protected void positionheldItem(WitchRenderer.State state, Arm arm, MatrixStack matrices) {
super.positionheldItem(state, arm, matrices);
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.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart;
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;

View file

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

View file

@ -1,11 +1,11 @@
package com.minelittlepony.client.model.entity.race;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
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;
@ -15,8 +15,8 @@ public class KirinModel<T extends LivingEntity> extends UnicornModel<T> {
}
@Override
protected void adjustBody(float pitch, Pivot pivot) {
super.adjustBody(pitch, pivot);
protected void adjustBody(T state, float pitch, Pivot pivot) {
super.adjustBody(state, pitch, pivot);
beard.resetTransform();
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.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView;
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;

View file

@ -4,13 +4,14 @@ import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony;
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.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
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;
@ -60,12 +61,12 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
protected void ponySit() {}
@Override
public void setModelAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) {
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch);
protected void setModelAngles(T entity) {
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;
}
@ -75,20 +76,20 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
rightFin.yaw = -finAngle;
centerFin.roll = flapMotion;
if (!entity.isSubmergedInWater()) {
if (!entity.submergedInWater) {
leftArm.pitch -= 0.5F;
rightArm.pitch -= 0.5F;
}
if (!entity.isSubmergedInWater() || entity.isOnGround()) {
if (!entity.submergedInWater || entity.onGround) {
leftArm.yaw -= 0.5F;
rightArm.yaw += 0.5F;
}
}
@Override
protected void rotateLegs(float move, float swing, float ticks, T entity) {
super.rotateLegs(move, swing, ticks, entity);
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(state, move, swing, ticks, entity);
leftArm.pitch -= 1.4F;
leftArm.yaw -= 0.3F;
rightArm.pitch -= 1.4F;
@ -96,8 +97,8 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
}
@Override
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(move, swing, ticks, entity);
protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(state, move, swing, ticks, entity);
}
@Override
@ -114,7 +115,7 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
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) {
super(tree);
@ -131,14 +132,13 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
}
@Override
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(move, swing, ticks, entity);
protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(state, move, swing, ticks, entity);
}
@Override
public void transform(BodyPart part, MatrixStack stack) {
stack.translate(0, 0.6F, 0);
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.SizePreset;
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.util.RenderList;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.consume.UseAction;
import net.minecraft.registry.Registries;
import net.minecraft.util.*;
/**
* 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 unicornArmLeft;
@ -34,20 +36,20 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
public void init(ModelView context) {
super.init(context);
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) -> {
horn.renderMagic(stack, vertices, getAttributes().metadata.glowColor());
})).checked(() -> hasMagic() && isCasting()));
horn.renderMagic(stack, vertices, currentState.attributes.metadata.glowColor());
})).checked(() -> hasMagic(currentState) && isCasting(currentState)));
}
@Override
public float getWobbleAmount() {
return isCasting() ? 0 : super.getWobbleAmount();
return isCasting(currentState) ? 0 : super.getWobbleAmount();
}
@Override
protected void rotateLegs(float move, float swing, float ticks, T entity) {
super.rotateLegs(move, swing, ticks, entity);
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(state, move, swing, ticks, entity);
unicornArmRight.setAngles(0, 0, 0);
unicornArmRight.setPivot(-7, 12, -2);
@ -57,31 +59,30 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
}
@Override
public boolean isCasting() {
return PonyConfig.getInstance().tpsmagic.get()
&& (rightArmPose != ArmPose.EMPTY || leftArmPose != ArmPose.EMPTY);
public boolean isCasting(T state) {
return PonyConfig.getInstance().tpsmagic.get() && (!state.leftHandStack.isEmpty() || !state.rightHandStack.isEmpty());
}
@Override
protected void ponyCrouch() {
super.ponyCrouch();
protected void ponyCrouch(T state) {
super.ponyCrouch(state);
unicornArmRight.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT;
unicornArmLeft.pitch -= LEG_SNEAKING_PITCH_ADJUSTMENT;
}
@Override
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 super.getArm(side);
}
@Override
protected void positionheldItem(Arm arm, MatrixStack matrices) {
super.positionheldItem(arm, matrices);
protected void positionheldItem(T state, Arm arm, MatrixStack matrices) {
super.positionheldItem(state, arm, matrices);
if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic()) {
if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic(state)) {
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);
UseAction action = getAttributes().heldStack.getUseAction();
UseAction action = state.attributes.heldStack.getUseAction();
boolean shouldAimItem =
(action == UseAction.SPYGLASS || action == UseAction.BOW) && getAttributes().itemUseTime > 0
|| PonyConfig.getInstance().forwardHoldingItems.get().contains(Registries.ITEM.getId(getAttributes().heldStack.getItem()));
(action == UseAction.SPYGLASS || action == UseAction.BOW) && state.attributes.itemUseTime > 0
|| PonyConfig.getInstance().forwardHoldingItems.get().contains(Registries.ITEM.getId(state.attributes.heldStack.getItem()));
if (shouldAimItem) {
Arm main = getAttributes().mainArm;
if (getAttributes().activeHand == Hand.OFF_HAND) {
Arm main = state.attributes.mainArm;
if (state.attributes.activeHand == Hand.OFF_HAND) {
main = main.getOpposite();
}
if (main == arm) {
if (action == UseAction.SPYGLASS) {
Size size = getSize();
Size size = state.getSize();
float x = 0.3F;
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.WorldRenderer;
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.entity.LivingEntity;
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.pony.Pony;
import com.minelittlepony.client.PonyBounds;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
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) {
return;
}
MinecraftClient client = MinecraftClient.getInstance();
if (!client.getEntityRenderDispatcher().shouldRenderHitboxes() || entity.isInvisible() || client.hasReducedDebugInfo()) {
if (!client.getEntityRenderDispatcher().shouldRenderHitboxes() || state.invisible || client.hasReducedDebugInfo()) {
return;
}
Vec3d offset = renderer.getPositionOffset(entity, tickDelta);
Vec3d offset = state.positionOffset;
stack.push();
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);
double y = - MathHelper.lerp(tickDelta, entity.lastRenderY, pos.y);
double z = - MathHelper.lerp(tickDelta, entity.lastRenderZ, pos.z);
VertexConsumer vertices = renderContext.getBuffer(RenderLayer.getLines());
VertexConsumer vertices = matrices.getBuffer(RenderLayer.getLines());
WorldRenderer.drawBox(stack, vertices, boundingBox.offset(x, y, z), 1, 1, 0, 1);
stack.pop();

View file

@ -7,6 +7,7 @@ import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.client.PonyDataLoader;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.transform.PonyPosture;
import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.util.MathUtil;
@ -20,20 +21,26 @@ import net.fabricmc.api.EnvType;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Frustum;
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.entity.EntityPose;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
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;
@Nullable
private Function<T, Models<T, M>> modelsLookup;
private Function<S, Models<T, M>> modelsLookup;
private final PonyRenderContext<T, M> context;
private final Transformer<T> transformer;
private final PonyRenderContext<T, S, M> context;
private final Transformer<? super S> transformer;
private final FrustrumCheck<T> frustrum;
@ -41,7 +48,7 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
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.transformer = transformer;
this.models = models;
@ -50,11 +57,11 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
}
@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));
}
public void setModelsLookup(@Nullable Function<T, Models<T, M>> modelsLookup) {
public void setModelsLookup(@Nullable Function<S, Models<T, M>> modelsLookup) {
this.modelsLookup = modelsLookup;
}
@ -73,78 +80,40 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
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);
if (modelsLookup != null) {
models = modelsLookup.apply(entity);
models = modelsLookup.apply(state);
context.setModel(models.body());
}
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) {
float s = getScaleFactor();
public void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw) {
float s = state.getScaleFactor();
stack.scale(s, s, s);
if (entity instanceof PlayerEntity) {
if (getModels().body().getAttributes().isSitting) {
if (state instanceof PlayerEntityRenderState) {
if (state.attributes.isSitting) {
stack.translate(0, 0.125D, 0);
}
}
bodyYaw = getMountedYaw(entity, bodyYaw, tickDelta);
transformer.setupTransforms(entity, stack, animationProgress, bodyYaw, tickDelta, scale);
transformer.setupTransforms(state, stack, animationProgress, bodyYaw);
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) {
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity mount) {
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 Transformer<S extends BipedEntityRenderState> {
void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw);
}
public interface RegistrationHandler {
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);
}

View file

@ -19,9 +19,9 @@ public class FrustrumCheck<T extends LivingEntity> extends Frustum {
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());
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.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.util.*;
import com.mojang.blaze3d.systems.RenderSystem;
import com.google.common.base.Suppliers;
@ -62,7 +61,7 @@ public abstract class MagicGlow extends RenderPhase {
private final float alpha;
public Colored(Identifier texture, int color) {
super(texture, false, false);
super(texture, TriState.FALSE, false);
this.red = Color.r(color);
this.green = Color.g(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.gear.Gear;
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.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);
EquineRenderManager<T, M> getInternalRenderer();
EquineRenderManager<T, S, M> getInternalRenderer();
void setModel(M model);
}

View file

@ -8,6 +8,7 @@ import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.mixin.MixinEntityRenderers;
import com.minelittlepony.client.render.entity.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import org.jetbrains.annotations.Nullable;
@ -16,6 +17,7 @@ import com.minelittlepony.mson.api.Mson;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.entity.*;
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.entity.Entity;
import net.minecraft.entity.EntityType;
@ -69,7 +71,7 @@ public class PonyRenderDispatcher {
* @param factory The replacement value
* @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()
? factory.apply(ctx)
: MixinEntityRenderers.getRendererFactories().get(type).create(ctx)
@ -78,7 +80,7 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked")
@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) {
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.entity.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelKey;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.*;
import net.minecraft.client.MinecraftClient;
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.feature.FeatureRenderer;
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.entity.mob.MobEntity;
import net.minecraft.text.Text;
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 TextureSupplier<T> texture;
private final TextureSupplier<S> texture;
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);
this.manager = new EquineRenderManager<>(this, super::setupTransforms, key);
this.manager = new EquineRenderManager<T, S, M>(this, super::setupTransforms, key);
this.texture = texture;
this.scale = scale;
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) {
addFeature(new ArmourFeature<>(this, context.getModelManager()));
addFeature(createHeldItemFeature(context));
@ -54,47 +66,48 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
addFeature(new GearFeature<>(this));
}
protected HeldItemFeature<T, M> createHeldItemFeature(EntityRendererFactory.Context context) {
return new HeldItemFeature<>(this, context.getHeldItemRenderer());
@SuppressWarnings({"unchecked", "rawtypes"})
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
public final Identifier getTexture(T entity) {
public final Identifier getTexture(S entity) {
return texture.apply(entity);
}
@Override
public void render(T entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
if (manager.getModels().body() instanceof BipedEntityModel model) {
model.setVisible(true);
}
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
public void render(S state, MatrixStack stack, VertexConsumerProvider vertices, int light) {
super.render(state, stack, vertices, light);
DebugBoundingBoxRenderer.render(getEntityPony(state), this, state, stack, vertices);
}
@Override
protected void setupTransforms(T entity, MatrixStack stack, float animationProgress, float bodyYaw, float tickDelta, float scale) {
manager.setupTransforms(entity, stack, animationProgress, bodyYaw, tickDelta, scale);
protected void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw) {
manager.setupTransforms(state, stack, animationProgress, bodyYaw);
}
@Override
public boolean shouldRender(T entity, Frustum visibleRegion, double camX, double camY, double camZ) {
return super.shouldRender(entity, manager.getFrustrum(entity, visibleRegion), camX, camY, camZ);
public boolean shouldRender(T state, Frustum visibleRegion, double camX, double camY, double camZ) {
return super.shouldRender(state, manager.getFrustrum(state, visibleRegion), camX, camY, camZ);
}
@Override
public void scale(T entity, MatrixStack stack, float tickDelta) {
shadowRadius = manager.getShadowSize();
public void scale(S state, MatrixStack stack) {
shadowRadius = state.getShadowSize();
if (entity.isBaby()) {
if (state.baby) {
shadowRadius *= 3; // undo vanilla shadow scaling
}
if (!entity.hasVehicle()) {
stack.translate(0, 0, -entity.getWidth() / 2); // move us to the center of the shadow
if (!state.hasVehicle) {
stack.translate(0, 0, -state.width / 2); // move us to the center of the shadow
} else {
if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) {
if (state.attributes.isSitting && state.hasVehicle) {
stack.translate(0, 0.25F, 0);
}
}
@ -103,17 +116,17 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
}
@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.translate(0, manager.getNamePlateYOffset(entity), 0);
super.renderLabelIfPresent(entity, name, matrices, vertices, light, tickDelta);
matrices.translate(0, state.nameplateYOffset, 0);
super.renderLabelIfPresent(state, name, matrices, vertices, light);
matrices.pop();
}
@Override
public Identifier getDefaultTexture(T entity, Wearable wearable) {
public Identifier getDefaultTexture(S state, Wearable wearable) {
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()) {
return texture;
@ -128,7 +141,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
}
@Override
public EquineRenderManager<T, M> getInternalRenderer() {
public EquineRenderManager<T, S, M> getInternalRenderer() {
return manager;
}
@ -137,25 +150,39 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends 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) {
renderer.addFeature(featureFactory.apply(renderer));
return renderer;
}
@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,
List exportedLayers, Consumer<M> modelConsumer) {
var renderer = new AbstractPonyRenderer<T, M>(context, key, texture, scale) {
public static <
T extends MobEntity,
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
protected void addFeatures(EntityRendererFactory.Context context) {
features.clear();
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;
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.model.ModelType;
import com.minelittlepony.client.model.entity.EnderStallionModel;
import com.minelittlepony.client.render.entity.feature.GlowingEyesFeature;
import com.minelittlepony.client.render.entity.feature.HeldItemFeature;
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 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.feature.StuckArrowsFeatureRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.EndermanEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
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");
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));
}
@Override
public State createRenderState() {
return new State();
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
protected void addFeatures(EntityRendererFactory.Context context) {
addFeature(createHeldItemFeature(context));
addFeature(new StuckArrowsFeatureRenderer<>(context, this));
addFeature(new GlowingEyesFeature<>(this));
addPonyFeature(createHeldItemFeature(context));
addPonyFeature(new StuckArrowsFeatureRenderer<EnderStallionModel>((PonyRenderer)this, context));
addPonyFeature(new GlowingEyesFeature<EnderStallionRenderer.State, EnderStallionModel>(this));
}
@Override
protected HeldItemFeature<EndermanEntity, EnderStallionModel> createHeldItemFeature(EntityRendererFactory.Context context) {
return new HeldItemFeature<EndermanEntity, EnderStallionModel>(this, context.getHeldItemRenderer()) {
@Override
protected ItemStack getRightItem(EndermanEntity entity) {
BlockState state = entity.getCarriedBlock();
if (state == null) {
return ItemStack.EMPTY;
}
return new ItemStack(state.getBlock().asItem());
}
};
protected HeldItemFeature<State, EnderStallionModel> createHeldItemFeature(EntityRendererFactory.Context context) {
return new HeldItemFeature<State, EnderStallionModel>(this, context.getItemRenderer());
}
@Override
public void render(EndermanEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
model.isCarrying = entity.getCarriedBlock() != null;
model.isAttacking = entity.isAngry();
if (entity.isAngry()) {
stack.translate(rnd.nextGaussian() / 50, 0, rnd.nextGaussian() / 50);
public void render(State entity, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
if (entity.angry) {
matrices.translate(rnd.nextGaussian() / 50, 0, rnd.nextGaussian() / 50);
}
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
super.render(entity, matrices, vertices, light);
}
@Override
public Identifier getEyeTexture() {
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.PonyRenderContext;
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 java.util.*;
@ -24,19 +26,26 @@ import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.PlayerEntityRenderer;
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.entity.EntityPose;
import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.util.math.Vec3d;
public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> {
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>>> modelsCache;
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager;
public class PlayerPonyRenderer
extends PlayerEntityRenderer
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) {
super(context, slim);
modelsCache = Util.memoize(race -> ModelType.getPlayerModel(race).create(slim));
manager = new EquineRenderManager<>(this, super::setupTransforms, modelsCache.apply(Race.EARTH));
manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity, getEntityPony(entity))));
manager.setModelsLookup(entity -> modelsCache.apply(getPlayerRace(entity)));
addPonyFeatures(context);
}
@ -53,7 +62,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
|| feature instanceof ShoulderParrotFeatureRenderer;
});
addPonyFeature(new ArmourFeature<>(this, context.getModelManager()));
addPonyFeature(new HeldItemFeature(this, context.getHeldItemRenderer()));
addPonyFeature(new HeldItemFeature(this, context.getItemRenderer()));
addPonyFeature(new DJPon3Feature<>(this));
addPonyFeature(new CapeFeature<>(this));
addPonyFeature(new SkullFeature<>(this, context.getModelLoader(), context.getItemRenderer()));
@ -63,29 +72,41 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
}
@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);
}
public Vec3d getPositionOffset(PlayerEntityRenderState state) {
Vec3d offset = super.getPositionOffset(state);
return offset.multiply(((PonyRenderState)state).getScaleFactor());
}
@Override
protected void scale(AbstractClientPlayerEntity entity, MatrixStack stack, float tickDelta) {
if (manager.getModels().body().getAttributes().isSitting && entity.hasVehicle()) {
stack.translate(0, -0.25F * manager.getScaleFactor(), 0);
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;
}
super.scale(entity, stack, tickDelta);
}
protected void preRender(AbstractClientPlayerEntity player, ModelAttributes.Mode mode) {
manager.preRender(player, mode);
}
@Override
public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
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
preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
shadowRadius = manager.getShadowSize();
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(getEntityPony(entity), this, entity, stack, renderContext, tickDelta);
shadowRadius = ((PlayerPonyRenderState)state).getShadowSize();
super.render(state, stack, vertices, light);
DebugBoundingBoxRenderer.render((PlayerPonyRenderState)state, stack, vertices);
// Translate the shadow position after everything is done
// (shadows are drawn after us)
@ -102,13 +123,13 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
}
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
return pony.race();
protected Race getPlayerRace(PlayerPonyRenderState state) {
return state.getRace();
}
@Override
protected void setupTransforms(AbstractClientPlayerEntity entity, MatrixStack matrices, float animationProgress, float bodyYaw, float tickDelta, float scale) {
manager.setupTransforms(entity, matrices, animationProgress, bodyYaw, tickDelta, scale);
protected void setupTransforms(PlayerEntityRenderState state, MatrixStack matrices, float animationProgress, float bodyYaw) {
manager.setupTransforms((PlayerPonyRenderState)state, matrices, animationProgress, bodyYaw);
}
@Override
@ -121,71 +142,61 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
}
@Override
protected void renderLabelIfPresent(AbstractClientPlayerEntity entity, Text name, MatrixStack stack, VertexConsumerProvider renderContext, int light, float tickDelta) {
stack.push();
protected void renderLabelIfPresent(PlayerEntityRenderState state, Text name, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
matrices.push();
if (state.isInPose(EntityPose.SLEEPING)) {
if (state.sleepingDirection != null && ((PlayerPonyRenderState)state).sleepingInBed) {
double bedRad = Math.toRadians(state.sleepingDirection.asRotation());
if (entity.isSleeping()) {
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));
matrices.translate(Math.cos(bedRad), 0, -Math.sin(bedRad));
}
}
stack.translate(0, manager.getNamePlateYOffset(entity), 0);
super.renderLabelIfPresent(entity, name, stack, renderContext, light, tickDelta);
stack.pop();
matrices.translate(0, ((PlayerPonyRenderState)state).nameplateYOffset, 0);
super.renderLabelIfPresent(state, name, matrices, vertices, light);
matrices.pop();
}
@Override
public final void renderRightArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player) {
renderArm(stack, renderContext, lightUv, player, Arm.RIGHT);
public final void renderRightArm(MatrixStack matrices, VertexConsumerProvider vertices, int light, Identifier skinTexture, boolean sleeveVisible) {
renderArm(matrices, vertices, light, skinTexture, sleeveVisible, Arm.RIGHT);
}
@Override
public final void renderLeftArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player) {
renderArm(stack, renderContext, lightUv, player, Arm.LEFT);
public final void renderLeftArm(MatrixStack matrices, VertexConsumerProvider vertices, int light, Identifier skinTexture, boolean sleeveVisible) {
renderArm(matrices, vertices, light, skinTexture, sleeveVisible, Arm.LEFT);
}
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
preRender(player, ModelAttributes.Mode.FIRST_PERSON);
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int light, Identifier skinTexture, boolean sleeveVisible, Arm side) {
stack.push();
float reflect = side == Arm.LEFT ? 1 : -1;
stack.translate(reflect * 0.1F, -0.54F, 0);
Identifier texture = getTexture(player);
Identifier playerSkin = player.getSkinTextures().texture();
VertexConsumerProvider interceptedContext = layer -> {
return renderContext.getBuffer(RenderLayerUtil
.getTexture(layer)
.filter(playerSkin::equals)
.map(i -> RenderLayer.getEntityTranslucent(texture))
.filter(skinTexture::equals)
.map(i -> RenderLayer.getEntityTranslucent(skinTexture))
.orElse(layer)
);
};
if (side == Arm.LEFT) {
super.renderLeftArm(stack, interceptedContext, lightUv, player);
super.renderLeftArm(stack, interceptedContext, light, skinTexture, sleeveVisible);
} else {
super.renderRightArm(stack, interceptedContext, lightUv, player);
super.renderRightArm(stack, interceptedContext, light, skinTexture, sleeveVisible);
}
stack.pop();
}
@Override
public Identifier getTexture(AbstractClientPlayerEntity player) {
return getEntityPony(player).texture();
}
@Override
public void setModel(ClientPonyModel<AbstractClientPlayerEntity> model) {
public void setModel(ClientPonyModel<PlayerPonyRenderState> model) {
this.model = model;
}
@Override
public EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> getInternalRenderer() {
public EquineRenderManager<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> getInternalRenderer() {
return manager;
}
@ -195,13 +206,20 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRend
}
@Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) {
return SkinsProxy.getInstance().getSkin(wearable.getId(), entity).orElseGet(() -> {
if (wearable.isSaddlebags() && getInternalRenderer().getModels().body().getRace().supportsLegacySaddlebags()) {
return getTexture(entity);
}
public Identifier getTexture(PlayerEntityRenderState state) {
return ((PonyRenderState)state).pony.texture();
}
return wearable.getDefaultTexture();
});
@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();
}
}

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

View file

@ -1,16 +1,19 @@
package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.mob.AbstractPiglinEntity;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.client.render.entity.state.PiglinEntityRenderState;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.mob.*;
import net.minecraft.item.CrossbowItem;
import net.minecraft.util.Identifier;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.PiglinPonyModel;
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_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");
@ -32,7 +35,24 @@ public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PiglinPonyMo
}
@Override
protected boolean isShaking(HostileEntity entity) {
return entity instanceof AbstractPiglinEntity && ((AbstractPiglinEntity)entity).shouldZombify();
public State createRenderState() {
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.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelKey;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.feature.StuckArrowsFeatureRenderer;
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;
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);
}
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);
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
protected void addFeatures(EntityRendererFactory.Context 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;
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.model.ModelType;
import com.minelittlepony.client.model.entity.WitchPonyModel;
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.entity.LivingEntity;
import net.minecraft.entity.mob.WitchEntity;
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");
public WitchRenderer(EntityRendererFactory.Context context) {
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 com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
// 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);
renderer = render;
}
@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();
renderer.getModel().copyStateTo(overlayModel);
overlayModel.animateModel(entity, limbDistance, limbAngle, tickDelta);
overlayModel.setAngles(entity, limbDistance, limbAngle, age, headYaw, headPitch);
VertexConsumer vertexConsumer = renderContext.getBuffer(overlayModel.getLayer(getOverlayTexture()));
overlayModel.render(stack, vertexConsumer, lightUv, OverlayTexture.DEFAULT_UV, Colors.WHITE);
overlayModel.setAngles(state);
VertexConsumer buffer = vertices.getBuffer(overlayModel.getLayer(getOverlayTexture()));
overlayModel.render(matrices, buffer, light, OverlayTexture.DEFAULT_UV, Colors.WHITE);
}
protected abstract M getOverlayModel();
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.PonyModel;
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.FeatureRendererContext;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
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")
public AbstractPonyFeature(PonyRenderContext<T, M> context) {
super((FeatureRendererContext<T, M>)context);
public AbstractPonyFeature(PonyRenderContext<?, S, M> context) {
super((FeatureRendererContext<S, M>)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")
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;
}
@ -48,7 +33,7 @@ public abstract class AbstractPonyFeature<T extends LivingEntity, M extends Enti
return context.getInternalRenderer().getModels().body();
}
protected Models<T, M> getModelWrapper() {
protected Models<?, M> getModelWrapper() {
return context.getInternalRenderer().getModels();
}
}

View file

@ -10,6 +10,7 @@ import java.util.*;
import net.minecraft.client.render.*;
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.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
@ -19,19 +20,19 @@ import net.minecraft.item.*;
import net.minecraft.item.trim.ArmorTrim;
import net.minecraft.util.Colors;
public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
public ArmourFeature(PonyRenderContext<T, M> context, BakedModelManager bakery) {
public class ArmourFeature<T extends LivingEntity, S extends BipedEntityRenderState, M extends EntityModel<? super S> & PonyModel<S>> extends AbstractPonyFeature<S, M> {
public ArmourFeature(PonyRenderContext<T, S, M> context, BakedModelManager bakery) {
super(context);
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch);
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, S entity, float limbDistance, float limbAngle) {
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle);
}
public static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor(
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, T entity,
public static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, S entity,
float limbDistance, float limbAngle,
float age, float headYaw, float headPitch) {
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(
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, T entity,
private static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, S entity,
float limbDistance, float limbAngle,
float age, float headYaw, float headPitch,
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.client.model.DJPon3EarsModel;
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();
public DJPon3Feature(PonyRenderContext<T, M> context) {
public DJPon3Feature(PonyRenderContext<T, S, M> context) {
super(context);
}
@Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
if ("deadmau5".equals(entity.getName().getString())) {
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, S state, float limbAngle, float limbDistance) {
if ("deadmau5".equals(state.name)) {
stack.push();
M body = getModelWrapper().body();
body.transform(BodyPart.HEAD, stack);
body.transform(state, BodyPart.HEAD, stack);
body.getHead().rotate(stack);
stack.scale(1.3333334F, 1.3333334F, 1.3333334F);
@ -37,7 +42,7 @@ public class DJPon3Feature<T extends AbstractClientPlayerEntity, M extends Entit
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);

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.ArmourRendererPlugin;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
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.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
@ -23,17 +25,21 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Colors;
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 final PonyElytra<T> model = ModelType.ELYTRA.createModel();
public ElytraFeature(PonyRenderContext<T, M> context) {
public ElytraFeature(PonyRenderContext<T, S, M> context) {
super(context);
}
@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();
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();
preRenderCallback(matrices);
getContextModel().copyStateTo(model);
model.isSneaking = PonyPosture.isCrouching(getContext().getEntityPony(entity), entity);
model.setAngles(entity, limbDistance, limbAngle, age, headYaw, headPitch);
model.setAngles(entity);
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, (Colors.WHITE & 0xFFFFFF) | (int)(alpha * 255) << 24);
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);
}
protected void preRenderCallback(MatrixStack stack) {
protected void preRenderCallback(S state, MatrixStack stack) {
M body = getModelWrapper().body();
stack.translate(0, body.getRiderYOffset(), 0.125);
body.transform(BodyPart.BODY, stack);
stack.translate(0, state.riderOffset, 0.125);
body.transform(state, BodyPart.BODY, stack);
}
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.client.render.*;
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.entity.EquipmentSlot;
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.ArmourRendererPlugin;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.*;
import java.util.concurrent.TimeUnit;
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(
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;
}));
public GearFeature(PonyRenderContext<T, M> renderer) {
public GearFeature(PonyRenderContext<T, S, M> renderer) {
super(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 (entity.isInvisible()) {
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, S entity, float limbAngle, float limbDistance) {
if (entity.invisible) {
return;
}
@ -89,7 +95,7 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & Pony
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();
}
}

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.FeatureRendererContext;
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 com.minelittlepony.api.model.PonyModel;
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;
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);
layer = RenderLayer.getEyes(renderer.getEyeTexture());
}

View file

@ -1,62 +1,53 @@
package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.*;
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.FeatureRendererContext;
import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.item.HeldItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
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<T, M> context, HeldItemRenderer renderer) {
super((FeatureRendererContext<T, M>)context, renderer);
public HeldItemFeature(PonyRenderContext<?, S, M> context, ItemRenderer renderer) {
super((FeatureRendererContext<PlayerEntityRenderState, M>)context, renderer);
this.context = context;
}
protected ItemStack getLeftItem(T entity) {
boolean main = entity.getMainArm() == Arm.LEFT;
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
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);
protected ItemStack getRightItem(T entity) {
boolean main = entity.getMainArm() == Arm.RIGHT;
ModelAttributes attributes = ((PonyModel.AttributedHolder)state).getAttributes();
return main ? entity.getMainHandStack() : entity.getOffHandStack();
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();
}
}
@Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
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();
}
public final void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
render(matrices, vertices, light, (S)state, limbAngle, limbDistance);
}
}

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;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.ParrotEntityRenderer;
import net.minecraft.client.render.entity.model.EntityModelLayers;
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.util.math.RotationAxis;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.passive.ParrotEntity;
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.client.model.ClientPonyModel;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.Optional;
public class PassengerFeature<T extends PlayerEntity, M extends ClientPonyModel<T>> extends AbstractPonyFeature<T, M> {
public class PassengerFeature<
T extends PlayerEntity,
S extends PonyRenderState,
M extends ClientPonyModel<S>
> extends AbstractPonyFeature<S, M> {
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);
model = new ParrotEntityModel(context.getPart(EntityModelLayers.PARROT));
parrotState.parrotPose = ParrotEntityModel.Pose.ON_SHOULDER;
}
@Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
getShoulderParrot(entity.getShoulderEntityLeft()).ifPresent(texture -> {
renderShoulderParrot(stack, renderContext, light, entity, limbDistance, limbAngle, headYaw, headPitch, texture, 1);
});
getShoulderParrot(entity.getShoulderEntityRight()).ifPresent(texture -> {
renderShoulderParrot(stack, renderContext, light, entity, limbDistance, limbAngle, headYaw, headPitch, texture, -1);
});
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, S state, float limbAngle, float limbDistance) {
if (state.leftShoulderParrotVariant != null) {
render(matrices, vertices, light, state, state.leftShoulderParrotVariant, limbAngle, limbDistance, true);
}
if (state.rightShoulderParrotVariant != null) {
render(matrices, vertices, light, state, state.rightShoulderParrotVariant, limbAngle, limbDistance, false);
}
}
private Optional<Identifier> getShoulderParrot(NbtCompound tag) {
return EntityType.get(tag.getString("id"))
.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) {
stack.push();
getContextModel().transform(BodyPart.BODY, stack);
stack.translate(
sigma * 0.25,
entity.isInSneakingPose() ? -0.9 : -1.2,
0.45);
stack.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(sigma * -5));
VertexConsumer buffer = renderContext.getBuffer(model.getLayer(texture));
model.poseOnShoulder(stack, buffer, light, OverlayTexture.DEFAULT_UV, limbDistance, limbAngle, headYaw, headPitch, entity.age);
stack.pop();
private void render(
MatrixStack matrices,
VertexConsumerProvider vertexConsumers,
int light,
S state,
ParrotEntity.Variant parrotVariant,
float headYaw,
float headPitch,
boolean left
) {
matrices.push();
getContextModel().transform(state, BodyPart.BACK, matrices);
matrices.translate(
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.render.PonyRenderContext;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.EntityModelLoader;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
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.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.ZombieVillagerEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.*;
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;
public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) {
public SkullFeature(PonyRenderContext<T, S, M> renderPony, EntityModelLoader entityModelLoader, ItemRenderer itemRenderer) {
super(renderPony);
this.itemRenderer = itemRenderer;
}
@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();
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()) {
continue;
}
@ -46,16 +47,16 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
matrices.push();
if (entity.isBaby() && !(entity instanceof VillagerEntity)) {
if (state.baby && !(state instanceof VillagerEntity)) {
matrices.translate(0, 0.03125F, 0);
matrices.scale(0.7F, 0.7F, 0.7F);
matrices.translate(0, 1, 0);
}
model.transform(BodyPart.HEAD, matrices);
model.transform(state, BodyPart.HEAD, 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;
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.translate(0, -0.1F, 0.1F);
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) {
matrices.translate(0, 0.1F, -0.1F);
HeadFeatureRenderer.translate(matrices, isVillager);
itemRenderer.renderItem(entity, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal());
itemRenderer.renderItem(state, stack, ModelTransformationMode.HEAD, false, matrices, provider, entity.getWorld(), light, OverlayTexture.DEFAULT_UV, entity.getId() + ModelTransformationMode.HEAD.ordinal());
}
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.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.npc.textures.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.function.Function;
abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer> extends PonyRenderer<T, ClientPonyModel<T>> {
private final NpcClothingFeature<T, ClientPonyModel<T>, AbstractNpcRenderer<T>> clothing;
private final Function<Race, Models<T, ClientPonyModel<T>>> models = Util.memoize(race -> {
abstract class AbstractNpcRenderer<
T extends MobEntity & VillagerDataContainer,
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()) {
race = Race.EARTH;
}
@ -34,7 +38,7 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
}
@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) {
VillagerProfession profession = entity.getVillagerData().getProfession();
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);
}
protected void initializeModel(ClientPonyModel<T> model) {
protected void initializeModel(ClientPonyModel<S> model) {
}
@Override
public Identifier getDefaultTexture(T villager, Wearable wearable) {
public Identifier getDefaultTexture(S villager, Wearable wearable) {
if (wearable.isSaddlebags()) {
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.render.PonyRenderContext;
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.util.ResourceUtil;
@ -26,8 +27,9 @@ import java.util.*;
class NpcClothingFeature<
T extends LivingEntity & VillagerDataContainer,
M extends EntityModel<T> & PonyModel<T>,
C extends FeatureRendererContext<T, M> & PonyRenderContext<T, M>> extends AbstractPonyFeature<T, M> {
S extends PonyRenderState,
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 -> {
a.put(1, Identifier.ofVanilla("stone"));
@ -46,22 +48,22 @@ class NpcClothingFeature<
}
@Override
public void render(MatrixStack matrixStack, VertexConsumerProvider provider, int i, T entity, float f, float g, float h, float j, float k, float l) {
if (entity.isInvisible()) {
public void render(MatrixStack matrixStack, VertexConsumerProvider provider, int light, S entity, float limbAngle, float limbDistance) {
if (entity.invisible) {
return;
}
VillagerData data = entity.getVillagerData();
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()));
if (!ResourceUtil.textureExists(typeSkin)) {
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 {
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;
import net.minecraft.client.render.VertexConsumerProvider;
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.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.model.ModelType;
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.state.PonyRenderState;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.PonyRenderer;
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");
public PillagerRenderer(EntityRendererFactory.Context context) {
@ -20,7 +30,43 @@ public class PillagerRenderer extends PonyRenderer<PillagerEntity, PillagerPonyM
}
@Override
protected HeldItemFeature<PillagerEntity, PillagerPonyModel<PillagerEntity>> createHeldItemFeature(EntityRendererFactory.Context context) {
return new IllagerHeldItemFeature<>(this, context.getHeldItemRenderer());
protected HeldItemFeature<PillagerRenderer.State, PillagerPonyModel> createHeldItemFeature(EntityRendererFactory.Context context) {
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.render.entity.PonyRenderer;
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 TraderRenderer(EntityRendererFactory.Context context) {
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
if (player instanceof PlayerEntity) {
float leaningPitch = player.getLeaningPitch(tickDelta);
if (player.isFallFlying()) {
if (player.isGliding()) {
if (RenderPass.getCurrent() == RenderPass.GUI) {
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);
if (!player.isUsingRiptide()) {
stack.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(targetRoll * (-90 - player.getPitch())));

View file

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