WIP update to 1.21.3

This commit is contained in:
Sollace 2024-11-21 14:31:26 +00:00
parent 1b5a46b716
commit 2035985c2f
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
90 changed files with 1447 additions and 1485 deletions

View file

@ -1,17 +1,15 @@
package com.minelittlepony.api.model;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
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(T state) {
return state.getRace().hasHorn() && state.attributes.metadata.glowColor() != 0;
}
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.client.render.entity.state.*;
import net.minecraft.util.Arm;
public interface HornedPonyModel<T extends EntityRenderState & PonyModel.AttributedHolder> extends PonyModel<T> {
/**
* Returns true if this model is currently using magic (horn is lit).
*/
boolean isCasting(T state);
default boolean isCasting(T state) {
return state instanceof PlayerEntityRenderState s
&& (getArmPoseForSide(s, Arm.LEFT) != ArmPose.EMPTY || getArmPoseForSide(s, Arm.RIGHT) != ArmPose.EMPTY);
}
}

View file

@ -30,26 +30,25 @@ public final class MobPosingHelper {
arm.roll = cos;
}
public static void rotateUndeadArms(PonyModel<?> model, float move, float ticks) {
ModelPart leftArm = model.getForeLeg(Arm.LEFT);
public static void rotateUndeadArms(PonyModel.AttributedHolder attributes, PonyModel<?> model, float limbAngle, float ticks) {
if (islookAngleRight(limbAngle)) {
ModelPart rightArm = model.getForeLeg(Arm.RIGHT);
if (islookAngleRight(move)) {
rotateArmHolding(rightArm, 1, model.getSwingAmount(), ticks);
if (model.getAttributes().isSitting) {
rotateArmHolding(rightArm, 1, attributes.getSwingAmount(), ticks);
if (attributes.getAttributes().isSitting) {
rightArm.pitch += 0.6F;
}
PartUtil.shift(rightArm, 0.5F, 1.5F, 3);
} else {
rotateArmHolding(leftArm, -1, model.getSwingAmount(), ticks);
if (model.getAttributes().isSitting) {
ModelPart leftArm = model.getForeLeg(Arm.LEFT);
rotateArmHolding(leftArm, -1, attributes.getSwingAmount(), ticks);
if (attributes.getAttributes().isSitting) {
leftArm.pitch += 0.6F;
}
PartUtil.shift(leftArm, -0.5F, 1.5F, 3);
}
}
public static boolean islookAngleRight(float move) {
return MathHelper.sin(move / 20) < 0;
public static boolean islookAngleRight(float limbAngle) {
return MathHelper.sin(limbAngle / 20) < 0;
}
}

View file

@ -186,6 +186,10 @@ public class ModelAttributes {
return Interpolator.linear(interpolatorId);
}
public UUID getEntityId() {
return interpolatorId;
}
public boolean shouldLiftArm(ArmPose pose, ArmPose complement, float sigma) {
return pose != ArmPose.EMPTY
&& (pose != complement || sigma == (isLeftHanded ? 1 : -1))

View file

@ -1,57 +1,40 @@
package com.minelittlepony.api.model;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.client.model.PlayerModelKey;
import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.mson.api.ModelKey;
import com.minelittlepony.mson.api.MsonModel;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Container class for the various models and their associated piece of armour.
*/
public class Models<T extends LivingEntity, M extends PonyModel<?>> {
@Nullable
private final MsonModel.Factory<PonyArmourModel<T>> armorFactory;
private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>();
public record Models<M extends PonyModel<?>> (
Function<ModelKey<PonyArmourModel<?>>, PonyArmourModel<?>> armor,
M body
) {
private final M body;
public Models(PlayerModelKey<T, ? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) {
this.armorFactory = playerModelKey.armorFactory();
this.body = playerModelKey.getKey(slimArms).createModel();
public Models(PlayerModelKey<? super M> playerModelKey, boolean slimArms, @Nullable Consumer<M> initializer) {
this(Util.memoize(key -> key.createModel(playerModelKey.armorFactory())), playerModelKey.getKey(slimArms).createModel());
if (initializer != null) {
initializer.accept(this.body);
initializer.accept(body);
}
}
public Models(ModelKey<M> key) {
this.armorFactory = null;
this.body = key.createModel();
this(Util.memoize(k -> k.createModel()), key.createModel());
}
public M body() {
return body;
}
public Optional<PonyArmourModel<T>> getArmourModel(ItemStack stack, ArmourLayer layer, ArmourVariant variant) {
public Optional<PonyArmourModel<?>> getArmourModel(ItemStack stack, ArmourLayer layer, ArmourVariant variant) {
return ArmorModelRegistry.getModelKey(stack.getItem(), layer).or(() -> variant.getDefaultModel(layer).filter(l -> stack.getItem() instanceof ArmorItem))
.map(key -> armor.computeIfAbsent(key, k -> {
return armorFactory == null ? k.createModel() : k.createModel(armorFactory);
}));
}
public Models<T, M> applyMetadata(PonyData meta) {
body.setMetadata(meta);
armor.values().forEach(a -> a.setMetadata(meta));
return this;
.map(armor);
}
}

View file

@ -2,12 +2,13 @@ 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.render.entity.state.EntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.mson.api.MsonModel;
public interface PonyModel<T extends BipedEntityRenderState & PonyModel.AttributedHolder> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
public interface PonyModel<T extends EntityRenderState & PonyModel.AttributedHolder> extends MsonModel, ModelWithHooves, ModelWithHat, ModelWithHead {
ModelPart getBodyPart(BodyPart part);
@ -18,5 +19,9 @@ public interface PonyModel<T extends BipedEntityRenderState & PonyModel.Attribut
public interface AttributedHolder {
ModelAttributes getAttributes();
Race getRace();
float getSwingAmount();
}
}

View file

@ -1,117 +0,0 @@
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.util.Arm;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
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 BipedEntityRenderState, M extends PonyModel<T>> extends PonyModel<T> {
M mixin();
@Override
default void init(ModelView context) {
mixin().init(context);
if (mixin() instanceof RenderLayerSetter && this instanceof RenderLayerSetter) {
((RenderLayerSetter)this).setRenderLayerFactory(((RenderLayerSetter)mixin()).getRenderLayerFactory());
}
}
@Override
default void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
mixin().updateLivingState(entity, pony, mode);
}
@Override
default void copyAttributes(BipedEntityModel<T> other) {
mixin().copyAttributes(other);
}
@Override
default void transform(BodyPart part, MatrixStack stack) {
mixin().transform(part, stack);
}
@Override
default ModelAttributes getAttributes() {
return mixin().getAttributes();
}
@Override
default Size getSize() {
return mixin().getSize();
}
@Override
default void setMetadata(PonyData meta) {
mixin().setMetadata(meta);
}
@Override
default float getSwingAmount() {
return mixin().getSwingAmount();
}
@Override
default float getWobbleAmount() {
return mixin().getWobbleAmount();
}
@Override
default float getRiderYOffset() {
return mixin().getRiderYOffset();
}
@Override
default ModelPart getForeLeg(Arm side) {
return mixin().getForeLeg(side);
}
@Override
default ModelPart getHindLeg(Arm side) {
return mixin().getHindLeg(side);
}
@Override
default ArmPose getArmPoseForSide(Arm side) {
return mixin().getArmPoseForSide(side);
}
@Override
default void setArmAngle(Arm arm, MatrixStack stack) {
if (mixin() instanceof ModelWithArms) {
((ModelWithArms)mixin()).setArmAngle(arm, stack);
}
}
@Override
default ModelPart getHead() {
return mixin().getHead();
}
@Override
default ModelPart getBodyPart(BodyPart part) {
return mixin().getBodyPart(part);
}
@Override
default void setHatVisible(boolean hatVisible) {
mixin().setHatVisible(hatVisible);
}
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,25 +1,26 @@
package com.minelittlepony.api.model;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
public interface SubModel {
public interface SubModel<T extends BipedEntityRenderState & PonyModel.AttributedHolder> {
/**
* Sets the model's various rotation angles.
*/
default void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
default void setPartAngles(T state, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
}
/**
* Renders this model component.
*/
void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes);
void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color);
/**
* Sets whether this part should be rendered.
*/
default void setVisible(boolean visible, ModelAttributes attributes) {
default void setVisible(boolean visible, T state) {
}
}

View file

@ -11,6 +11,11 @@ public interface WingedPonyModel<T extends BipedEntityRenderState & PonyModel.At
public static final float WINGS_FULL_SPREAD_ANGLE = MathUtil.Angles._270_DEG + 0.4F;
public static final float WINGS_RAISED_ANGLE = 4;
/**
* Gets the wings of this pegasus/flying creature
*/
SubModel<T> getWings();
/**
* Returns true if the wings are spread.
*/
@ -25,11 +30,6 @@ public interface WingedPonyModel<T extends BipedEntityRenderState & PonyModel.At
|| state.getAttributes().isWearing(Wearable.SADDLE_BAGS_RIGHT);
}
/**
* Gets the wings of this pegasus/flying creature
*/
SubModel getWings();
/**
* Determines angle used to animate wing flaps whilst flying/swimming.
*

View file

@ -2,10 +2,9 @@ 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.BipedEntityRenderState;
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;
import com.minelittlepony.api.model.*;
@ -75,9 +74,9 @@ public interface Gear {
/**
* Applies body transformations for this wearable
*/
default <M extends EntityModel<?> & PonyModel<?>> void transform(M model, MatrixStack matrices) {
default <S extends EntityRenderState & PonyModel.AttributedHolder> void transform(S state, PonyModel<S> model, MatrixStack matrices) {
BodyPart part = getGearLocation();
model.transform(part, matrices);
model.transform(state, part, matrices);
model.getBodyPart(part).rotate(matrices);
}
@ -86,7 +85,7 @@ public interface Gear {
*
* See {@link AbstractPonyMode.setRotationAndAngle} for an explanation of the various parameters.
*/
default void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
default <S extends BipedEntityRenderState & PonyModel.AttributedHolder> void pose(PonyModel<S> model, S state, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
}

View file

@ -1,12 +1,13 @@
package com.minelittlepony.api.model.gear;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class WearableGear extends AbstractGearModel {
@ -25,12 +26,12 @@ public class WearableGear extends AbstractGearModel {
}
@Override
public boolean canRender(PonyModel<?> model, Entity entity) {
return model.isWearing(wearable);
public boolean canRender(PonyModel<?> model, EntityRenderState entity) {
return entity instanceof PonyRenderState state && state.isWearing(wearable);
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
public <S extends EntityRenderState> Identifier getTexture(S entity, Context<S, ?> context) {
return context.getDefaultTexture(entity, wearable);
}
}

View file

@ -1,28 +0,0 @@
package com.minelittlepony.client;
import com.minelittlepony.api.pony.Pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class PonyBounds {
private static Vec3d getBaseRidingOffset(LivingEntity entity) {
float delta = MinecraftClient.getInstance().getRenderTickCounter().getTickDelta(false);
return new Vec3d(
MathHelper.lerp(delta, entity.prevX, entity.getX()),
MathHelper.lerp(delta, entity.prevY, entity.getY()),
MathHelper.lerp(delta, entity.prevZ, entity.getZ())
);
}
public static Box getBoundingBox(Pony pony, LivingEntity entity) {
final float scale = pony.size().scaleFactor();
final float width = entity.getWidth() * scale;
final float height = entity.getHeight() * scale;
return new Box(-width, 0, -width, width, height, width).offset(getBaseRidingOffset(entity));
}
}

View file

@ -11,8 +11,9 @@ import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.resource.ResourceManager;
import net.minecraft.server.network.ServerPlayerEntity;
@ -108,6 +109,7 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe
return loadPony(DefaultSkinHelper.getSkinTextures(uuid).texture(), true);
}
@SuppressWarnings("unchecked")
@Nullable
private Identifier getSkin(LivingEntity entity) {
if (entity instanceof PlayerEntity player) {
@ -115,8 +117,8 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe
return clientPlayer.getSkinTextures().texture();
}
} else {
if (MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity) != null) {
return MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity).getTexture(entity);
if (MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity) instanceof LivingEntityRenderer renderer) {
return renderer.getTexture((LivingEntityRenderState)renderer.getAndUpdateRenderState(entity, 1));
}
}

View file

@ -57,7 +57,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
protected final RenderList mainRenderList;
private final List<SubModel> parts = new ArrayList<>();
private final List<SubModel<? super T>> parts = new ArrayList<>();
@Nullable
protected T currentState;
@ -76,17 +76,17 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
.add(withStage(BodyPart.HEAD, helmetRenderList = RenderList.of(hat)));
}
protected <P extends SubModel> P addPart(P part) {
protected <P extends SubModel<? super T>> P addPart(P part) {
parts.add(part);
return part;
}
protected RenderList forPart(Supplier<SubModel> part) {
return (stack, vertices, overlay, light, color) -> part.get().renderPart(stack, vertices, overlay, light, color, currentState.attributes);
protected RenderList forPart(Supplier<SubModel<? super T>> part) {
return (stack, vertices, overlay, light, color) -> part.get().renderPart(stack, vertices, overlay, light, color);
}
protected RenderList forPart(SubModel part) {
return (stack, vertices, overlay, light, color) -> part.renderPart(stack, vertices, overlay, light, color, currentState.attributes);
protected RenderList forPart(SubModel<T> part) {
return (stack, vertices, overlay, light, color) -> part.renderPart(stack, vertices, overlay, light, color);
}
protected RenderList withStage(BodyPart part, RenderList action) {
@ -127,7 +127,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
protected void setModelVisibilities(T state) {
hat.visible = head.visible && !state.attributes.isHorsey;
parts.forEach(part -> part.setVisible(body.visible, state.attributes));
parts.forEach(part -> part.setVisible(body.visible, state));
}
protected void setModelAngles(T entity) {
@ -147,7 +147,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
body.yaw = wobbleAmount;
neck.yaw = wobbleAmount;
rotateLegs(entity, limbAngle, limbSpeed, animationProgress, entity);
rotateLegs(entity, limbAngle, limbSpeed, animationProgress);
ArmPose left = getArmPose(entity, Arm.LEFT);
ArmPose right = getArmPose(entity, Arm.RIGHT);
@ -188,7 +188,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
head.pitch = 0.5F;
}
parts.forEach(part -> part.setPartAngles(entity.attributes, limbAngle, limbSpeed, wobbleAmount, animationProgress));
parts.forEach(part -> part.setPartAngles(entity, limbAngle, limbSpeed, wobbleAmount, animationProgress));
}
public void setHeadRotation(float animationProgress, float yaw, float pitch) {
@ -253,11 +253,11 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*
*/
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
protected void rotateLegs(T state, float move, float swing, float ticks) {
if (state.attributes.isSwimming) {
rotateLegsSwimming(state, move, swing, ticks, entity);
rotateLegsSwimming(state, move, swing, ticks);
} else {
rotateLegsOnGround(state, move, swing, ticks, entity);
rotateLegsOnGround(state, move, swing, ticks);
}
float sin = MathHelper.sin(body.yaw) * 5;
@ -293,14 +293,14 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
*
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*/
protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
protected void rotateLegsSwimming(T state, @Deprecated float move, @Deprecated float swing, @Deprecated float ticks) {
float lerp = entity.isInPose(EntityPose.SWIMMING) ? (float)state.attributes.motionLerp : 1;
float lerp = state.isInPose(EntityPose.SWIMMING) ? (float)state.attributes.motionLerp : 1;
float legLeft = (MathUtil.Angles._90_DEG + MathHelper.sin((move / 3) + 2 * MathHelper.PI/3) / 2) * lerp;
float legLeft = (MathUtil.Angles._90_DEG + MathHelper.sin((state.limbFrequency / 3) + 2 * MathHelper.PI/3) / 2) * lerp;
float left = (MathUtil.Angles._90_DEG + MathHelper.sin((move / 3) + 2 * MathHelper.PI) / 2) * lerp;
float right = (MathUtil.Angles._90_DEG + MathHelper.sin(move / 3) / 2) * lerp;
float left = (MathUtil.Angles._90_DEG + MathHelper.sin((state.limbFrequency / 3) + 2 * MathHelper.PI) / 2) * lerp;
float right = (MathUtil.Angles._90_DEG + MathHelper.sin(state.limbFrequency / 3) / 2) * lerp;
leftArm.setAngles(-left, -left/2, left/2);
rightArm.setAngles(-right, right/2, -right/2);
@ -312,7 +312,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
* Rotates legs in quopy fashion for walking.
*
*/
protected void rotateLegsOnGround(T state, float move, float swing, float ticks, T entity) {
protected void rotateLegsOnGround(T state, float move, float swing, float ticks) {
float angle = MathHelper.PI * (float) Math.pow(swing, 16);
float baseRotation = move * 0.6662F; // magic number ahoy
@ -545,7 +545,7 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
@Override
public final void setArmAngle(Arm arm, MatrixStack matrices) {
super.setArmAngle(arm, matrices);
positionheldItem(arm, matrices);
positionheldItem(currentState, arm, matrices);
}
protected void positionheldItem(T state, Arm arm, MatrixStack matrices) {
@ -600,6 +600,6 @@ public abstract class AbstractPonyModel<T extends PonyRenderState> extends Clien
neck.hidden = !head.visible;
}
PonyTransformation.forSize(state.getSize()).transform(this, part, stack);
PonyTransformation.forSize(state.getSize()).transform(state.attributes, part, stack);
}
}

View file

@ -4,8 +4,6 @@ import net.minecraft.client.model.Model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.ArmorStandEntityModel;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.VexEntity;
import net.minecraft.entity.passive.*;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
@ -29,7 +27,7 @@ import java.util.function.BiFunction;
import java.util.stream.Stream;
public final class ModelType {
private static final Map<Race, PlayerModelKey<?, ?>> PLAYER_MODELS = new HashMap<>();
private static final Map<Race, PlayerModelKey<?>> PLAYER_MODELS = new HashMap<>();
private static final Map<Wearable, GearModelKey<? extends Gear>> GEAR_MODELS = new HashMap<>();
public static final ModelKey<DJPon3EarsModel> DJ_PON_3 = register("dj_pon_three", DJPon3EarsModel::new);
@ -41,12 +39,12 @@ public final class ModelType {
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<IllagerPonyModel<?>> ILLAGER = register("illager", IllagerPonyModel::new);
public static final ModelKey<GuardianPonyModel> GUARDIAN = register("guardian", GuardianPonyModel::new);
public static final ModelKey<SeaponyModel<?>> GUARDIAN = register("guardian", SeaponyModel::new);
public static final ModelKey<EnderStallionModel> ENDERMAN = register("enderman", EnderStallionModel::new);
public static final ModelKey<ParaspriteModel<VexEntity>> VEX = register("vex", ParaspriteModel::new);
public static final ModelKey<SpikeModel<StriderEntity>> STRIDER = register("strider", SpikeModel::new);
public static final ModelKey<SaddleModel<StriderEntity>> STRIDER_SADDLE = register("strider_saddle", SaddleModel::new);
public static final ModelKey<BreezieModel<AllayEntity>> ALLAY = register("allay", BreezieModel::new);
public static final ModelKey<ParaspriteModel> VEX = register("vex", ParaspriteModel::new);
public static final ModelKey<SpikeModel> STRIDER = register("strider", SpikeModel::new);
public static final ModelKey<SaddleModel> STRIDER_SADDLE = register("strider_saddle", SaddleModel::new);
public static final ModelKey<BreezieModel> ALLAY = register("allay", BreezieModel::new);
public static final ModelKey<PonyElytra<?>> ELYTRA = register("elytra", PonyElytra::new);
@ -56,38 +54,38 @@ public final class ModelType {
public static final ModelKey<PonyArmourModel<?>> INNER_PONY_ARMOR = register("armor/inner_pony_armor", PonyArmourModel::new);
public static final ModelKey<PonyArmourModel<?>> OUTER_PONY_ARMOR = register("armor/outer_pony_armor", PonyArmourModel::new);
public static final GearModelKey<AbstractGearModel> STETSON = registerGear("stetson", Wearable.STETSON, t -> new WearableGear(Wearable.STETSON, BodyPart.HEAD, 0.15F).addPart(t));
public static final GearModelKey<AbstractGearModel> STETSON = registerGear("stetson", Wearable.STETSON, t -> new WearableGear(t, Wearable.STETSON, BodyPart.HEAD, 0.15F));
public static final GearModelKey<SaddleBags> SADDLEBAGS_BOTH = registerGear("saddlebags", Wearable.SADDLE_BAGS_BOTH, t -> new SaddleBags(t, Wearable.SADDLE_BAGS_BOTH));
public static final GearModelKey<SaddleBags> SADDLEBAGS_LEFT = registerGear(SADDLEBAGS_BOTH, Wearable.SADDLE_BAGS_LEFT, t -> new SaddleBags(t, Wearable.SADDLE_BAGS_LEFT));
public static final GearModelKey<SaddleBags> SADDLEBAGS_RIGHT = registerGear(SADDLEBAGS_BOTH, Wearable.SADDLE_BAGS_RIGHT, t -> new SaddleBags(t, Wearable.SADDLE_BAGS_RIGHT));
public static final GearModelKey<Crown> CROWN = registerGear("crown", Wearable.CROWN, Crown::new);
public static final GearModelKey<AbstractGearModel> MUFFIN = registerGear("muffin", Wearable.MUFFIN, t -> new WearableGear(Wearable.MUFFIN, BodyPart.HEAD, 0.45F).addPart(t.getChild("crown")));
public static final GearModelKey<AbstractGearModel> WITCH_HAT = registerGear("witch_hat", Wearable.HAT, t -> new WearableGear(Wearable.HAT, BodyPart.HEAD, 0.7F).addPart(t.getChild("hat")));
public static final GearModelKey<AbstractGearModel> MUFFIN = registerGear("muffin", Wearable.MUFFIN, t -> new WearableGear(t.getChild("crown"), Wearable.MUFFIN, BodyPart.HEAD, 0.45F));
public static final GearModelKey<AbstractGearModel> WITCH_HAT = registerGear("witch_hat", Wearable.HAT, t -> new WearableGear(t.getChild("hat"), Wearable.HAT, BodyPart.HEAD, 0.7F));
public static final GearModelKey<DeerAntlers> ANTLERS = registerGear("antlers", Wearable.ANTLERS, DeerAntlers::new);
public static final PlayerModelKey<LivingEntity, AlicornModel<?>> ALICORN = registerPlayer("alicorn", Race.ALICORN, AlicornModel::new);
public static final PlayerModelKey<LivingEntity, UnicornModel<?>> UNICORN = registerPlayer("unicorn", Race.UNICORN, UnicornModel::new);
public static final PlayerModelKey<LivingEntity, KirinModel<?>> KIRIN = registerPlayer("kirin", Race.KIRIN, KirinModel::new);
public static final PlayerModelKey<LivingEntity, PegasusModel<?>> PEGASUS = registerPlayer("pegasus", Race.PEGASUS, PegasusModel::new);
public static final PlayerModelKey<LivingEntity, PegasusModel<?>> GRYPHON = registerPlayer("gryphon", Race.GRYPHON, PegasusModel::new);
public static final PlayerModelKey<LivingEntity, PegasusModel<?>> HIPPOGRIFF = registerPlayer("hippogriff", Race.HIPPOGRIFF, PegasusModel::new, PonyArmourModel::new);
public static final PlayerModelKey<LivingEntity, EarthPonyModel<?>> EARTH_PONY = registerPlayer("earth_pony", Race.EARTH, EarthPonyModel::new);
public static final PlayerModelKey<LivingEntity, SeaponyModel<?>> SEA_PONY = registerPlayer("sea_pony", Race.SEAPONY, SeaponyModel::new, SeaponyModel.Armour::new);
public static final PlayerModelKey<LivingEntity, PegasusModel<?>> BAT_PONY = registerPlayer("bat_pony", Race.BATPONY, PegasusModel::new);
public static final PlayerModelKey<LivingEntity, ChangelingModel<?>> CHANGELING = registerPlayer("changeling", Race.CHANGELING, ChangelingModel::new);
public static final PlayerModelKey<LivingEntity, ChangelingModel<?>> CHANGEDLING = registerPlayer("reformed_changeling", Race.CHANGEDLING, ChangelingModel::new);
public static final PlayerModelKey<LivingEntity, EarthPonyModel<?>> ZEBRA = registerPlayer("zebra", Race.ZEBRA, EarthPonyModel::new);
public static final PlayerModelKey<AlicornModel<?>> ALICORN = registerPlayer("alicorn", Race.ALICORN, AlicornModel::new);
public static final PlayerModelKey<UnicornModel<?>> UNICORN = registerPlayer("unicorn", Race.UNICORN, UnicornModel::new);
public static final PlayerModelKey<KirinModel<?>> KIRIN = registerPlayer("kirin", Race.KIRIN, KirinModel::new);
public static final PlayerModelKey<PegasusModel<?>> PEGASUS = registerPlayer("pegasus", Race.PEGASUS, PegasusModel::new);
public static final PlayerModelKey<PegasusModel<?>> GRYPHON = registerPlayer("gryphon", Race.GRYPHON, PegasusModel::new);
public static final PlayerModelKey<PegasusModel<?>> HIPPOGRIFF = registerPlayer("hippogriff", Race.HIPPOGRIFF, PegasusModel::new, PonyArmourModel::new);
public static final PlayerModelKey<EarthPonyModel<?>> EARTH_PONY = registerPlayer("earth_pony", Race.EARTH, EarthPonyModel::new);
public static final PlayerModelKey<SeaponyModel<?>> SEA_PONY = registerPlayer("sea_pony", Race.SEAPONY, SeaponyModel::new, SeaponyModel.Armour::new);
public static final PlayerModelKey<PegasusModel<?>> BAT_PONY = registerPlayer("bat_pony", Race.BATPONY, PegasusModel::new);
public static final PlayerModelKey<ChangelingModel<?>> CHANGELING = registerPlayer("changeling", Race.CHANGELING, ChangelingModel::new);
public static final PlayerModelKey<ChangelingModel<?>> CHANGEDLING = registerPlayer("reformed_changeling", Race.CHANGEDLING, ChangelingModel::new);
public static final PlayerModelKey<EarthPonyModel<?>> ZEBRA = registerPlayer("zebra", Race.ZEBRA, EarthPonyModel::new);
static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> registerPlayer(String name, Race race,
static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<T> registerPlayer(String name, Race race,
BiFunction<ModelPart, Boolean, T> constructor) {
return registerPlayer(name, race, constructor, PonyArmourModel::new);
}
@SuppressWarnings("unchecked")
static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> registerPlayer(String name, Race race,
static <T extends Model & PonyModel<?>> PlayerModelKey<T> registerPlayer(String name, Race race,
BiFunction<ModelPart, Boolean, T> constructor,
MsonModel.Factory<PonyArmourModel<E>> armorFactory) {
return (PlayerModelKey<E, T>)PLAYER_MODELS.computeIfAbsent(race, r -> new PlayerModelKey<>(name, constructor, armorFactory));
MsonModel.Factory<PonyArmourModel<?>> armorFactory) {
return (PlayerModelKey<T>)PLAYER_MODELS.computeIfAbsent(race, r -> new PlayerModelKey<T>(name, constructor, armorFactory));
}
@SuppressWarnings("unchecked")
@ -108,8 +106,8 @@ public final class ModelType {
@SuppressWarnings("unchecked")
@Nullable
public static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> getPlayerModel(Race race) {
return (PlayerModelKey<E, T>)PLAYER_MODELS.get(race);
public static <T extends Model & PonyModel<?>> PlayerModelKey<T> getPlayerModel(Race race) {
return (PlayerModelKey<T>)PLAYER_MODELS.get(race);
}
public static Stream<Map.Entry<Wearable, GearModelKey<? extends Gear>>> getWearables() {

View file

@ -2,7 +2,6 @@ package com.minelittlepony.client.model;
import net.minecraft.client.model.Model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity;
import org.jetbrains.annotations.Nullable;
@ -14,12 +13,15 @@ import com.minelittlepony.mson.api.*;
import java.util.function.*;
public record PlayerModelKey<T extends LivingEntity, M extends Model & PonyModel<?>> (
public record PlayerModelKey<M extends Model & PonyModel<?>> (
ModelKey<M> steveKey,
ModelKey<M> alexKey,
MsonModel.Factory<PonyArmourModel<T>> armorFactory
MsonModel.Factory<PonyArmourModel<?>> armorFactory
) {
PlayerModelKey(String name,
BiFunction<ModelPart, Boolean, M> modelFactory,
MsonModel.Factory<PonyArmourModel<?>> armorFactory
) {
PlayerModelKey(String name, BiFunction<ModelPart, Boolean, M> modelFactory, MsonModel.Factory<PonyArmourModel<T>> armorFactory) {
this(
new ModelKeyImpl<>(MineLittlePony.id("races/steve/" + name), tree -> modelFactory.apply(tree, false)),
new ModelKeyImpl<>(MineLittlePony.id("races/alex/" + name), tree -> modelFactory.apply(tree, true)),
@ -31,12 +33,11 @@ public record PlayerModelKey<T extends LivingEntity, M extends Model & PonyModel
return slimArms ? alexKey : steveKey;
}
public <E extends T, N extends M> Models<E, N> create(boolean slimArms) {
public <N extends M> Models<N> create(boolean slimArms) {
return create(slimArms, null);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public <E extends T, N extends M> Models<E, N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new Models(this, slimArms, initializer);
public <N extends M> Models<N> create(boolean slimArms, @Nullable Consumer<N> initializer) {
return new Models<>(this, slimArms, initializer);
}
}

View file

@ -1,90 +1,30 @@
package com.minelittlepony.client.model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.entity.model.AnimalModel;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
/**
* Modified from ModelElytra.
*/
public class PonyElytra<T extends LivingEntity> extends AnimalModel<T> {
public class PonyElytra<T extends BipedEntityRenderState> extends EntityModel<T> {
public boolean isSneaking;
private final ModelPart rightWing;
private final ModelPart leftWing;
public PonyElytra(ModelPart tree) {
rightWing = tree.getChild("right_wing");
leftWing = tree.getChild("left_wing");
public PonyElytra(ModelPart root) {
super(root);
rightWing = root.getChild("right_wing");
leftWing = root.getChild("left_wing");
}
@Override
protected Iterable<ModelPart> getHeadParts() {
return ImmutableList.of();
}
@Override
protected Iterable<ModelPart> getBodyParts() {
return ImmutableList.of(leftWing, rightWing);
}
/**
* Sets the model's various rotation angles.
*
* See {@link AbstractPonyModel.setRotationAngles} for an explanation of the various parameters.
*/
@Override
public void setAngles(T entity, float limbDistance, float limbAngle, float age, float headYaw, float headPitch) {
float rotateX = MathHelper.PI / 2;
float rotateY = MathHelper.PI / 8;
float rotateZ = MathHelper.PI / 12;
float rpY = 0;
if (entity.isFallFlying()) {
float velY = 1;
Vec3d motion = entity.getVelocity();
if (motion.y < 0) {
velY = 1 - (float) Math.pow(-motion.normalize().y, 1.5);
}
rotateX = velY * MathHelper.PI * (2 / 3F) + (1 - velY) * rotateX;
rotateY = velY * (MathHelper.PI / 2) + (1 - velY) * rotateY;
} else if (isSneaking) {
rotateX = MathHelper.PI * 1.175F;
rotateY = MathHelper.PI / 2;
rotateZ = MathHelper.PI / 4;
rpY = AbstractPonyModel.BODY_SNEAKING.y();
}
leftWing.pivotX = 5;
leftWing.pivotY = rpY;
if (entity instanceof AbstractClientPlayerEntity) {
AbstractClientPlayerEntity player = (AbstractClientPlayerEntity) entity;
player.elytraPitch += (rotateX - player.elytraPitch) / 10;
player.elytraYaw += (rotateY - player.elytraYaw) / 10;
player.elytraRoll += (rotateZ - player.elytraRoll) / 10;
leftWing.pitch = player.elytraPitch;
leftWing.yaw = player.elytraYaw;
leftWing.roll = player.elytraRoll;
} else {
leftWing.pitch = rotateX;
leftWing.yaw = rotateZ;
leftWing.roll = rotateY;
}
rightWing.pivotX = -leftWing.pivotX;
rightWing.pivotY = leftWing.pivotY;
public void setAngles(T state) {
leftWing.pitch = state.leftWingPitch;
leftWing.yaw = state.leftWingYaw;
leftWing.roll = state.leftWingRoll;
rightWing.pitch = leftWing.pitch;
rightWing.yaw = -leftWing.yaw;
rightWing.roll = -leftWing.roll;

View file

@ -3,6 +3,8 @@ package com.minelittlepony.client.model.armour;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.model.Model;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
@ -11,11 +13,11 @@ import net.minecraft.component.type.DyedColorComponent;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import net.minecraft.item.trim.ArmorTrim;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.item.equipment.EquipmentModel.LayerType;
import net.minecraft.item.equipment.trim.ArmorTrim;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.util.*;
import org.jetbrains.annotations.Nullable;
@ -33,12 +35,20 @@ public interface ArmourRendererPlugin {
return ArmourTextureResolver.INSTANCE;
}
default void onArmourRendered(LivingEntity entity, MatrixStack matrices, VertexConsumerProvider provider, EquipmentSlot armorSlot, ArmourLayer layer, ArmourType type) {
default void onArmourRendered(LivingEntityRenderState state, MatrixStack matrices, VertexConsumerProvider provider, EquipmentSlot armorSlot, ArmourLayer layer, ArmourType type) {
}
default ItemStack[] getArmorStacks(LivingEntity entity, EquipmentSlot armorSlot, ArmourLayer layer, ArmourType type) {
return new ItemStack[] { entity.getEquippedStack(armorSlot) };
default ItemStack[] getArmorStacks(BipedEntityRenderState state, EquipmentSlot armorSlot, ArmourLayer layer, ArmourType type) {
return new ItemStack[] { switch (armorSlot) {
case HEAD -> state.equippedHeadStack;
case CHEST -> state.equippedChestStack;
case LEGS -> state.equippedLegsStack;
case FEET -> state.equippedFeetStack;
case BODY -> state.equippedChestStack;
case MAINHAND -> state.getMainHandStack();
case OFFHAND -> state.mainArm == Arm.LEFT ? state.leftHandStack : state.rightHandStack;
}};
}
default float getGlintAlpha(EquipmentSlot slot, ItemStack stack) {
@ -49,51 +59,51 @@ public interface ArmourRendererPlugin {
return stack.isIn(ItemTags.DYEABLE) ? DyedColorComponent.getColor(stack, -6265536) : Colors.WHITE;
}
default float getArmourAlpha(EquipmentSlot slot, ArmourLayer layer) {
default float getArmourAlpha(EquipmentSlot slot, LayerType layer) {
return 1F;
}
default float getTrimAlpha(EquipmentSlot slot, RegistryEntry<ArmorMaterial> material, ArmorTrim trim, ArmourLayer layer) {
default float getTrimAlpha(EquipmentSlot slot, ArmorTrim trim, LayerType layer) {
return 1F;
}
default float getElytraAlpha(ItemStack stack, Model model, LivingEntity entity) {
default float getElytraAlpha(ItemStack stack, Model model, LivingEntityRenderState entity) {
return stack.isOf(Items.ELYTRA) ? 1F : 0F;
}
@Nullable
default VertexConsumer getTrimConsumer(EquipmentSlot slot, VertexConsumerProvider provider, RegistryEntry<ArmorMaterial> material, ArmorTrim trim, ArmourLayer layer) {
@Nullable VertexConsumer buffer = getOptionalBuffer(provider, getTrimLayer(slot, material, trim, layer));
default VertexConsumer getTrimConsumer(EquipmentSlot slot, VertexConsumerProvider provider, ArmorTrim trim, LayerType layerType, Identifier modelId) {
@Nullable VertexConsumer buffer = getOptionalBuffer(provider, getTrimLayer(slot, trim, layerType, modelId));
if (buffer == null) {
return null;
}
SpriteAtlasTexture armorTrimsAtlas = MinecraftClient.getInstance().getBakedModelManager().getAtlas(TexturedRenderLayers.ARMOR_TRIMS_ATLAS_TEXTURE);
Sprite sprite = armorTrimsAtlas.getSprite(layer == ArmourLayer.INNER ? trim.getLeggingsModelId(material) : trim.getGenericModelId(material));
Sprite sprite = armorTrimsAtlas.getSprite(trim.getTexture(layerType, modelId));
return sprite.getTextureSpecificVertexConsumer(buffer);
}
@Nullable
default RenderLayer getTrimLayer(EquipmentSlot slot, RegistryEntry<ArmorMaterial> material, ArmorTrim trim, ArmourLayer layer) {
return TexturedRenderLayers.getArmorTrims(trim.getPattern().value().decal());
default RenderLayer getTrimLayer(EquipmentSlot slot, ArmorTrim trim, LayerType layerType, Identifier modelId) {
return TexturedRenderLayers.getArmorTrims(trim.pattern().value().decal());
}
@Nullable
default VertexConsumer getArmourConsumer(EquipmentSlot slot, VertexConsumerProvider provider, Identifier texture, ArmourLayer layer) {
default VertexConsumer getArmourConsumer(EquipmentSlot slot, VertexConsumerProvider provider, Identifier texture, EquipmentModel.LayerType layer) {
return getOptionalBuffer(provider, getArmourLayer(slot, texture, layer));
}
@Nullable
default RenderLayer getArmourLayer(EquipmentSlot slot, Identifier texture, ArmourLayer layer) {
default RenderLayer getArmourLayer(EquipmentSlot slot, Identifier texture, EquipmentModel.LayerType layer) {
return RenderLayer.getArmorCutoutNoCull(texture);
}
@Nullable
default VertexConsumer getGlintConsumer(EquipmentSlot slot, VertexConsumerProvider provider, ArmourLayer layer) {
default VertexConsumer getGlintConsumer(EquipmentSlot slot, VertexConsumerProvider provider, EquipmentModel.LayerType layer) {
return getOptionalBuffer(provider, getGlintLayer(slot, layer));
}
@Nullable
default RenderLayer getGlintLayer(EquipmentSlot slot, ArmourLayer layer) {
default RenderLayer getGlintLayer(EquipmentSlot slot, EquipmentModel.LayerType layer) {
return RenderLayer.getArmorEntityGlint();
}
@ -110,9 +120,13 @@ public interface ArmourRendererPlugin {
return RenderLayer.getEntitySolid(texture);
}
/**
* @deprecated Method is no longer used
*/
@Deprecated
@Nullable
default VertexConsumer getElytraConsumer(ItemStack stack, Model model, LivingEntity entity, VertexConsumerProvider provider, Identifier texture) {
return ItemRenderer.getDirectItemGlintConsumer(provider, model.getLayer(texture), false, getGlintAlpha(EquipmentSlot.CHEST, stack) > 0F);
default VertexConsumer getElytraConsumer(ItemStack stack, Model model, BipedEntityRenderState state, VertexConsumerProvider provider, Identifier texture) {
return ItemRenderer.getArmorGlintConsumer(provider, RenderLayer.getArmorCutoutNoCull(texture), getGlintAlpha(EquipmentSlot.CHEST, stack) > 0F);
}
@Nullable

View file

@ -1,12 +1,8 @@
package com.minelittlepony.client.model.armour;
import net.minecraft.item.ArmorMaterial;
import net.minecraft.item.ItemStack;
import java.util.List;
import net.minecraft.item.equipment.EquipmentModel;
public interface ArmourTextureLookup {
ArmourTexture getTexture(ItemStack stack, ArmourLayer layer, ArmorMaterial.Layer armorLayer);
List<ArmorMaterial.Layer> getArmorLayers(ItemStack stack, int dyeColor);
ArmourTexture getTexture(ItemStack stack, ArmourLayer layerType, EquipmentModel.Layer layer);
}

View file

@ -4,15 +4,12 @@ import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.CustomModelDataComponent;
import net.minecraft.item.*;
import net.minecraft.registry.Registries;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Colors;
import net.minecraft.resource.ResourceReloader;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
import com.google.common.cache.*;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.minelittlepony.client.MineLittlePony;
import java.util.*;
@ -39,14 +36,12 @@ public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableR
public static final Identifier ID = MineLittlePony.id("armor_textures");
public static final ArmourTextureResolver INSTANCE = new ArmourTextureResolver();
private static final Interner<ArmorMaterial.Layer> LAYER_INTERNER = Interners.newWeakInterner();
private final LoadingCache<ArmourParameters, ArmourTexture> layerCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(parameters -> {
return Stream.of(ArmourTexture.legacy(parameters.material().getTexture(parameters.layer() == ArmourLayer.OUTER))).flatMap(i -> {
return Stream.of(ArmourTexture.legacy(parameters.material().textureId())).flatMap(i -> {
if (parameters.layer() == ArmourLayer.OUTER) {
return Stream.of(i, ArmourTexture.legacy(parameters.material().getTexture(false)));
return Stream.of(i, ArmourTexture.legacy(parameters.material().textureId()));
}
return Stream.of(i);
}).flatMap(i -> {
@ -56,15 +51,6 @@ public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableR
return Stream.of(i);
}).flatMap(this::performLookup).findFirst().orElse(ArmourTexture.UNKNOWN);
}));
private final LoadingCache<Identifier, List<ArmorMaterial.Layer>> nonDyedLayers = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(material -> List.of(LAYER_INTERNER.intern(new ArmorMaterial.Layer(material, "", false)))));
private final LoadingCache<Identifier, List<ArmorMaterial.Layer>> dyedLayers = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(material -> List.of(
LAYER_INTERNER.intern(new ArmorMaterial.Layer(material, "", false)),
LAYER_INTERNER.intern(new ArmorMaterial.Layer(material, "overlay", true))
)));
private Stream<ArmourTexture> performLookup(ArmourTexture id) {
List<ArmourTexture> options = Stream.of(id)
@ -85,12 +71,10 @@ public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableR
public void invalidate() {
layerCache.invalidateAll();
nonDyedLayers.invalidateAll();
dyedLayers.invalidateAll();
}
@Override
public CompletableFuture<Void> reload(Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor) {
public CompletableFuture<Void> reload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Executor prepareExecutor, Executor applyExecutor) {
return CompletableFuture.runAsync(this::invalidate, prepareExecutor).thenCompose(synchronizer::whenPrepared);
}
@ -100,24 +84,15 @@ public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableR
}
@Override
public ArmourTexture getTexture(ItemStack stack, ArmourLayer layer, ArmorMaterial.Layer armorLayer) {
public ArmourTexture getTexture(ItemStack stack, ArmourLayer layer, EquipmentModel.Layer armorLayer) {
return layerCache.getUnchecked(new ArmourParameters(layer, armorLayer, getCustom(stack)));
}
@Override
public List<ArmorMaterial.Layer> getArmorLayers(ItemStack stack, int dyeColor) {
if (stack.getItem() instanceof ArmorItem armor) {
return armor.getMaterial().value().layers();
}
return (dyeColor == Colors.WHITE ? nonDyedLayers : dyedLayers).getUnchecked(Registries.ITEM.getId(stack.getItem()));
}
private int getCustom(ItemStack stack) {
return stack.getOrDefault(DataComponentTypes.CUSTOM_MODEL_DATA, CustomModelDataComponent.DEFAULT).value();
}
private record ArmourParameters(ArmourLayer layer, ArmorMaterial.Layer material, int customModelId) {
private record ArmourParameters(ArmourLayer layer, EquipmentModel.Layer material, int customModelId) {
}
}

View file

@ -0,0 +1,113 @@
package com.minelittlepony.client.model.armour;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
import net.minecraft.client.render.entity.equipment.EquipmentRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.DyedColorComponent;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.item.equipment.EquipmentModel.LayerType;
import net.minecraft.item.equipment.trim.ArmorTrim;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.*;
public class PonifiedEquipmentRenderer extends EquipmentRenderer {
private final EquipmentModelLoader modelLoader;
public PonifiedEquipmentRenderer(EquipmentModelLoader modelLoader) {
super(modelLoader, MinecraftClient.getInstance().getBakedModelManager().getAtlas(TexturedRenderLayers.ARMOR_TRIMS_ATLAS_TEXTURE));
this.modelLoader = modelLoader;
}
public <S extends PonyRenderState, V extends PonyArmourModel<S>> void render(
EquipmentSlot equipmentSlot,
EquipmentModel.LayerType layerType,
Identifier modelId,
Models<? extends PonyModel<S>> models,
ItemStack stack,
MatrixStack matrices,
VertexConsumerProvider vertexConsumers,
int light
) {
this.render(equipmentSlot, layerType, modelId, models, stack, matrices, vertexConsumers, light, null);
}
public <S extends PonyRenderState, V extends PonyArmourModel<S>> void render(
EquipmentSlot equipmentSlot,
EquipmentModel.LayerType layerType,
Identifier modelId,
Models<? extends PonyModel<S>> models,
ItemStack stack,
MatrixStack matrices,
VertexConsumerProvider vertexConsumers,
int light,
@Nullable Identifier texture
) {
List<EquipmentModel.Layer> layers = modelLoader.get(modelId).getLayers(layerType);
if (!layers.isEmpty()) {
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
int i = stack.isIn(ItemTags.DYEABLE) ? DyedColorComponent.getColor(stack, 0) : 0;
float armorAlpha = plugin.getArmourAlpha(equipmentSlot, layerType);
boolean hasGlint = plugin.getGlintAlpha(equipmentSlot, stack) > 0 && stack.hasGlint();
Set<V> drawnModels = new HashSet<>();
if (armorAlpha > 0) {
for (EquipmentModel.Layer layer : layers) {
int j = getDyeColor(layer, i);
if (j != 0) {
ArmourTexture armorTexture = plugin.getTextureLookup().getTexture(stack, layerType == LayerType.HUMANOID_LEGGINGS ? ArmourLayer.INNER : ArmourLayer.OUTER, layer);
Identifier layerTexture = layer.usePlayerTexture() && texture != null
? texture
: armorTexture.texture();
VertexConsumer armorConsumer = plugin.getArmourConsumer(equipmentSlot, vertexConsumers, layerTexture, layerType);
if (armorConsumer != null) {
ArmourVariant variant = layer.usePlayerTexture() ? ArmourVariant.NORMAL : armorTexture.variant();
models.getArmourModel(stack, null, variant).ifPresent(model -> {
VertexConsumer glintConsumer = hasGlint ? plugin.getGlintConsumer(equipmentSlot, vertexConsumers, layerType) : null;
model.render(matrices, glintConsumer != null ? VertexConsumers.union(plugin.getGlintConsumer(equipmentSlot, vertexConsumers, layerType), armorConsumer) : armorConsumer, light, OverlayTexture.DEFAULT_UV, j);
});
}
}
}
}
ArmorTrim armorTrim = stack.get(DataComponentTypes.TRIM);
if (armorTrim != null && plugin.getTrimAlpha(equipmentSlot, armorTrim, layerType) > 0) {
VertexConsumer trimConsumer = plugin.getTrimConsumer(equipmentSlot, vertexConsumers, armorTrim, layerType, modelId);
if (trimConsumer != null) {
drawnModels.forEach(model -> {
model.render(matrices, trimConsumer, light, OverlayTexture.DEFAULT_UV);
});
}
}
}
}
private static int getDyeColor(EquipmentModel.Layer layer, int dyeColor) {
Optional<EquipmentModel.Dyeable> optional = layer.dyeable();
if (optional.isPresent()) {
int i = (Integer)((EquipmentModel.Dyeable)optional.get()).colorWhenUndyed().map(ColorHelper::fullAlpha).orElse(0);
return dyeColor != 0 ? dyeColor : i;
} else {
return -1;
}
}
}

View file

@ -2,28 +2,26 @@ 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;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class PonyArmourModel<T extends BipedEntityRenderState> extends AbstractPonyModel<T> {
public class PonyArmourModel<S extends PonyRenderState> extends AbstractPonyModel<S> {
public PonyArmourModel(ModelPart tree) {
super(tree);
super(tree, false);
}
public boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch,
public boolean poseModel(S state,
EquipmentSlot slot, ArmourLayer layer,
PonyModel<T> mainModel) {
PonyModel<S> mainModel) {
if (!setVisibilities(slot, layer)) {
return false;
}
mainModel.copyAttributes(this);
setAngles(entity, limbAngle, limbDistance, age, headYaw, headPitch);
setAngles(state);
if (mainModel instanceof BipedEntityModel<?> biped) {
head.copyTransform(biped.head);
body.copyTransform(biped.body);

View file

@ -2,12 +2,13 @@ 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.BipedEntityRenderState;
import net.minecraft.entity.EntityPose;
import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper;
public class BreezieModel<T extends BipedEntityRenderState> extends BipedEntityModel<T> {
import com.minelittlepony.client.render.entity.AllayRenderer;
public class BreezieModel extends BipedEntityModel<AllayRenderer.State> {
private ModelPart leftWing;
private ModelPart rightWing;
@ -25,7 +26,7 @@ public class BreezieModel<T extends BipedEntityRenderState> extends BipedEntityM
}
@Override
public void setAngles(T state) {
public void setAngles(AllayRenderer.State state) {
float move = state.limbFrequency;
float swing = state.limbAmplitudeMultiplier;
@ -90,7 +91,7 @@ public class BreezieModel<T extends BipedEntityRenderState> extends BipedEntityM
leg.setAngles(-1.4137167F, factor * MathHelper.PI / 10, factor * 0.07853982F);
}
protected void swingArms(T state, Arm mainHand) {
protected void swingArms(AllayRenderer.State state, Arm mainHand) {
body.yaw = MathHelper.sin(MathHelper.sqrt(state.handSwingProgress) * MathHelper.TAU) / 5;
if (mainHand == Arm.LEFT) {

View file

@ -1,46 +0,0 @@
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.render.entity.model.GuardianEntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.GuardianEntity;
import com.minelittlepony.api.model.PonyModelMixin;
import com.minelittlepony.client.model.entity.race.SeaponyModel;
public class GuardianPonyModel extends GuardianEntityModel implements PonyModelMixin.Caster<GuardianEntity, SeaponyModel<GuardianEntity>, ModelPart> {
private final SeaponyModel<GuardianEntity> mixin;
public GuardianPonyModel(ModelPart tree) {
super(getTexturedModelData().createModel());
mixin = new SeaponyModel<>(tree);
}
@Override
public SeaponyModel<GuardianEntity> mixin() {
return mixin;
}
@Override
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, int color) {
mixin().render(matrices, vertices, light, overlay, color);
}
@Override
public void animateModel(GuardianEntity entity, float limbAngle, float limbDistance, float tickDelta) {
mixin().animateModel(entity, limbAngle, limbDistance, tickDelta);
}
@Override
public void copyStateTo(EntityModel<GuardianEntity> copy) {
mixin().copyStateTo(copy);
}
@Override
public void setAngles(GuardianEntity entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
mixin().setVisible(true);
mixin().setAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch);
}
}

View file

@ -6,30 +6,30 @@ import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.entity.npc.IllagerPonyRenderer;
public class IllagerPonyModel<T extends IllagerEntity> extends AlicornModel<T> {
public class IllagerPonyModel<S extends IllagerPonyRenderer.State> extends AlicornModel<S> {
public IllagerPonyModel(ModelPart tree) {
super(tree, false);
}
@Override
public void setModelAngles(T illager, float move, float swing, float ticks, float headYaw, float headPitch) {
super.setModelAngles(illager, move, swing, ticks, headYaw, headPitch);
public void setModelAngles(S state) {
super.setModelAngles(state);
IllagerEntity.State pose = state.state;
IllagerEntity.State pose = illager.getState();
boolean rightHanded = illager.getMainArm() == Arm.RIGHT;
boolean rightHanded = state.mainArm == Arm.RIGHT;
float mult = rightHanded ? 1 : -1;
ModelPart arm = getArm(illager.getMainArm());
ModelPart arm = getArm(state.mainArm);
if (pose == IllagerEntity.State.ATTACKING) {
// vindicator attacking
float f = MathHelper.sin(getSwingAmount() * (float) Math.PI);
float f1 = MathHelper.sin((1 - (1 - getSwingAmount()) * (1 - getSwingAmount())) * (float) Math.PI);
float f = MathHelper.sin(state.getSwingAmount() * (float) Math.PI);
float f1 = MathHelper.sin((1 - (1 - state.getSwingAmount()) * (1 - state.getSwingAmount())) * (float) Math.PI);
float cos = MathHelper.cos(ticks * 0.09F) * 0.05F + 0.05F;
float sin = MathHelper.sin(ticks * 0.067F) * 0.05F;
float cos = MathHelper.cos(state.age * 0.09F) * 0.05F + 0.05F;
float sin = MathHelper.sin(state.age * 0.067F) * 0.05F;
rightArm.roll = cos;
leftArm.roll = cos;
@ -37,7 +37,7 @@ public class IllagerPonyModel<T extends IllagerEntity> extends AlicornModel<T> {
rightArm.yaw = 0.15707964F;
leftArm.yaw = -0.15707964F;
arm.pitch = -1.8849558F + MathHelper.cos(ticks * 0.09F) * 0.15F;
arm.pitch = -1.8849558F + MathHelper.cos(state.age * 0.09F) * 0.15F;
arm.pitch += f * 2.2F - f1 * 0.4F;
rightArm.pitch += sin;
@ -46,10 +46,10 @@ public class IllagerPonyModel<T extends IllagerEntity> extends AlicornModel<T> {
// waving arms!
// rightArm.rotationPointZ = 0;
arm.pitch = (float) (-.75F * Math.PI);
arm.roll = mult * MathHelper.cos(ticks * 0.6662F) / 4;
arm.roll = mult * MathHelper.cos(state.age * 0.6662F) / 4;
arm.yaw = mult * 1.1F;
} else if (pose == IllagerEntity.State.BOW_AND_ARROW) {
aimBow(arm, ticks);
aimBow(state, arm, state.age);
}
}
}

View file

@ -2,19 +2,12 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.RenderLayer;
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.entity.mob.VexEntity;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.common.util.animation.Interpolator;
public class ParaspriteModel<T extends LivingEntity> extends EntityModel<T> {
private final ModelPart root;
import com.minelittlepony.client.render.entity.VexRenderer;
public class ParaspriteModel extends EntityModel<VexRenderer.State> {
private final ModelPart body;
private final ModelPart jaw;
private final ModelPart lips;
@ -24,70 +17,45 @@ public class ParaspriteModel<T extends LivingEntity> extends EntityModel<T> {
private final ModelPart leftWing2;
private final ModelPart rightWing2;
public ParaspriteModel(ModelPart tree) {
super(RenderLayer::getEntityTranslucent);
child = false;
root = tree;
body = tree.getChild("body");
public ParaspriteModel(ModelPart root) {
super(root, RenderLayer::getEntityTranslucent);
body = root.getChild("body");
jaw = body.getChild("jaw");
lips = body.getChild("lips");
leftWing = tree.getChild("leftWing");
rightWing = tree.getChild("rightWing");
leftWing2 = tree.getChild("leftWing2");
rightWing2 = tree.getChild("rightWing2");
leftWing = root.getChild("leftWing");
rightWing = root.getChild("rightWing");
leftWing2 = root.getChild("leftWing2");
rightWing2 = root.getChild("rightWing2");
}
@Override
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, int color) {
root.render(matrices, vertices, light, overlay, color);
}
@Override
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch) {
root.pitch = MathHelper.clamp((float)entity.getVelocity().horizontalLength() / 10F, 0, 0.1F);
public void setAngles(VexRenderer.State state) {
root.pitch = state.bodyPitch;
body.pitch = 0;
root.pitch = state.pitch * MathHelper.RADIANS_PER_DEGREE;
root.yaw = state.yawDegrees * MathHelper.RADIANS_PER_DEGREE;
if (entity.hasPassengers()) {
root.yaw = 0;
root.pitch = 0;
} else {
root.yaw = headYaw * 0.017453292F;
root.pitch = headPitch * 0.017453292F;
}
float sin = (float)Math.sin(ticks) / 2F;
float cos = (float)Math.cos(ticks) / 3F;
float jawOpenAmount = Interpolator.linear(entity.getUuid()).interpolate("jawOpen", entity instanceof VexEntity vex && vex.isCharging() ? 1 : 0, 10);
jaw.pivotY = Math.max(0, 1.2F * jawOpenAmount);
jaw.pivotY = Math.max(0, 1.2F * state.jawOpenAmount);
lips.pivotY = jaw.pivotY - 0.9F;
lips.visible = jawOpenAmount > 0;
body.pitch += 0.3F * jawOpenAmount;
jaw.pitch = 0.4F * jawOpenAmount;
lips.pitch = 0.2F * jawOpenAmount;
float basWingExpand = 1;
float innerWingExpand = basWingExpand / 2F;
lips.visible = state.jawOpenAmount > 0;
body.pitch += 0.3F * state.jawOpenAmount;
jaw.pitch = 0.4F * state.jawOpenAmount;
lips.pitch = 0.2F * state.jawOpenAmount;
leftWing.pitch = 0;
leftWing.roll = basWingExpand + cos + 0.3F;
leftWing.yaw = basWingExpand - sin;
leftWing.roll = state.wingRoll;
leftWing.yaw = state.wingYaw;
rightWing.pitch = 0;
rightWing.roll = -basWingExpand - cos - 0.3F;
rightWing.yaw = -basWingExpand + sin;
sin = -(float)Math.sin(ticks + Math.PI / 4F) / 2F;
cos = (float)Math.cos(ticks + Math.PI / 4F) / 3F;
rightWing.roll = -state.wingRoll;
rightWing.yaw = -state.wingYaw;
leftWing2.pitch = 0;
leftWing2.roll = innerWingExpand + sin - 0.3F;
leftWing2.yaw = innerWingExpand - cos + 0.3F;
leftWing2.roll = state.innerWingRoll;
leftWing2.yaw = state.innerWingPitch;
rightWing2.pitch = 0;
rightWing2.roll = -innerWingExpand - sin + 0.3F;
rightWing2.yaw = -innerWingExpand + cos - 0.3F;
rightWing2.roll = -state.innerWingRoll;
rightWing2.yaw = -state.innerWingPitch;
}
}

View file

@ -1,20 +1,14 @@
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> {
public class PiglinPonyModel extends ZomponyModel<PonyPiglinRenderer.State> {
private final ModelPart leftFlap;
private final ModelPart rightFlap;
@ -45,11 +39,11 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
}
@Override
public void setModelAngles(HostileEntity entity, float move, float swing, float ticks, float headYaw, float headPitch) {
super.setModelAngles(entity, move, swing, ticks, headYaw, headPitch);
public void setModelAngles(PonyPiglinRenderer.State state) {
super.setModelAngles(state);
float progress = ticks * 0.1F + move * 0.5F;
float range = 0.08F + swing * 0.4F;
float progress = state.age * 0.1F + state.limbFrequency * 0.5F;
float range = 0.08F + state.limbAmplitudeMultiplier * 0.4F;
rightFlap.roll = -0.5235988F - MathHelper.cos(progress * 1.2F) * range;
leftFlap.roll = 0.5235988F + MathHelper.cos(progress) * range;
}
@ -62,10 +56,10 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
}
@Override
protected void rotateLegs(float move, float swing, float ticks, HostileEntity entity) {
super.rotateLegs(move, swing, ticks, entity);
protected void rotateLegs(PonyPiglinRenderer.State state, float move, float swing, float ticks) {
super.rotateLegs(state, move, swing, ticks);
if (activity == PiglinActivity.ADMIRING_ITEM) {
if (state.activity == PiglinActivity.ADMIRING_ITEM) {
leftArm.yaw = 0.5F;
leftArm.pitch = -1.9F;
leftArm.pivotY += 4;
@ -75,7 +69,7 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
head.yaw = 0;
head.roll = MathHelper.sin(ticks / 10) / 3F;
} else if (activity == PiglinActivity.DANCING) {
} else if (state.activity == PiglinActivity.DANCING) {
float speed = ticks / 60;
@ -101,7 +95,7 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
}
@Override
protected boolean isZombified(HostileEntity entity) {
return !(entity instanceof AbstractPiglinEntity);
protected boolean shouldLiftBothArms(PonyPiglinRenderer.State state) {
return state.zombified && super.shouldLiftBothArms(state);
}
}

View file

@ -7,16 +7,16 @@ import net.minecraft.entity.mob.IllagerEntity;
import net.minecraft.util.Arm;
import com.minelittlepony.client.model.entity.race.ChangelingModel;
import com.minelittlepony.client.render.entity.npc.PillagerRenderer;
import com.minelittlepony.client.render.entity.npc.IllagerPonyRenderer;
public class PillagerPonyModel extends ChangelingModel<PillagerRenderer.State> {
public class PillagerPonyModel extends ChangelingModel<IllagerPonyRenderer.State> {
public PillagerPonyModel(ModelPart tree) {
super(tree, false);
}
@Override
protected BipedEntityModel.ArmPose getArmPose(PlayerEntityRenderState state, Arm arm) {
ArmPose holdingPose = getHoldingPose(((PillagerRenderer.State)state).state);
ArmPose holdingPose = getHoldingPose(((IllagerPonyRenderer.State)state).state);
if (holdingPose != ArmPose.EMPTY) {
boolean isMain = state.mainArm == Arm.RIGHT;

View file

@ -2,16 +2,17 @@ package com.minelittlepony.client.model.entity;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.util.math.MathHelper;
public class SaddleModel<T extends LivingEntityRenderState> extends EntityModel<T> {
import com.minelittlepony.client.render.entity.StriderRenderer;
public class SaddleModel extends EntityModel<StriderRenderer.State> {
public SaddleModel(ModelPart tree) {
super(tree);
}
@Override
public void setAngles(T entity) {
public void setAngles(StriderRenderer.State entity) {
root.pivotY = 2 - MathHelper.cos(entity.limbFrequency * 1.5F) * 3 * entity.limbAmplitudeMultiplier;
}
}

View file

@ -8,9 +8,9 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm;
import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.entity.state.SkeletonPonyRenderState;
import com.minelittlepony.client.render.entity.SkeleponyRenderer;
public class SkeleponyModel<T extends SkeletonPonyRenderState> extends AlicornModel<T> {
public class SkeleponyModel<T extends SkeleponyRenderer.State> extends AlicornModel<T> {
public SkeleponyModel(ModelPart tree) {
super(tree, false);
vestRenderList.clear();

View file

@ -2,12 +2,10 @@ 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 LivingEntityRenderState> extends BipedEntityModel<T> {
import com.minelittlepony.client.render.entity.StriderRenderer;
public class SpikeModel extends BipedEntityModel<StriderRenderer.State> {
private final ModelPart tail;
private final ModelPart tail2;
@ -21,7 +19,7 @@ public class SpikeModel<T extends LivingEntityRenderState> extends BipedEntityMo
}
@Override
public void setAngles(T entity) {
public void setAngles(StriderRenderer.State entity) {
entity.limbFrequency *= 2;
entity.limbAmplitudeMultiplier *= 1.5F;
entity.baby = false;
@ -36,7 +34,7 @@ public class SpikeModel<T extends LivingEntityRenderState> extends BipedEntityMo
rightArm.pivotY++;
body.pitch += 0.15F;
if ((entity instanceof SaddleableRenderState strider && strider.isSaddled())) {
if (entity.saddled) {
leftArm.pitch = 3.15F;
leftArm.yaw = 1;
rightArm.pitch = 3.15F;
@ -50,10 +48,8 @@ public class SpikeModel<T extends LivingEntityRenderState> extends BipedEntityMo
leftLeg.pitch += 0.4F;
rightLeg.pitch += 0.4F;
} else {
float flailAmount = 1 + (float)MathHelper.clamp(entity.getVelocity().y * 10, 0, 7);
leftArm.roll -= 0.2F * flailAmount;
rightArm.roll += 0.2F * flailAmount;
leftArm.roll -= 0.2F * entity.flailAmount;
rightArm.roll += 0.2F * entity.flailAmount;
leftArm.pivotZ += 2;
leftArm.pitch -= 0.3F;
@ -61,7 +57,7 @@ public class SpikeModel<T extends LivingEntityRenderState> extends BipedEntityMo
rightArm.pivotZ += 2;
rightArm.pitch -= 0.3F;
if (entity instanceof StriderEntityRenderState strider && strider.cold) {
if (entity.cold) {
float armMotion = (float)Math.sin(entity.age / 10F) / 10F;
leftArm.pitch = -1 - armMotion;

View file

@ -1,39 +1,25 @@
package com.minelittlepony.client.model.entity;
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.ZomponyRenderer;
import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.mob.HostileEntity;
public class ZomponyModel<Zombie extends HostileEntity> extends AlicornModel<Zombie> {
private boolean isPegasus;
public class ZomponyModel<T extends ZomponyRenderer.State> extends AlicornModel<T> {
public ZomponyModel(ModelPart tree) {
super(tree, false);
}
@Override
public void animateModel(Zombie entity, float move, float swing, float ticks) {
super.animateModel(entity, move, swing, ticks);
isPegasus = entity.getUuid().getLeastSignificantBits() % 30 == 0;
}
@Override
protected void rotateLegs(float move, float swing, float ticks, Zombie entity) {
super.rotateLegs(move, swing, ticks, entity);
if (isZombified(entity)) {
MobPosingHelper.rotateUndeadArms(this, move, ticks);
protected void rotateLegs(T state, float move, float swing, float ticks) {
super.rotateLegs(state, move, swing, ticks);
if (shouldLiftBothArms(state)) {
MobPosingHelper.rotateUndeadArms(state, this, state.limbFrequency, state.age);
}
}
@Override
public Race getRace() {
return isPegasus ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
}
protected boolean isZombified(Zombie entity) {
return rightArmPose == ArmPose.EMPTY;
protected boolean shouldLiftBothArms(T state) {
return getArmPose(state, state.mainArm) == ArmPose.EMPTY;
}
}

View file

@ -7,11 +7,10 @@ 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 PonyRenderState> extends UnicornModel<T> implements WingedPonyModel<T> {
private PonyWings<AlicornModel<T>> wings;
private PonyWings<T> wings;
public AlicornModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms);
@ -21,11 +20,11 @@ public class AlicornModel<T extends PonyRenderState> extends UnicornModel<T> imp
public void init(ModelView context) {
super.init(context);
wings = addPart(context.findByName("wings"));
bodyRenderList.add(forPart(this::getWings).checked(() -> getRace().hasWings()));
bodyRenderList.add(forPart(this::getWings).checked(() -> currentState.getRace().hasWings()));
}
@Override
public SubModel getWings() {
public SubModel<T> getWings() {
return wings;
}
}

View file

@ -3,7 +3,6 @@ package com.minelittlepony.client.model.entity.race;
import net.minecraft.client.model.ModelPart;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class ChangelingModel<T extends PonyRenderState> extends AlicornModel<T> {
@ -13,15 +12,12 @@ public class ChangelingModel<T extends PonyRenderState> extends AlicornModel<T>
}
@Override
public boolean wingsAreOpen(ModelAttributes state) {
return (state.isFlying || state.isCrouching) && !state.isGliding;
public boolean wingsAreOpen(T state) {
return (state.attributes.isFlying || state.attributes.isCrouching) && !state.attributes.isGliding;
}
@Override
public float getWingRotationFactor(ModelAttributes state, float ticks) {
if (state.isFlying) {
return MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE;
}
return WINGS_RAISED_ANGLE;
public float getWingRotationFactor(T state, float ticks) {
return state.attributes.isFlying ? MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE : WINGS_RAISED_ANGLE;
}
}

View file

@ -10,7 +10,7 @@ import net.minecraft.client.model.ModelPart;
public class EarthPonyModel<T extends PonyRenderState> extends AbstractPonyModel<T> {
protected SubModel tail;
protected SubModel<T> tail;
protected PonySnout snout;
protected PonyEars ears;

View file

@ -10,7 +10,7 @@ import net.minecraft.client.model.ModelPart;
public class PegasusModel<T extends PonyRenderState> extends EarthPonyModel<T> implements WingedPonyModel<T> {
private PonyWings<PegasusModel<T>> wings;
private PonyWings<T> wings;
public PegasusModel(ModelPart tree, boolean smallArms) {
super(tree, smallArms);
@ -24,7 +24,7 @@ public class PegasusModel<T extends PonyRenderState> extends EarthPonyModel<T> i
}
@Override
public SubModel getWings() {
public SubModel<T> getWings() {
return wings;
}
}

View file

@ -2,13 +2,11 @@ package com.minelittlepony.client.model.entity.race;
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 PonyRenderState> extends UnicornModel<T> {
@ -45,21 +43,6 @@ public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
bodyRenderList.add(body).add(body::rotate).add(forPart(tail)).add(leftFin, centerFin, rightFin);
}
@Override
public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode);
// Seaponies can't sneak, silly
sneaking = false;
attributes.isCrouching = false;
}
@Override
protected void ponySleep() {}
@Override
protected void ponySit() {}
@Override
protected void setModelAngles(T entity) {
super.setModelAngles(entity);
@ -88,8 +71,8 @@ public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
}
@Override
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(state, move, swing, ticks, entity);
protected void rotateLegs(T state, float move, float swing, float ticks) {
super.rotateLegs(state, move, swing, ticks);
leftArm.pitch -= 1.4F;
leftArm.yaw -= 0.3F;
rightArm.pitch -= 1.4F;
@ -97,14 +80,14 @@ public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
}
@Override
protected void rotateLegsSwimming(T state, float move, float swing, float ticks, T entity) {
super.rotateLegsOnGround(state, move, swing, ticks, entity);
protected void rotateLegsSwimming(T state, float move, float swing, float ticks) {
rotateLegsOnGround(state, move, swing, ticks);
}
@Override
public void transform(BodyPart part, MatrixStack stack) {
public void transform(T state, BodyPart part, MatrixStack stack) {
stack.translate(0, 0.6F, 0);
super.transform(part, stack);
super.transform(state, part, stack);
}
@Override
@ -116,7 +99,6 @@ public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
}
public static class Armour<T extends PonyRenderState> extends PonyArmourModel<T> {
public Armour(ModelPart tree) {
super(tree);
rightLeg.hidden = true;
@ -124,22 +106,14 @@ public class SeaponyModel<T extends PonyRenderState> extends UnicornModel<T> {
}
@Override
public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode);
// Seaponies can't sneak, silly
sneaking = false;
protected void rotateLegsSwimming(T state, float move, float swing, float ticks) {
rotateLegsOnGround(state, move, swing, ticks);
}
@Override
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) {
public void transform(T state, BodyPart part, MatrixStack stack) {
stack.translate(0, 0.6F, 0);
super.transform(part, stack);
super.transform(state, part, stack);
}
}
}

View file

@ -39,7 +39,7 @@ public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> i
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, currentState.attributes.metadata.glowColor());
})).checked(() -> hasMagic(currentState) && isCasting(currentState)));
})).checked(() -> currentState.hasMagicGlow() && isCasting(currentState)));
}
@Override
@ -48,8 +48,8 @@ public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> i
}
@Override
protected void rotateLegs(T state, float move, float swing, float ticks, T entity) {
super.rotateLegs(state, move, swing, ticks, entity);
protected void rotateLegs(T state, float move, float swing, float ticks) {
super.rotateLegs(state, move, swing, ticks);
unicornArmRight.setAngles(0, 0, 0);
unicornArmRight.setPivot(-7, 12, -2);
@ -58,11 +58,6 @@ public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> i
unicornArmLeft.setPivot(-7, 12, -2);
}
@Override
public boolean isCasting(T state) {
return PonyConfig.getInstance().tpsmagic.get() && (!state.leftHandStack.isEmpty() || !state.rightHandStack.isEmpty());
}
@Override
protected void ponyCrouch(T state) {
super.ponyCrouch(state);
@ -72,7 +67,7 @@ public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> i
@Override
public ModelPart getArm(Arm side) {
if (hasMagic(currentState) && getArmPoseForSide(currentState, side) != ArmPose.EMPTY && PonyConfig.getInstance().tpsmagic.get()) {
if (currentState.hasMagicGlow() && getArmPoseForSide(currentState, side) != ArmPose.EMPTY && PonyConfig.getInstance().tpsmagic.get()) {
return side == Arm.LEFT ? unicornArmLeft : unicornArmRight;
}
return super.getArm(side);
@ -82,7 +77,7 @@ public class UnicornModel<T extends PonyRenderState> extends EarthPonyModel<T> i
protected void positionheldItem(T state, Arm arm, MatrixStack matrices) {
super.positionheldItem(state, arm, matrices);
if (!PonyConfig.getInstance().tpsmagic.get() || !hasMagic(state)) {
if (!PonyConfig.getInstance().tpsmagic.get() || !currentState.hasMagicGlow()) {
return;
}

View file

@ -1,6 +1,7 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.AbstractPiglinEntity;
import net.minecraft.entity.mob.ZombifiedPiglinEntity;
@ -14,12 +15,11 @@ import com.minelittlepony.api.pony.meta.Wearable;
public class Crown extends WearableGear {
public Crown(ModelPart tree) {
super(Wearable.CROWN, BodyPart.HEAD, 0.1F);
addPart(tree.getChild("crown"));
super(tree.getChild("crown"), Wearable.CROWN, BodyPart.HEAD, 0.1F);
}
@Override
public boolean canRender(PonyModel<?> model, Entity entity) {
public boolean canRender(PonyModel<?> model, EntityRenderState entity) {
return super.canRender(model, entity)
|| ((
entity instanceof AbstractPiglinEntity

View file

@ -2,8 +2,9 @@ package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.BodyPart;
@ -35,18 +36,18 @@ public class DeerAntlers extends WearableGear {
private int tint;
public DeerAntlers(ModelPart tree) {
super(Wearable.ANTLERS, BodyPart.HEAD, 0);
super(tree, Wearable.ANTLERS, BodyPart.HEAD, 0);
left = tree.getChild("left");
right = tree.getChild("right");
}
@Override
public boolean canRender(PonyModel<?> model, Entity entity) {
public boolean canRender(PonyModel<?> model, EntityRenderState entity) {
return isChristmasDay() || super.canRender(model, entity);
}
@Override
public void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
public <S extends BipedEntityRenderState & PonyModel.AttributedHolder> void pose(PonyModel<S> model, S state, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
float pi = MathHelper.PI * (float) Math.pow(swing, 16);
float mve = move * 0.6662f;
@ -56,7 +57,7 @@ public class DeerAntlers extends WearableGear {
bodySwing += 0.1F;
tint = model.getAttributes().metadata.glowColor();
tint = state.getAttributes().metadata.glowColor();
left.roll = bodySwing;
right.roll = -bodySwing;
}

View file

@ -11,8 +11,8 @@ import java.util.UUID;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
public class SaddleBags extends WearableGear {
@ -26,15 +26,16 @@ public class SaddleBags extends WearableGear {
private float dropAmount = 0;
public SaddleBags(ModelPart tree, Wearable wearable) {
super(wearable, BodyPart.BODY, 0);
super(tree, wearable, BodyPart.BODY, 0);
strap = tree.getChild("strap");
leftBag = tree.getChild("left_bag");
rightBag = tree.getChild("right_bag");
}
@SuppressWarnings("unchecked")
@Override
public void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
hangLow = model instanceof WingedPonyModel pegasus && pegasus.wingsAreOpen();
public <S extends BipedEntityRenderState & PonyModel.AttributedHolder> void pose(PonyModel<S> model, S state, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
hangLow = model instanceof WingedPonyModel pegasus && pegasus.wingsAreOpen(state);
float pi = MathHelper.PI * (float) Math.pow(swing, 16);
@ -46,8 +47,8 @@ public class SaddleBags extends WearableGear {
leftBag.pitch = bodySwing;
rightBag.pitch = bodySwing;
if (model instanceof WingedPonyModel pegasus && pegasus.getAttributes().isFlying) {
bodySwing = pegasus.getWingRotationFactor(ticks) - MathUtil.Angles._270_DEG;
if (model instanceof WingedPonyModel pegasus && state.getAttributes().isFlying) {
bodySwing = pegasus.getWingRotationFactor(state, ticks) - MathUtil.Angles._270_DEG;
bodySwing /= 10;
}
@ -59,7 +60,7 @@ public class SaddleBags extends WearableGear {
strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH;
dropAmount = hangLow ? 0.15F : 0;
dropAmount = model.getAttributes().getMainInterpolator().interpolate("dropAmount", dropAmount, 3);
dropAmount = state.getAttributes().getMainInterpolator().interpolate("dropAmount", dropAmount, 3);
}
@Override

View file

@ -6,10 +6,10 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.common.util.animation.Interpolator;
public class LionTail implements SubModel {
public class LionTail implements SubModel<PonyRenderState> {
private ModelPart tail;
@ -18,7 +18,7 @@ public class LionTail implements SubModel {
}
@Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
public void setPartAngles(PonyRenderState state, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
tail.resetTransform();
bodySwing *= 5;
@ -26,18 +26,18 @@ public class LionTail implements SubModel {
float baseSail = 1F;
float speed = limbSpeed > 0.01F ? 6 : 90;
Interpolator interpolator = attributes.getMainInterpolator();
Interpolator interpolator = state.attributes.getMainInterpolator();
float straightness = 1.6F * (1 + (float)Math.sin(animationProgress / speed) / 8F);
float twist = (float)Math.sin(Math.PI/2F + 2 * animationProgress / speed) / 16F;
float bend = attributes.motionRoll / 80F;
float bend = state.attributes.motionRoll / 80F;
if (attributes.isCrouching) {
if (state.attributes.isCrouching) {
baseSail += 1;
straightness += 0.5F;
}
if (attributes.isGoingFast || attributes.isSwimming) {
if (state.attributes.isGoingFast || state.attributes.isSwimming) {
straightness *= 2;
}
@ -84,19 +84,19 @@ public class LionTail implements SubModel {
tail5.roll += bend;
tail6.roll += bend;
if (attributes.isHorsey) {
if (state.attributes.isHorsey) {
tail.pivotZ = 14;
tail.pivotY = 7;
}
}
@Override
public void setVisible(boolean visible, ModelAttributes attributes) {
public void setVisible(boolean visible, PonyRenderState state) {
tail.visible = visible;
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
tail.render(stack, vertices, overlay, light, color);
}
}

View file

@ -6,11 +6,11 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.*;
import com.minelittlepony.mson.api.model.PartBuilder;
public class PonyEars implements SubModel, MsonModel {
public class PonyEars implements SubModel<PonyRenderState>, MsonModel {
private final ModelPart right;
private final ModelPart left;
@ -27,7 +27,7 @@ public class PonyEars implements SubModel, MsonModel {
}
@Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
public void setPartAngles(PonyRenderState state, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
right.resetTransform();
left.resetTransform();
@ -52,15 +52,15 @@ public class PonyEars implements SubModel, MsonModel {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
}
@Override
public void setVisible(boolean visible, ModelAttributes attributes) {
right.visible = visible && !attributes.metadata.race().isHuman();
left.visible = visible && !attributes.metadata.race().isHuman();
public void setVisible(boolean visible, PonyRenderState state) {
right.visible = visible && !state.getRace().isHuman();
left.visible = visible && !state.getRace().isHuman();
if (attributes.isHorsey) {
if (state.attributes.isHorsey) {
left.pivotX = -1;
right.pivotX = 1;
left.pivotY = right.pivotY = 1;

View file

@ -6,12 +6,12 @@ import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.meta.Gender;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.*;
import com.minelittlepony.mson.api.model.PartBuilder;
public class PonySnout implements SubModel, MsonModel {
public class PonySnout implements SubModel<PonyRenderState>, MsonModel {
private final ModelPart mare;
private final ModelPart stallion;
@ -34,15 +34,15 @@ public class PonySnout implements SubModel, MsonModel {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
}
@Override
public void setVisible(boolean visible, ModelAttributes attributes) {
visible &= !attributes.isHorsey
&& !attributes.metadata.race().isHuman()
public void setVisible(boolean visible, PonyRenderState state) {
visible &= !state.attributes.isHorsey
&& !state.attributes.metadata.race().isHuman()
&& PonyConfig.getInstance().snuzzles.get();
Gender gender = attributes.metadata.gender();
Gender gender = state.attributes.metadata.gender();
mare.visible = (visible && gender.isMare());
stallion.visible = (visible && gender.isStallion());

View file

@ -8,13 +8,14 @@ import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.TailShape;
import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.*;
import com.minelittlepony.util.MathUtil;
import java.util.List;
import java.util.stream.IntStream;
public class PonyTail implements SubModel, MsonModel {
public class PonyTail implements SubModel<PonyRenderState>, MsonModel {
private static final float TAIL_Z = 14;
private static final float TAIL_RIDING_Y = 3;
private static final float TAIL_RIDING_Z = 13;
@ -43,15 +44,15 @@ public class PonyTail implements SubModel, MsonModel {
}
@Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
boolean rainboom = attributes.isSwimming || attributes.isGoingFast;
public void setPartAngles(PonyRenderState state, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
boolean rainboom = state.attributes.isSwimming || state.attributes.isGoingFast;
tail.roll = rainboom ? 0 : MathHelper.cos(limbAngle * 0.8F) * 0.2f * limbSpeed;
tail.yaw = bodySwing * 5;
if (attributes.isCrouching && !rainboom) {
if (state.attributes.isCrouching && !rainboom) {
tail.setPivot(0, 0, TAIL_SNEAKING_Z);
tail.pitch = -model.body.pitch + 0.1F;
} else if (attributes.isSitting) {
} else if (state.attributes.isSitting) {
tail.pivotZ = TAIL_RIDING_Z;
tail.pivotY = TAIL_RIDING_Y;
tail.pitch = MathHelper.PI / 5;
@ -70,6 +71,10 @@ public class PonyTail implements SubModel, MsonModel {
tail.pivotY += 6;
tail.pivotZ++;
}
for (int i = 0; i < segments.size(); i++) {
segments.get(i).setAngles(i, this, state.attributes);
}
}
private void swingX(float ticks) {
@ -79,19 +84,19 @@ public class PonyTail implements SubModel, MsonModel {
}
@Override
public void setVisible(boolean visible, ModelAttributes attributes) {
public void setVisible(boolean visible, PonyRenderState state) {
tail.visible = visible;
tailStop = attributes.metadata.tailLength().ordinal();
shape = attributes.metadata.tailShape();
tailStop = state.attributes.metadata.tailLength().ordinal();
shape = state.attributes.metadata.tailShape();
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
stack.push();
tail.rotate(stack);
for (int i = 0; i < segments.size(); i++) {
segments.get(i).render(this, stack, vertices, i, overlay, light, color, attributes);
segments.get(i).render(stack, vertices, i, overlay, light, color);
}
stack.pop();
@ -99,15 +104,17 @@ public class PonyTail implements SubModel, MsonModel {
public static class Segment {
private final ModelPart tree;
private TailShape shape;
private boolean horsey;
public Segment(ModelPart tree) {
this.tree = tree;
}
public void render(PonyTail tail, MatrixStack stack, VertexConsumer renderContext, int index, int overlay, int light, int color, ModelAttributes attributes) {
if (index >= tail.tailStop) {
return;
}
public void setAngles(int index, PonyTail tail, ModelAttributes attributes) {
tree.visible = index >= tail.tailStop;
shape = tail.shape;
horsey = attributes.isHorsey;
if (attributes.isHorsey) {
tree.pitch = 0.5F;
@ -115,29 +122,35 @@ public class PonyTail implements SubModel, MsonModel {
} else {
tree.resetTransform();
}
}
if (attributes.isHorsey || tail.shape == TailShape.STRAIGHT) {
public void render(MatrixStack stack, VertexConsumer renderContext, int index, int overlay, int light, int color) {
if (!tree.visible) {
return;
}
if (horsey || shape == TailShape.STRAIGHT) {
tree.yaw = 0;
tree.render(stack, renderContext, overlay, light, color);
return;
}
stack.push();
if (tail.shape == TailShape.BUMPY) {
if (shape == TailShape.BUMPY) {
stack.translate(0, 0, -9/16F);
float scale = 1 + MathHelper.cos(index + 5) / 2F;
stack.scale(scale, 1, scale);
stack.translate(1 / 16F * scale - 0.1F, 0, -2 / 16F * scale);
tree.pivotZ = 9;
}
if (tail.shape == TailShape.SWIRLY) {
if (shape == TailShape.SWIRLY) {
stack.translate(0, 0, -6/16F);
float scale = 1 + MathHelper.cos(index + 10) / 5F;
stack.scale(1, 1, scale);
stack.translate(0, 0, -2 / 16F * scale);
tree.pivotZ = 9;
}
if (tail.shape == TailShape.SPIKY) {
if (shape == TailShape.SPIKY) {
stack.translate(0, 0, -6/16F);
float scale = 1 + MathHelper.cos(index + 10) / 5F;
stack.scale(1, 1, scale);

View file

@ -1,6 +1,5 @@
package com.minelittlepony.client.model.part;
import net.minecraft.client.model.Model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
@ -8,18 +7,19 @@ import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.MsonModel;
import com.minelittlepony.util.MathUtil;
public class PonyWings<T extends Model & WingedPonyModel<?>> implements SubModel, MsonModel {
public class PonyWings<S extends PonyRenderState> implements SubModel<S>, MsonModel {
protected T pegasus;
private WingedPonyModel<S> pegasus;
protected Wing leftWing;
protected Wing rightWing;
protected Wing<S> leftWing;
protected Wing<S> rightWing;
protected Wing legacyWing;
protected Wing<S> legacyWing;
public PonyWings(ModelPart tree) {
@ -44,22 +44,22 @@ public class PonyWings<T extends Model & WingedPonyModel<?>> implements SubModel
legacyWing.walkingRotationSpeed = walkingRotationSpeed;
}
public Wing getLeft() {
public Wing<S> getLeft(S state) {
return leftWing;
}
public Wing getRight() {
public Wing<S> getRight(S state) {
return (
pegasus.isEmbedded(Wearable.SADDLE_BAGS_BOTH)
|| pegasus.isEmbedded(Wearable.SADDLE_BAGS_LEFT)
|| pegasus.isEmbedded(Wearable.SADDLE_BAGS_RIGHT)
state.isEmbedded(Wearable.SADDLE_BAGS_BOTH)
|| state.isEmbedded(Wearable.SADDLE_BAGS_LEFT)
|| state.isEmbedded(Wearable.SADDLE_BAGS_RIGHT)
) ? legacyWing : rightWing;
}
@Override
public void setPartAngles(ModelAttributes attributes, float move, float swing, float bodySwing, float ticks) {
public void setPartAngles(S state, float move, float swing, float bodySwing, float ticks) {
float flap = 0;
float progress = pegasus.getSwingAmount();
float progress = state.getSwingAmount();
if (progress > 0) {
flap = MathHelper.sin(MathHelper.sqrt(progress) * MathHelper.TAU);
@ -72,38 +72,58 @@ public class PonyWings<T extends Model & WingedPonyModel<?>> implements SubModel
flap = MathHelper.cos(mve + pi) * srt;
}
getLeft().rotateWalking(flap);
getRight().rotateWalking(-flap);
float flapAngle = MathUtil.Angles._270_DEG;
if (pegasus.wingsAreOpen()) {
flapAngle = pegasus.getWingRotationFactor(ticks);
if (!attributes.isCrouching && pegasus.isBurdened()) {
if (pegasus.wingsAreOpen(state)) {
flapAngle = pegasus.getWingRotationFactor(state, ticks);
if (!state.attributes.isCrouching && pegasus.isBurdened(state)) {
flapAngle -= 1F;
}
} else {
flapAngle = MathUtil.Angles._270_DEG - 0.9F + (float)Math.sin(ticks / 10) / 15F;
}
if (!pegasus.getAttributes().isFlying) {
flapAngle = attributes.getMainInterpolator().interpolate("wingFlap", flapAngle, 10);
if (!state.attributes.isFlying) {
flapAngle = state.attributes.getMainInterpolator().interpolate("wingFlap", flapAngle, 10);
}
getLeft().rotateFlying(flapAngle);
getRight().rotateFlying(-flapAngle);
boolean extended = pegasus.wingsAreOpen(state);
boolean bags = !extended && state.isWearing(Wearable.SADDLE_BAGS_BOTH);
boolean useLegacyWing = (
state.isEmbedded(Wearable.SADDLE_BAGS_BOTH)
|| state.isEmbedded(Wearable.SADDLE_BAGS_LEFT)
|| state.isEmbedded(Wearable.SADDLE_BAGS_RIGHT)
);
leftWing.open = extended;
leftWing.bags = bags;
leftWing.setAngles(state, flap, flapAngle);
rightWing.open = extended;
rightWing.bags = bags;
rightWing.setAngles(state, -flap, -flapAngle);
if (legacyWing != rightWing) {
rightWing.root.hidden = useLegacyWing;
legacyWing.root.hidden = !useLegacyWing;
legacyWing.open = extended;
legacyWing.bags = bags;
legacyWing.setAngles(state, -flap, -flapAngle);
}
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
getLeft().render(stack, vertices, overlay, light, color);
getRight().render(stack, vertices, overlay, light, color);
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
leftWing.render(stack, vertices, overlay, light, color);
rightWing.render(stack, vertices, overlay, light, color);
legacyWing.render(stack, vertices, overlay, light, color);
}
public static class Wing implements MsonModel {
public static class Wing<S extends PonyRenderState> implements MsonModel {
protected WingedPonyModel<?> pegasus;
private final ModelPart root;
protected final ModelPart extended;
protected final ModelPart folded;
@ -111,49 +131,36 @@ public class PonyWings<T extends Model & WingedPonyModel<?>> implements SubModel
private float wingScale = 1;
private float walkingRotationSpeed = 0.15F;
public boolean hidden;
public boolean open;
public boolean bags;
public Wing(ModelPart tree) {
root = tree;
extended = tree.getChild("extended");
folded = tree.getChild("folded");
}
@Override
public void init(ModelView context) {
pegasus = context.getModel();
}
public void rotateWalking(float swing) {
public void setAngles(S state, float swing, float roll) {
root.pivotY = root.getDefaultTransform().pivotY() + (bags ? 0.198F / wingScale : 0);
root.xScale = wingScale;
root.yScale = wingScale;
root.zScale = wingScale;
extended.visible = open;
folded.visible = !open;
folded.yaw = swing * walkingRotationSpeed;
if (pegasus.getRace().hasBugWings()) {
if (state.getRace().hasBugWings()) {
extended.yaw = folded.yaw;
}
}
public void rotateFlying(float roll) {
extended.roll = roll;
if (pegasus.getRace().hasBugWings()) {
if (state.getRace().hasBugWings()) {
folded.roll = roll;
}
}
public void render(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
stack.push();
stack.scale(wingScale, wingScale, wingScale);
if (pegasus.wingsAreOpen()) {
extended.render(stack, vertices, overlay, light, color);
} else {
boolean bags = pegasus.isWearing(Wearable.SADDLE_BAGS_BOTH);
if (bags) {
stack.push();
stack.translate(0, 0, 0.198F);
}
folded.render(stack, vertices, overlay, light, color);
if (bags) {
stack.pop();
}
}
stack.pop();
public void render(MatrixStack matrices, VertexConsumer vertices, int overlay, int light, int color) {
root.render(matrices, vertices, overlay, light, color);
}
}
}

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.model.part;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.mson.api.MsonModel;
import net.minecraft.client.model.ModelPart;
@ -9,7 +9,7 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
public class SeaponyTail implements SubModel, MsonModel {
public class SeaponyTail implements SubModel<PonyRenderState>, MsonModel {
private final ModelPart tailBase;
private final ModelPart tailTip;
@ -22,14 +22,14 @@ public class SeaponyTail implements SubModel, MsonModel {
}
@Override
public void setPartAngles(ModelAttributes attributes, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
float rotation = attributes.isLyingDown ? 0 : MathHelper.sin(animationProgress * 0.536f) / 4;
public void setPartAngles(PonyRenderState state, float limbAngle, float limbSpeed, float bodySwing, float animationProgress) {
float rotation = state.attributes.isLyingDown ? 0 : MathHelper.sin(animationProgress * 0.536f) / 4;
tailBase.pitch = MathHelper.HALF_PI + rotation;
tailTip.pitch = rotation;
tailFins.pitch = rotation - MathHelper.HALF_PI;
float turn = MathHelper.clamp(attributes.motionRoll * 0.05F + bodySwing, -0.4F, 0.4F);
float turn = MathHelper.clamp(state.attributes.motionRoll * 0.05F + bodySwing, -0.4F, 0.4F);
tailBase.yaw = turn;
turn /= 2F;
@ -39,7 +39,7 @@ public class SeaponyTail implements SubModel, MsonModel {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
tailBase.render(stack, vertices, overlay, light, color);
}

View file

@ -8,10 +8,10 @@ import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.model.SubModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.render.MagicGlow;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class UnicornHorn implements SubModel {
public class UnicornHorn implements SubModel<PonyRenderState> {
private final ModelPart horn;
private final ModelPart glow;
@ -24,7 +24,7 @@ public class UnicornHorn implements SubModel {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color, ModelAttributes attributes) {
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlay, int light, int color) {
horn.render(stack, vertices, overlay, light, color);
}
@ -38,7 +38,7 @@ public class UnicornHorn implements SubModel {
}
@Override
public void setVisible(boolean visible, ModelAttributes attributes) {
public void setVisible(boolean visible, PonyRenderState state) {
horn.visible = visible;
glow.visible = visible;
}

View file

@ -2,8 +2,7 @@ package com.minelittlepony.client.render;
import net.minecraft.client.render.*;
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.util.*;
import java.util.function.BiFunction;
@ -16,7 +15,7 @@ public class ArmorRenderLayers extends RenderPhase {
return RenderLayer.of(decal ? "armor_decal_translucent_no_cull" : "armor_translucent_no_cull",
VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, VertexFormat.DrawMode.QUADS, 256, true, false, MultiPhaseParameters.builder()
.program(ARMOR_CUTOUT_NO_CULL_PROGRAM)
.texture(new RenderPhase.Texture(texture, false, false))
.texture(new RenderPhase.Texture(texture, TriState.FALSE, false))
.transparency(TRANSLUCENT_TRANSPARENCY)
.cull(DISABLE_CULLING)
.lightmap(ENABLE_LIGHTMAP)

View file

@ -1,21 +1,12 @@
package com.minelittlepony.client.render;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
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.render.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
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 {
@ -35,15 +26,21 @@ public final class DebugBoundingBoxRenderer {
stack.push();
stack.translate(-offset.x, -offset.y, -offset.z);
Box boundingBox = PonyBounds.getBoundingBox(state.pony, state);
double x = -state.x;
double y = -state.y;
double z = -state.z;
VertexConsumer vertices = matrices.getBuffer(RenderLayer.getLines());
WorldRenderer.drawBox(stack, vertices, boundingBox.offset(x, y, z), 1, 1, 0, 1);
VertexRendering.drawBox(stack, vertices, getBoundingBox(state).offset(x, y, z), 1, 1, 0, 1);
stack.pop();
}
public static Box getBoundingBox(PonyRenderState state) {
final float scale = state.getScaleFactor();
final float width = state.width * scale;
final float height = state.height * scale;
return new Box(-width, 0, -width, width, height, width).offset(state.x, state.y, state.z);
}
}

View file

@ -10,7 +10,6 @@ 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;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.*;
@ -21,10 +20,8 @@ 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;
@ -35,9 +32,9 @@ public class EquineRenderManager<
S extends PonyRenderState,
M extends EntityModel<? super S> & PonyModel<S>> {
private Models<T, M> models;
@Nullable
private Function<S, Models<T, M>> modelsLookup;
private Models<M> models;
private Function<S, Models<M>> modelsLookup = s -> models;
private final PonyRenderContext<T, S, M> context;
private final Transformer<? super S> transformer;
@ -48,7 +45,7 @@ public class EquineRenderManager<
RenderSystem.disableBlend();
}
public EquineRenderManager(PonyRenderContext<T, S, M> context, Transformer<? super S> transformer, Models<T, M> models) {
public EquineRenderManager(PonyRenderContext<T, S, M> context, Transformer<? super S> transformer, Models<M> models) {
this.context = context;
this.transformer = transformer;
this.models = models;
@ -61,11 +58,11 @@ public class EquineRenderManager<
this(context, transformer, new Models(key));
}
public void setModelsLookup(@Nullable Function<S, Models<T, M>> modelsLookup) {
public void setModelsLookup(Function<S, Models<M>> modelsLookup) {
this.modelsLookup = modelsLookup;
}
public Models<T, M> getModels() {
public Models<M> getModels() {
return models;
}
@ -80,32 +77,28 @@ public class EquineRenderManager<
return frustrum.withCamera(entity, vanilla);
}
public void preRender(T entity, S state, ModelAttributes.Mode mode) {
Pony pony = context.getEntityPony(entity);
if (modelsLookup != null) {
public void updateState(T entity, S state, ModelAttributes.Mode mode) {
models = modelsLookup.apply(state);
context.setModel(models.body());
}
models.applyMetadata(pony.metadata());
state.updateState(entity, models.body(), pony, mode);
state.updateState(entity, models.body(), context.getEntityPony(entity), mode);
}
public void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw) {
float s = state.getScaleFactor();
stack.scale(s, s, s);
if (state instanceof PlayerEntityRenderState) {
if (state.attributes.isSitting) {
if (state instanceof PlayerEntityRenderState && state.attributes.isSitting) {
stack.translate(0, 0.125D, 0);
}
}
transformer.setupTransforms(state, stack, animationProgress, bodyYaw);
PonyPosture.of(state.attributes).apply(state, getModels().body(), stack, bodyYaw, state.age, 1);
if (RenderPass.getCurrent() == RenderPass.WORLD) {
PonyPosture.of(state.attributes).transform(state, stack);
}
}
public interface Transformer<S extends BipedEntityRenderState> {
public interface Transformer<S extends PonyRenderState> {
void setupTransforms(S state, MatrixStack stack, float animationProgress, float bodyYaw);
}
@ -113,7 +106,7 @@ public class EquineRenderManager<
SyncedPony getSyncedPony();
}
public interface ModelHolder<S extends BipedEntityRenderState, M extends EntityModel<S> & PonyModel<S>> {
public interface ModelHolder<S extends PonyRenderState, M extends EntityModel<S> & PonyModel<S>> {
void setModel(M model);
}

View file

@ -4,21 +4,22 @@ import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.HornedPonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.common.util.render.RenderLayerUtil;
import org.jetbrains.annotations.Nullable;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import net.minecraft.item.consume.UseAction;
import net.minecraft.registry.Registries;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.UseAction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.world.World;
@ -43,12 +44,13 @@ public class LevitatingItemRenderer {
|| mode == ModelTransformationMode.THIRD_PERSON_LEFT_HAND
|| mode == ModelTransformationMode.THIRD_PERSON_RIGHT_HAND)
) {
if (MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity) instanceof PonyRenderContext<LivingEntity, ?> context) {
Pony pony = context.getEntityPony(entity);
if (context.getInternalRenderer().getModels().body() instanceof HornedPonyModel model) {
var context = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity);
if (context != null) {
var state = context.getAndUpdateRenderState(entity, MinecraftClient.getInstance().getRenderTickCounter().getTickDelta(false));
matrix.push();
boolean doMagic = (mode.isFirstPerson() ? PonyConfig.getInstance().fpsmagic : PonyConfig.getInstance().tpsmagic).get() && model.hasMagic();
boolean doMagic = (mode.isFirstPerson() ? PonyConfig.getInstance().fpsmagic : PonyConfig.getInstance().tpsmagic).get() && state.hasMagicGlow();
if (doMagic && mode.isFirstPerson()) {
setupPerspective(itemRenderer, entity, stack, left, matrix);
@ -57,7 +59,7 @@ public class LevitatingItemRenderer {
itemRenderer.renderItem(entity, stack, mode, left, matrix, renderContext, world, lightUv, OverlayTexture.DEFAULT_UV, posLong);
if (doMagic) {
VertexConsumerProvider interceptedContext = getProvider(pony, renderContext);
VertexConsumerProvider interceptedContext = getProvider(state.pony, renderContext);
if (stack.hasGlint()) {
stack = stack.copy();
@ -85,7 +87,6 @@ public class LevitatingItemRenderer {
return;
}
}
}
itemRenderer.renderItem(entity, stack, mode, left, matrix, renderContext, world, lightUv, OverlayTexture.DEFAULT_UV, posLong);
}

View file

@ -28,8 +28,8 @@ public class MobRenderers {
pony.switchRenderer(state, EntityType.VEX, VexRenderer::new);
pony.switchRenderer(state, EntityType.EVOKER, IllagerPonyRenderer::evoker);
pony.switchRenderer(state, EntityType.VINDICATOR, IllagerPonyRenderer::vindicator);
pony.switchRenderer(state, EntityType.ILLUSIONER, IllagerPonyRenderer.Illusionist::new);
pony.switchRenderer(state, EntityType.PILLAGER, PillagerRenderer::new);
pony.switchRenderer(state, EntityType.ILLUSIONER, IllusionistPonyRenderer::new);
pony.switchRenderer(state, EntityType.PILLAGER, IllagerPonyRenderer::pillager);
});
public static final MobRenderers ZOMBIE = register("zombies", (state, pony) -> {
pony.switchRenderer(state, EntityType.ZOMBIE, ZomponyRenderer::zombie);

View file

@ -80,9 +80,9 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked")
@Nullable
public <T extends LivingEntity, S extends PonyRenderState, M extends EntityModel<S> & PonyModel<S>> PonyRenderContext<T, S, M> getPonyRenderer(@Nullable T entity) {
public <T extends LivingEntity, S extends PonyRenderState, M extends EntityModel<S> & PonyModel<S>, R extends LivingEntityRenderer<T, S, M> & PonyRenderContext<T, S, M>> R getPonyRenderer(@Nullable T entity) {
if (entity != null && MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity) instanceof PonyRenderContext c) {
return c;
return (R)c;
}
return null;

View file

@ -44,7 +44,6 @@ public class MobSkull implements ISkull {
@Override
public boolean bindPony(Pony pony) {
ponyHead.get().setMetadata(pony.metadata());
return true;
}

View file

@ -23,7 +23,7 @@ import org.joml.Vector3f;
public class PlayerPonySkull implements ISkull {
private AbstractPonyModel<?> ponyHead;
private final Map<PlayerModelKey<?, AbstractPonyModel<?>>, AbstractPonyModel<?>> modelCache = new HashMap<>();
private final Map<PlayerModelKey<AbstractPonyModel<?>>, AbstractPonyModel<?>> modelCache = new HashMap<>();
private final DJPon3EarsModel deadMau5 = ModelType.DJ_PON_3.createModel();
@ -61,7 +61,6 @@ public class PlayerPonySkull implements ISkull {
}
}
ponyHead = modelCache.computeIfAbsent(ModelType.getPlayerModel(race), key -> key.getKey(false).createModel());
ponyHead.setMetadata(pony.metadata());
return true;
}

View file

@ -3,7 +3,6 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.ArmourLayer;
import com.minelittlepony.client.model.armour.ArmourRendererPlugin;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.entity.*;
@ -26,6 +25,7 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.equipment.EquipmentModel.LayerType;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.util.math.Direction;
@ -112,7 +112,7 @@ public class PonySkullRenderer {
VertexConsumer vertices = renderContext.getBuffer(layer);
selectedSkull.setAngles(yaw, animationProgress);
selectedSkull.render(stack, vertices, light, OverlayTexture.DEFAULT_UV, Color.argbToHex(ArmourRendererPlugin.INSTANCE.get().getArmourAlpha(EquipmentSlot.HEAD, ArmourLayer.OUTER), 1, 1, 1));
selectedSkull.render(stack, vertices, light, OverlayTexture.DEFAULT_UV, Color.argbToHex(ArmourRendererPlugin.INSTANCE.get().getArmourAlpha(EquipmentSlot.HEAD, LayerType.HUMANOID), 1, 1, 1));
stack.pop();

View file

@ -55,7 +55,7 @@ public abstract class AbstractPonyRenderer<
@Override
public void updateRenderState(T entity, S state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
manager.preRender(entity, state, ModelAttributes.Mode.THIRD_PERSON);
manager.updateState(entity, state, ModelAttributes.Mode.THIRD_PERSON);
}
protected void addFeatures(EntityRendererFactory.Context context) {
@ -83,7 +83,7 @@ public abstract class AbstractPonyRenderer<
@Override
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);
DebugBoundingBoxRenderer.render(state, stack, vertices);
}
@Override

View file

@ -2,6 +2,7 @@ package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.*;
import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.passive.AllayEntity;
import net.minecraft.util.Identifier;
@ -12,29 +13,53 @@ import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.BreezieModel;
import java.util.UUID;
/**
* AKA a breezie :D
*/
public class AllayRenderer extends MobEntityRenderer<AllayEntity, BreezieModel<AllayEntity>> {
public class AllayRenderer extends MobEntityRenderer<AllayEntity, AllayRenderer.State, BreezieModel> {
public static final Identifier BREEZIE_PONIES = MineLittlePony.id("textures/entity/allay/pony");
public AllayRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.ALLAY.createModel(), 0.4f);
addFeature(new HeldItemFeatureRenderer<AllayEntity, BreezieModel<AllayEntity>>(this, context.getHeldItemRenderer()));
addFeature(new HeldItemFeatureRenderer<State, BreezieModel>(this, context.getItemRenderer()));
}
@Override
public Identifier getTexture(AllayEntity allayEntity) {
return MineLittlePony.getInstance().getVariatedTextures().get(BREEZIE_PONIES, allayEntity).orElse(DefaultPonySkinHelper.STEVE);
public State createRenderState() {
return new State();
}
public void updateRenderState(AllayEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.uuid = entity.getUuid();
state.dancing = entity.isDancing();
state.spinning = entity.isSpinning();
state.spinningAnimationTicks = entity.getSpinningAnimationTicks(tickDelta);
state.itemHoldAnimationTicks = entity.getItemHoldAnimationTicks(tickDelta);
}
@Override
protected void scale(AllayEntity entity, MatrixStack stack, float ticks) {
stack.scale(0.4F, 0.4F, 0.4F);
public Identifier getTexture(State state) {
return MineLittlePony.getInstance().getVariatedTextures().get(BREEZIE_PONIES, state.uuid).orElse(DefaultPonySkinHelper.STEVE);
}
@Override
protected void scale(State state, MatrixStack matrices) {
matrices.scale(0.4F, 0.4F, 0.4F);
}
@Override
protected int getBlockLight(AllayEntity allayEntity, BlockPos blockPos) {
return 15;
}
public static class State extends BipedEntityRenderState {
public UUID uuid;
public boolean dancing;
public boolean spinning;
public float spinningAnimationTicks;
public float itemHoldAnimationTicks;
}
}

View file

@ -1,16 +1,17 @@
package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.PreviewModel;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.render.entity.state.PlayerPonyRenderState;
import com.minelittlepony.util.MathUtil;
import java.util.function.Predicate;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.Identifier;
@ -21,47 +22,37 @@ public class AquaticPlayerPonyRenderer extends FormChangingPlayerPonyRenderer {
}
@Override
public void render(AbstractClientPlayerEntity player, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int light) {
super.render(player, entityYaw, tickDelta, stack, renderContext, light);
if (!(player instanceof PreviewModel) && transformed && player.getVelocity().length() > 0.1F) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);
double y = player.getEntityWorld().getRandom().nextTriangular(player.getY(), 1);
double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1);
player.getEntityWorld().addParticle(ParticleTypes.BUBBLE, x, y, z, 0, 0, 0);
}
protected Race getPlayerRace(PlayerPonyRenderState state) {
Race race = super.getPlayerRace(state);
return ((State)state).skinOverride != null ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
}
protected class State extends FormChangingPlayerPonyRenderer.State {
@Override
protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
Race race = super.getPlayerRace(entity, pony);
return transformed ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
}
@Override
protected void setupTransforms(AbstractClientPlayerEntity player, MatrixStack matrices, float animationProgress, float bodyYaw, float tickDelta, float scale) {
if (transformed) {
matrices.translate(0, 0.6 * scale, 0);
if (player.isInSneakingPose()) {
matrices.translate(0, 0.125 * scale, 0);
}
}
super.setupTransforms(player, matrices, animationProgress, bodyYaw, tickDelta, scale);
}
@Override
protected void updateForm(AbstractClientPlayerEntity player) {
super.updateForm(player);
if (!(player instanceof PreviewModel)) {
float state = transformed ? 100 : 0;
float interpolated = getInternalRenderer().getModels().body().getAttributes().getMainInterpolator().interpolate("seapony_state", state, 5);
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
yOffset = skinOverride != null ? (0.6 + (isInSneakingPose ? 0.125 : 0)) : 0;
pose = EntityPose.STANDING;
isInSneakingPose = false;
attributes.isCrouching = false;
if (!isPreviewModel) {
float state = skinOverride != null ? 100 : 0;
float interpolated = attributes.getMainInterpolator().interpolate("seapony_state", state, 5);
if (!MathUtil.compareFloats(interpolated, state)) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);
double y = player.getEntityWorld().getRandom().nextTriangular(player.getY() + player.getHeight() * 0.5F, 1);
double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1);
double x = entity.getEntityWorld().getRandom().nextTriangular(entity.getX(), 1);
double y = entity.getEntityWorld().getRandom().nextTriangular(entity.getY() + entity.getHeight() * 0.5F, 1);
double z = entity.getEntityWorld().getRandom().nextTriangular(entity.getZ(), 1);
player.getEntityWorld().addParticle(ParticleTypes.END_ROD, x, y, z, 0, 0, 0);
entity.getEntityWorld().addParticle(ParticleTypes.END_ROD, x, y, z, 0, 0, 0);
}
if (!isPreviewModel && skinOverride != null && entity.getVelocity().length() > 0.1F) {
double x = entity.getEntityWorld().getRandom().nextTriangular(entity.getX(), 1);
double y = entity.getEntityWorld().getRandom().nextTriangular(entity.getY(), 1);
double z = entity.getEntityWorld().getRandom().nextTriangular(entity.getZ(), 1);
entity.getEntityWorld().addParticle(ParticleTypes.BUBBLE, x, y, z, 0, 0, 0);
}
}
}
}

View file

@ -10,7 +10,6 @@ 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;
@ -69,7 +68,7 @@ public class EnderStallionRenderer extends PonyRenderer<EndermanEntity, EnderSta
return EYES;
}
public class State extends SkeletonPonyRenderState {
public class State extends SkeleponyRenderer.State {
public boolean angry;
@Nullable
public BlockState carriedBlock;

View file

@ -1,17 +1,21 @@
package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.render.entity.state.PlayerPonyRenderState;
import java.util.function.Predicate;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
public class FormChangingPlayerPonyRenderer extends PlayerPonyRenderer {
protected boolean transformed;
import org.jetbrains.annotations.Nullable;
public class FormChangingPlayerPonyRenderer extends PlayerPonyRenderer {
private final Identifier alternateFormSkinId;
private final Predicate<AbstractClientPlayerEntity> formModifierPredicate;
@ -22,21 +26,32 @@ public class FormChangingPlayerPonyRenderer extends PlayerPonyRenderer {
this.formModifierPredicate = formModifierPredicate;
}
@Override
public Identifier getTexture(AbstractClientPlayerEntity player) {
if (transformed) {
return SkinsProxy.getInstance().getSkin(alternateFormSkinId, player).orElseGet(() -> super.getTexture(player));
}
return super.getTexture(player);
public PlayerEntityRenderState createRenderState() {
return new State();
}
@Override
protected final void preRender(AbstractClientPlayerEntity player, ModelAttributes.Mode mode) {
super.preRender(player, mode);
updateForm(player);
public Identifier getTexture(PlayerEntityRenderState state) {
if (((State)state).skinOverride != null) {
return ((State)state).skinOverride;
}
return super.getTexture(state);
}
protected void updateForm(AbstractClientPlayerEntity player) {
transformed = formModifierPredicate.test(player);
protected class State extends PlayerPonyRenderState {
@Nullable
public Identifier skinOverride;
@Override
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
skinOverride = formModifierPredicate.test((AbstractClientPlayerEntity)entity)
? getSkinOverride((AbstractClientPlayerEntity)entity)
: null;
}
protected Identifier getSkinOverride(AbstractClientPlayerEntity player) {
return SkinsProxy.getInstance().getSkin(alternateFormSkinId, player).orElse(null);
}
}
}

View file

@ -36,7 +36,7 @@ import net.minecraft.util.math.Vec3d;
public class PlayerPonyRenderer
extends PlayerEntityRenderer
implements PonyRenderContext<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> {
private final Function<Race, Models<AbstractClientPlayerEntity, ClientPonyModel<PlayerPonyRenderState>>> modelsCache;
private final Function<Race, Models<ClientPonyModel<PlayerPonyRenderState>>> modelsCache;
protected final EquineRenderManager<AbstractClientPlayerEntity, PlayerPonyRenderState, ClientPonyModel<PlayerPonyRenderState>> manager;
private ModelAttributes.Mode mode = ModelAttributes.Mode.THIRD_PERSON;
@ -78,7 +78,7 @@ public class PlayerPonyRenderer
public Vec3d getPositionOffset(PlayerEntityRenderState state) {
Vec3d offset = super.getPositionOffset(state);
return offset.multiply(((PonyRenderState)state).getScaleFactor());
return offset.add(state.baseScale * ((PlayerPonyRenderState)state).yOffset).multiply(((PonyRenderState)state).getScaleFactor());
}
@Override
@ -89,7 +89,7 @@ public class PlayerPonyRenderer
@Override
public void updateRenderState(AbstractClientPlayerEntity entity, PlayerEntityRenderState state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
manager.preRender(entity, (PlayerPonyRenderState)state, mode);
manager.updateState(entity, (PlayerPonyRenderState)state, mode);
}
public final PlayerPonyRenderState getAndUpdateRenderState(AbstractClientPlayerEntity entity, float tickDelta, ModelAttributes.Mode mode) {

View file

@ -1,17 +1,13 @@
package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.EntityRendererFactory;
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, PonyPiglinRenderer.State, PiglinPonyModel> {
public static final Identifier PIGLIN = MineLittlePony.id("textures/entity/piglin/piglin_pony.png");
@ -39,10 +35,11 @@ public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PonyPiglinRe
return new State();
}
public void updateRenderState(AbstractPiglinEntity entity, State state, float tickDelta) {
public void updateRenderState(HostileEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.activity = entity.getActivity();
state.shouldZombify = entity.shouldZombify();
state.zombified = entity instanceof ZombifiedPiglinEntity;
state.activity = entity instanceof AbstractPiglinEntity piglin ? piglin.getActivity() : PiglinActivity.DEFAULT;
state.shouldZombify = entity instanceof AbstractPiglinEntity piglin && piglin.shouldZombify();
}
@Override
@ -50,9 +47,9 @@ public class PonyPiglinRenderer extends PonyRenderer<HostileEntity, PonyPiglinRe
return super.isShaking(state) || state.shouldZombify;
}
public static class State extends PonyRenderState {
public static class State extends ZomponyRenderer.State {
public boolean shouldZombify;
public boolean zombified;
public PiglinActivity activity;
}
}

View file

@ -1,36 +1,40 @@
package com.minelittlepony.client.render.entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.mixin.IResizeable;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.GuardianPonyModel;
import com.minelittlepony.client.model.entity.race.SeaponyModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.GuardianEntityRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.ElderGuardianEntity;
import net.minecraft.entity.mob.GuardianEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
public class SeaponyRenderer extends GuardianEntityRenderer {
public class SeaponyRenderer extends PonyRenderer<GuardianEntity, SeaponyRenderer.State, SeaponyModel<SeaponyRenderer.State>> {
public static final Identifier SEAPONY = MineLittlePony.id("textures/entity/guardian/blueball.png");
private static final Identifier SEAPONY_TEXTURES = MineLittlePony.id("textures/entity/guardian");
public static final Identifier ELDER_SEAPONY = MineLittlePony.id("textures/entity/elder_guardian/blueball.png");
private static final Identifier ELDER_SEAPONY_TEXTURES = MineLittlePony.id("textures/entity/elder_guardian");
private final AbstractPonyRenderer<GuardianEntity, GuardianPonyModel> ponyRenderer;
private static final Identifier EXPLOSION_BEAM_TEXTURE = Identifier.ofVanilla("textures/entity/guardian_beam.png");
private static final RenderLayer LAYER = RenderLayer.getEntityCutoutNoCull(EXPLOSION_BEAM_TEXTURE);
private final float scale;
public SeaponyRenderer(EntityRendererFactory.Context context, TextureSupplier<State> texture, float scale) {
super(context, ModelType.GUARDIAN, texture, scale);
}
public SeaponyRenderer(EntityRendererFactory.Context context, TextureSupplier<GuardianEntity> texture, float scale) {
super(context);
ponyRenderer = AbstractPonyRenderer.proxy(context, ModelType.GUARDIAN, texture, scale, features, m -> model = m);
this.scale = scale;
@Override
public State createRenderState() {
return new State();
}
public static SeaponyRenderer guardian(EntityRendererFactory.Context context) {
@ -42,30 +46,135 @@ public class SeaponyRenderer extends GuardianEntityRenderer {
}
@Override
@NotNull
public final Identifier getTexture(GuardianEntity entity) {
return ponyRenderer.getTexture(entity);
public void updateRenderState(GuardianEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.spikesExtension = entity.getSpikesExtension(tickDelta);
state.tailAngle = entity.getTailAngle(tickDelta);
state.cameraPosVec = getScaledCameraPosVec(entity, tickDelta, state.getScaleFactor());
Entity cameraBeamTarget = getBeamTarget(entity);
state.rotationVec = cameraBeamTarget != null ? entity.getRotationVec(tickDelta) : null;
state.lookAtPos = cameraBeamTarget != null ? cameraBeamTarget.getCameraPosVec(tickDelta) : null;
LivingEntity beamTarget = entity.getBeamTarget();
if (beamTarget != null) {
state.beamProgress = entity.getBeamProgress(tickDelta);
state.beamTicks = entity.getBeamTicks() + tickDelta;
state.beamTargetPos = fromLerpedPosition(beamTarget, (double)beamTarget.getHeight() * 0.5, tickDelta);
} else {
state.beamTargetPos = null;
}
}
@Override
protected void scale(GuardianEntity entity, MatrixStack stack, float ticks) {
ponyRenderer.scale(entity, stack, ticks);
}
@Override
public void render(GuardianEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
ponyRenderer.manager.preRender(entity, ModelAttributes.Mode.THIRD_PERSON);
float height = entity.getStandingEyeHeight();
// aligns the beam to their horns
((IResizeable)entity).setStandingEyeHeight(2 * scale * ponyRenderer.manager.getScaleFactor());
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
((IResizeable)entity).setStandingEyeHeight(height);
}
@Override
protected void setupTransforms(GuardianEntity entity, MatrixStack stack, float animationProgress, float bodyYaw, float tickDelta, float scale) {
ponyRenderer.manager.setupTransforms(entity, stack, animationProgress, bodyYaw, tickDelta, scale);
public void render(State state, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
super.render(state, matrices, vertices, light);
Vec3d vec3d = state.beamTargetPos;
if (vec3d != null) {
float f = state.beamTicks * 0.5F % 1.0F;
matrices.push();
matrices.translate(0.0F, state.standingEyeHeight, 0.0F);
renderBeam(
matrices,
vertices.getBuffer(LAYER),
vec3d.subtract(state.cameraPosVec),
state.beamTicks,
state.beamProgress,
f
);
matrices.pop();
}
}
private static void renderBeam(MatrixStack matrices, VertexConsumer vertexConsumer, Vec3d vec3d, float beamTicks, float f, float g) {
float h = (float)(vec3d.length() + 1.0);
vec3d = vec3d.normalize();
float i = (float)Math.acos(vec3d.y);
float j = (float) (Math.PI / 2) - (float)Math.atan2(vec3d.z, vec3d.x);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(j * (180.0F / (float)Math.PI)));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(i * (180.0F / (float)Math.PI)));
float k = beamTicks * 0.05F * -1.5F;
float l = f * f;
int m = 64 + (int)(l * 191.0F);
int n = 32 + (int)(l * 191.0F);
int o = 128 - (int)(l * 64.0F);
float p = 0.2F;
float q = 0.282F;
float r = MathHelper.cos(k + (float) (Math.PI * 3.0 / 4.0)) * 0.282F;
float s = MathHelper.sin(k + (float) (Math.PI * 3.0 / 4.0)) * 0.282F;
float t = MathHelper.cos(k + (float) (Math.PI / 4)) * 0.282F;
float u = MathHelper.sin(k + (float) (Math.PI / 4)) * 0.282F;
float v = MathHelper.cos(k + ((float) Math.PI * 5.0F / 4.0F)) * 0.282F;
float w = MathHelper.sin(k + ((float) Math.PI * 5.0F / 4.0F)) * 0.282F;
float x = MathHelper.cos(k + ((float) Math.PI * 7.0F / 4.0F)) * 0.282F;
float y = MathHelper.sin(k + ((float) Math.PI * 7.0F / 4.0F)) * 0.282F;
float z = MathHelper.cos(k + (float) Math.PI) * 0.2F;
float aa = MathHelper.sin(k + (float) Math.PI) * 0.2F;
float ab = MathHelper.cos(k + 0.0F) * 0.2F;
float ac = MathHelper.sin(k + 0.0F) * 0.2F;
float ad = MathHelper.cos(k + (float) (Math.PI / 2)) * 0.2F;
float ae = MathHelper.sin(k + (float) (Math.PI / 2)) * 0.2F;
float af = MathHelper.cos(k + (float) (Math.PI * 3.0 / 2.0)) * 0.2F;
float ag = MathHelper.sin(k + (float) (Math.PI * 3.0 / 2.0)) * 0.2F;
float ai = 0.0F;
float aj = 0.4999F;
float ak = -1.0F + g;
float al = ak + h * 2.5F;
MatrixStack.Entry entry = matrices.peek();
vertex(vertexConsumer, entry, z, h, aa, m, n, o, 0.4999F, al);
vertex(vertexConsumer, entry, z, 0.0F, aa, m, n, o, 0.4999F, ak);
vertex(vertexConsumer, entry, ab, 0.0F, ac, m, n, o, 0.0F, ak);
vertex(vertexConsumer, entry, ab, h, ac, m, n, o, 0.0F, al);
vertex(vertexConsumer, entry, ad, h, ae, m, n, o, 0.4999F, al);
vertex(vertexConsumer, entry, ad, 0.0F, ae, m, n, o, 0.4999F, ak);
vertex(vertexConsumer, entry, af, 0.0F, ag, m, n, o, 0.0F, ak);
vertex(vertexConsumer, entry, af, h, ag, m, n, o, 0.0F, al);
float am = MathHelper.floor(beamTicks) % 2 == 0 ? 0.5F : 0.0F;
vertex(vertexConsumer, entry, r, h, s, m, n, o, 0.5F, am + 0.5F);
vertex(vertexConsumer, entry, t, h, u, m, n, o, 1.0F, am + 0.5F);
vertex(vertexConsumer, entry, x, h, y, m, n, o, 1.0F, am);
vertex(vertexConsumer, entry, v, h, w, m, n, o, 0.5F, am);
}
private static void vertex(VertexConsumer vertexConsumer, MatrixStack.Entry matrix, float x, float y, float z, int red, int green, int blue, float u, float v) {
vertexConsumer.vertex(matrix, x, y, z)
.color(red, green, blue, 255)
.texture(u, v)
.overlay(OverlayTexture.DEFAULT_UV)
.light(LightmapTextureManager.MAX_LIGHT_COORDINATE)
.normal(matrix, 0.0F, 1.0F, 0.0F);
}
@Nullable
private static Entity getBeamTarget(GuardianEntity guardian) {
Entity entity = MinecraftClient.getInstance().getCameraEntity();
return guardian.hasBeamTarget() ? guardian.getBeamTarget() : entity;
}
private Vec3d fromLerpedPosition(LivingEntity entity, double yOffset, float delta) {
double d = MathHelper.lerp((double)delta, entity.lastRenderX, entity.getX());
double e = MathHelper.lerp((double)delta, entity.lastRenderY, entity.getY()) + yOffset;
double f = MathHelper.lerp((double)delta, entity.lastRenderZ, entity.getZ());
return new Vec3d(d, e, f);
}
public static Vec3d getScaledCameraPosVec(GuardianEntity entity, float tickDelta, float scale) {
double d = MathHelper.lerp((double)tickDelta, entity.prevX, entity.getX());
double e = MathHelper.lerp((double)tickDelta, entity.prevY, entity.getY()) + ((double)entity.getStandingEyeHeight() * scale);
double f = MathHelper.lerp((double)tickDelta, entity.prevZ, entity.getZ());
return new Vec3d(d, e, f);
}
public static class State extends PonyRenderState {
public float spikesExtension;
public float tailAngle;
public Vec3d cameraPosVec = Vec3d.ZERO;
@Nullable
public Vec3d rotationVec;
@Nullable
public Vec3d lookAtPos;
@Nullable
public Vec3d beamTargetPos;
public float beamTicks;
public float beamProgress;
}
}

View file

@ -1,16 +1,23 @@
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.SkeleponyModel;
import com.minelittlepony.client.render.entity.feature.StrayClothingFeature;
import com.minelittlepony.client.render.entity.feature.AbstractClothingFeature;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.*;
import net.minecraft.util.Identifier;
public class SkeleponyRenderer<Skeleton extends AbstractSkeletonEntity> extends PonyRenderer<Skeleton, SkeleponyModel<Skeleton>> {
public class SkeleponyRenderer<T extends AbstractSkeletonEntity> extends PonyRenderer<T, SkeleponyRenderer.State, SkeleponyModel<SkeleponyRenderer.State>> {
public static final Identifier SKELETON = MineLittlePony.id("textures/entity/skeleton/skeleton_pony.png");
public static final Identifier WITHER = MineLittlePony.id("textures/entity/skeleton/skeleton_wither_pony.png");
public static final Identifier STRAY = MineLittlePony.id("textures/entity/skeleton/stray_pony.png");
@ -19,6 +26,11 @@ public class SkeleponyRenderer<Skeleton extends AbstractSkeletonEntity> extends
super(context, ModelType.SKELETON, TextureSupplier.of(texture), scale);
}
@Override
public SkeleponyRenderer.State createRenderState() {
return new State();
}
public static SkeleponyRenderer<SkeletonEntity> skeleton(EntityRendererFactory.Context context) {
return new SkeleponyRenderer<>(context, SKELETON, 1);
}
@ -30,4 +42,51 @@ public class SkeleponyRenderer<Skeleton extends AbstractSkeletonEntity> extends
public static SkeleponyRenderer<WitherSkeletonEntity> wither(EntityRendererFactory.Context context) {
return new SkeleponyRenderer<>(context, WITHER, 1.2F);
}
public static class StrayClothingFeature<
T extends AbstractSkeletonEntity,
S extends SkeleponyRenderer.State
> extends AbstractClothingFeature<T, S, SkeleponyModel<S>> {
public static final Identifier STRAY_SKELETON_OVERLAY = MineLittlePony.id("textures/entity/skeleton/stray_pony_overlay.png");
private final SkeleponyModel<S> overlayModel = ModelType.SKELETON_CLOTHES.createModel();
public StrayClothingFeature(LivingEntityRenderer<T, S, SkeleponyModel<S>> render) {
super(render);
}
@Override
protected SkeleponyModel<S> getOverlayModel() {
return overlayModel;
}
@Override
protected Identifier getOverlayTexture() {
return STRAY_SKELETON_OVERLAY;
}
}
public static class State 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

@ -3,35 +3,55 @@ package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.MobEntityRenderer;
import net.minecraft.client.render.entity.feature.SaddleFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.client.render.entity.state.SaddleableRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.passive.StriderEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.DefaultPonySkinHelper;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.SpikeModel;
public class StriderRenderer extends MobEntityRenderer<StriderEntity, EntityModel<StriderEntity>> {
import java.util.UUID;
public class StriderRenderer extends MobEntityRenderer<StriderEntity, StriderRenderer.State, SpikeModel> {
public static final Identifier DRAGON_PONIES = MineLittlePony.id("textures/entity/strider/pony");
public static final Identifier COLD_DRAGON_PONIES = MineLittlePony.id("textures/entity/strider/cold_pony");
private static final Identifier SADDLE = MineLittlePony.id("textures/entity/strider/strider_saddle_pony.png");
@SuppressWarnings({"unchecked", "rawtypes"})
public StriderRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.STRIDER.createModel(), 0.5F);
addFeature(new SaddleFeatureRenderer<>(this, ModelType.STRIDER_SADDLE.createModel(), SADDLE));
addFeature(new SaddleFeatureRenderer(this, ModelType.STRIDER_SADDLE.createModel(), SADDLE));
}
@Override
public Identifier getTexture(StriderEntity entity) {
return MineLittlePony.getInstance().getVariatedTextures().get(entity.isCold() ? COLD_DRAGON_PONIES : DRAGON_PONIES, entity).orElse(DefaultPonySkinHelper.STEVE);
public State createRenderState() {
return new State();
}
@Override
protected void scale(StriderEntity entity, MatrixStack stack, float ticks) {
public void updateRenderState(StriderEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.uuid = entity.getUuid();
state.cold = entity.isCold();
state.saddled = entity.isSaddled();
state.flailAmount = 1 + (float)MathHelper.clamp(entity.getVelocity().y * 10, 0, 7);
}
@Override
public Identifier getTexture(State state) {
return MineLittlePony.getInstance().getVariatedTextures().get(state.cold ? COLD_DRAGON_PONIES : DRAGON_PONIES, state.uuid).orElse(DefaultPonySkinHelper.STEVE);
}
@Override
protected void scale(State state, MatrixStack stack) {
float scale = 0.9375F;
if (entity.isBaby()) {
if (state.baby) {
scale *= 0.5F;
shadowRadius = 0.25F;
} else {
@ -42,7 +62,19 @@ public class StriderRenderer extends MobEntityRenderer<StriderEntity, EntityMode
}
@Override
protected boolean isShaking(StriderEntity entity) {
return entity.isCold();
protected boolean isShaking(State state) {
return state.cold;
}
public static class State extends BipedEntityRenderState implements SaddleableRenderState {
public UUID uuid;
public boolean cold;
public boolean saddled;
public float flailAmount;
@Override
public boolean isSaddled() {
return saddled;
}
}
}

View file

@ -1,16 +1,21 @@
package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.*;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.VexEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.DefaultPonySkinHelper;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.ParaspriteModel;
import com.minelittlepony.common.util.animation.Interpolator;
public class VexRenderer extends MobEntityRenderer<VexEntity, ParaspriteModel<VexEntity>> {
import java.util.UUID;
public class VexRenderer extends MobEntityRenderer<VexEntity, VexRenderer.State, ParaspriteModel> {
public static final Identifier PARASPRITE_PONIES = MineLittlePony.id("textures/entity/illager/vex_pony");
public VexRenderer(EntityRendererFactory.Context context) {
@ -18,13 +23,43 @@ public class VexRenderer extends MobEntityRenderer<VexEntity, ParaspriteModel<Ve
}
@Override
protected void scale(VexEntity entity, MatrixStack stack, float ticks) {
stack.scale(0.4F, 0.4F, 0.4F);
public State createRenderState() {
return new State();
}
@Override
public Identifier getTexture(VexEntity entity) {
return MineLittlePony.getInstance().getVariatedTextures().get(PARASPRITE_PONIES, entity).orElse(DefaultPonySkinHelper.STEVE);
public void updateRenderState(VexEntity entity, State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
state.bodyPitch = MathHelper.clamp((float)entity.getVelocity().horizontalLength() / 10F, 0, 0.1F);
state.jawOpenAmount = Interpolator.linear(entity.getUuid()).interpolate("jawOpen", entity instanceof VexEntity vex && vex.isCharging() ? 1 : 0, 10);
state.wingRoll = 1 + ((float)Math.cos(state.age) / 3F) + 0.3F;
state.wingYaw = 1 - ((float)Math.sin(state.age) / 2F);
state.innerWingRoll = 0.5F + (-(float)Math.sin(state.age + Math.PI / 4F) / 2F) - 0.3F;
state.innerWingPitch = 0.5F - ((float)Math.cos(state.age + Math.PI / 4F) / 3F) + 0.3F;
if (entity.hasPassengers()) {
state.yawDegrees = 0;
state.pitch = 0;
}
}
@Override
protected void scale(State entity, MatrixStack matrices) {
matrices.scale(0.4F, 0.4F, 0.4F);
}
@Override
public Identifier getTexture(State state) {
return MineLittlePony.getInstance().getVariatedTextures().get(PARASPRITE_PONIES, state.uuid).orElse(DefaultPonySkinHelper.STEVE);
}
public static class State extends LivingEntityRenderState {
public UUID uuid;
public float bodyPitch;
public boolean hasPassengers;
public float jawOpenAmount;
public float wingRoll;
public float wingYaw;
public float innerWingRoll;
public float innerWingPitch;
}
}

View file

@ -1,32 +1,38 @@
package com.minelittlepony.client.render.entity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.*;
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.meta.Race;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.ZomponyModel;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class ZomponyRenderer<Zombie extends HostileEntity> extends PonyRenderer<Zombie, ZomponyModel<Zombie>> {
public class ZomponyRenderer<T extends HostileEntity> extends PonyRenderer<T, ZomponyRenderer.State, ZomponyModel<ZomponyRenderer.State>> {
public static final Identifier ZOMBIE = MineLittlePony.id("textures/entity/zombie/zombie_pony.png");
public static final Identifier HUSK = MineLittlePony.id("textures/entity/zombie/husk_pony.png");
public static final Identifier DROWNED = MineLittlePony.id("textures/entity/zombie/drowned_pony.png");
public static final Identifier DEMON_CHILD = MineLittlePony.id("textures/entity/zombie/demon_child.png");
public ZomponyRenderer(EntityRendererFactory.Context context, TextureSupplier<Zombie> texture, float scale) {
protected ZomponyRenderer(EntityRendererFactory.Context context, TextureSupplier<State> texture, float scale) {
super(context, ModelType.ZOMBIE, texture, scale);
}
public static ZomponyRenderer<ZombieEntity> zombie(EntityRendererFactory.Context context) {
return new ZomponyRenderer<>(context, entity -> {
if (entity.isBaby() && entity.getUuid().getLeastSignificantBits() % 160 == 0) {
return DEMON_CHILD;
@Override
public State createRenderState() {
return new State();
}
return ZOMBIE;
}, 1);
public static ZomponyRenderer<ZombieEntity> zombie(EntityRendererFactory.Context context) {
return new ZomponyRenderer<>(context, entity -> entity.isCozyGlow ? DEMON_CHILD : ZOMBIE, 1);
}
public static ZomponyRenderer<HuskEntity> husk(EntityRendererFactory.Context context) {
@ -40,4 +46,20 @@ public class ZomponyRenderer<Zombie extends HostileEntity> extends PonyRenderer<
public static ZomponyRenderer<GiantEntity> giant(EntityRendererFactory.Context context) {
return new ZomponyRenderer<>(context, TextureSupplier.of(ZOMBIE), 6.8F);
}
public static class State extends PonyRenderState {
public boolean isWinged;
public boolean isCozyGlow;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
isCozyGlow = baby && entity.getUuid().getLeastSignificantBits() % 160 == 0;
isWinged = entity.getUuid().getLeastSignificantBits() % 30 == 0;
}
@Override
public Race getRace() {
return isWinged ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
}
}
}

View file

@ -18,7 +18,7 @@ import com.minelittlepony.client.render.entity.state.PonyRenderState;
public abstract class AbstractClothingFeature<
T extends LivingEntity,
S extends PonyRenderState,
M extends BipedEntityModel<S> & PonyModel<S>
M extends BipedEntityModel<? super S> & PonyModel<? super S>
> extends FeatureRenderer<S, M> {
protected final FeatureRendererContext<S, M> renderer;

View file

@ -33,7 +33,7 @@ public abstract class AbstractPonyFeature<
return context.getInternalRenderer().getModels().body();
}
protected Models<?, M> getModelWrapper() {
protected Models<M> getModelWrapper() {
return context.getInternalRenderer().getModels();
}
}

View file

@ -4,119 +4,71 @@ import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.common.util.Color;
import java.util.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
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;
import net.minecraft.component.type.EquippableComponent;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import net.minecraft.item.trim.ArmorTrim;
import net.minecraft.util.Colors;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.util.Identifier;
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) {
public class ArmourFeature<T extends LivingEntity, S extends PonyRenderState, M extends EntityModel<? super S> & PonyModel<S>> extends AbstractPonyFeature<S, M> {
private final PonifiedEquipmentRenderer equipmentRenderer;
public ArmourFeature(PonyRenderContext<T, S, M> context, EquipmentModelLoader modelLoader) {
super(context);
this.equipmentRenderer = new PonifiedEquipmentRenderer(modelLoader);
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, S entity, float limbDistance, float limbAngle) {
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle);
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle, equipmentRenderer);
}
public static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
public static <S extends PonyRenderState, 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();
float limbDistance, float limbAngle, PonifiedEquipmentRenderer equipmentRenderer) {
for (EquipmentSlot i : EquipmentSlot.values()) {
if (i.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.INNER, plugin);
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.OUTER, plugin);
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, i, ArmourLayer.INNER, equipmentRenderer);
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, i, ArmourLayer.OUTER, equipmentRenderer);
}
}
}
private static <S extends BipedEntityRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<?, ? extends PonyModel<S>> pony, MatrixStack matrices,
VertexConsumerProvider provider, int light, S entity,
private static <S extends PonyRenderState, V extends PonyArmourModel<S>> void renderArmor(
Models<? extends PonyModel<S>> models, MatrixStack matrices,
VertexConsumerProvider vertices, int light, S entity,
float limbDistance, float limbAngle,
float age, float headYaw, float headPitch,
EquipmentSlot armorSlot, ArmourLayer layer, ArmourRendererPlugin plugin) {
EquipmentSlot armorSlot, ArmourLayer layer, PonifiedEquipmentRenderer equipmentRenderer) {
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
for (ItemStack stack : plugin.getArmorStacks(entity, armorSlot, layer, ArmourRendererPlugin.ArmourType.ARMOUR)) {
if (stack.isEmpty()) {
continue;
}
EquippableComponent equippableComponent = stack.get(DataComponentTypes.EQUIPPABLE);
float glintAlpha = plugin.getGlintAlpha(armorSlot, stack);
boolean glint = glintAlpha > 0;
int color = plugin.getDyeColor(armorSlot, stack);
Set<PonyArmourModel<?>> models = glint ? new HashSet<>() : null;
ArmourTextureLookup textureLookup = plugin.getTextureLookup();
float alpha = plugin.getArmourAlpha(armorSlot, layer);
if (alpha > 0) {
for (ArmorMaterial.Layer armorLayer : textureLookup.getArmorLayers(stack, color)) {
ArmourTexture layerTexture = textureLookup.getTexture(stack, layer, armorLayer);
if (layerTexture == ArmourTexture.UNKNOWN) {
continue;
}
var m = pony.getArmourModel(stack, layer, layerTexture.variant()).orElse(null);
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
VertexConsumer armorConsumer = plugin.getArmourConsumer(armorSlot, provider, layerTexture.texture(), layer);
if (armorConsumer != null) {
int armorTint = Colors.WHITE;
if (armorLayer.isDyeable() && color != Colors.WHITE) {
armorTint = color;
}
m.render(matrices, armorConsumer, light, OverlayTexture.DEFAULT_UV, (armorTint & 0xFFFFFF) | ((int)(alpha * 255) << 24));
}
if (glint) {
models.add(m);
}
}
if (equippableComponent != null && hasModel(equippableComponent, armorSlot)) {
EquipmentModel.LayerType layerType = layer == ArmourLayer.INNER
? EquipmentModel.LayerType.HUMANOID_LEGGINGS
: EquipmentModel.LayerType.HUMANOID;
Identifier modelId = equippableComponent.model().orElseThrow();
equipmentRenderer.render(armorSlot, layerType, modelId, models, stack, matrices, vertices, light);
}
}
ArmorTrim trim = stack.get(DataComponentTypes.TRIM);
if (trim != null && stack.getItem() instanceof ArmorItem armor) {
float trimAlpha = plugin.getTrimAlpha(armorSlot, armor.getMaterial(), trim, layer);
if (trimAlpha > 0) {
var m = pony.getArmourModel(stack, layer, ArmourVariant.TRIM).orElse(null);
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
VertexConsumer trimConsumer = plugin.getTrimConsumer(armorSlot, provider, armor.getMaterial(), trim, layer);
if (trimConsumer != null) {
m.render(matrices, trimConsumer, light, OverlayTexture.DEFAULT_UV, 0xFFFFFFFF);
}
}
}
plugin.onArmourRendered(entity, matrices, vertices, armorSlot, layer, ArmourRendererPlugin.ArmourType.ARMOUR);
}
if (glint) {
VertexConsumer glintConsumer = plugin.getGlintConsumer(armorSlot, provider, layer);
if (glintConsumer != null) {
for (var m : models) {
m.render(matrices, glintConsumer, light, OverlayTexture.DEFAULT_UV, Color.argbToHex(glintAlpha, 1, 1, 1));
}
}
}
}
plugin.onArmourRendered(entity, matrices, provider, armorSlot, layer, ArmourRendererPlugin.ArmourType.ARMOUR);
private static boolean hasModel(EquippableComponent component, EquipmentSlot slot) {
return component.model().isPresent() && component.slot() == slot;
}
}

View file

@ -2,7 +2,6 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.PonyElytra;
import com.minelittlepony.client.model.armour.ArmourLayer;
@ -10,19 +9,18 @@ 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.equipment.EquipmentRenderer;
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.SkinTextures;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.EquippableComponent;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerModelPart;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Colors;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.util.Identifier;
public class ElytraFeature<
@ -32,10 +30,13 @@ public class ElytraFeature<
> extends AbstractPonyFeature<S, M> {
private static final Identifier TEXTURE = Identifier.ofVanilla("textures/entity/elytra.png");
private final PonyElytra<T> model = ModelType.ELYTRA.createModel();
private final PonyElytra<S> model = ModelType.ELYTRA.createModel();
public ElytraFeature(PonyRenderContext<T, S, M> context) {
private final EquipmentRenderer equipmentRenderer;
public ElytraFeature(PonyRenderContext<T, S, M> context, EquipmentRenderer equipmentRenderer) {
super(context);
this.equipmentRenderer = equipmentRenderer;
}
@Override
@ -43,24 +44,23 @@ public class ElytraFeature<
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
for (ItemStack stack : plugin.getArmorStacks(entity, EquipmentSlot.CHEST, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA)) {
EquippableComponent equippable = stack.get(DataComponentTypes.EQUIPPABLE);
if (equippable != null && !equippable.model().isEmpty()) {
Identifier equipmentModel = equippable.model().get();
float alpha = plugin.getElytraAlpha(stack, model, entity);
if (alpha <= 0) {
return;
}
VertexConsumer vertexConsumer = plugin.getElytraConsumer(stack, model, entity, provider, getElytraTexture(entity));
if (vertexConsumer == null) {
return;
}
matrices.push();
preRenderCallback(matrices);
model.setAngles(entity);
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, (Colors.WHITE & 0xFFFFFF) | (int)(alpha * 255) << 24);
preRenderCallback(entity, matrices);
equipmentRenderer.render(EquipmentModel.LayerType.WINGS, equipmentModel, model, stack, matrices, provider, light, getElytraTexture(entity));
matrices.pop();
}
}
plugin.onArmourRendered(entity, matrices, provider, EquipmentSlot.BODY, ArmourLayer.OUTER, ArmourRendererPlugin.ArmourType.ELYTRA);
}
@ -71,15 +71,15 @@ public class ElytraFeature<
body.transform(state, BodyPart.BODY, stack);
}
protected Identifier getElytraTexture(T entity) {
if (entity instanceof AbstractClientPlayerEntity player) {
SkinTextures textures = player.getSkinTextures();
protected Identifier getElytraTexture(S state) {
if (state instanceof PlayerEntityRenderState playerState) {
SkinTextures textures = playerState.skinTextures;
if (textures.elytraTexture() != null) {
return textures.elytraTexture();
}
if (textures.capeTexture() != null && player.isPartVisible(PlayerModelPart.CAPE)) {
if (textures.capeTexture() != null && state.capeVisible) {
return textures.capeTexture();
}
}

View file

@ -5,7 +5,6 @@ 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;
@ -77,11 +76,11 @@ public class GearFeature<
final M model = getModelWrapper().body();
final Object2FloatMap<BodyPart> renderStackingOffsets = new Object2FloatLinkedOpenHashMap<>();
for (var entry : randomisedGearCache.getUnchecked(entity.getUuid().getLeastSignificantBits())) {
for (var entry : randomisedGearCache.getUnchecked(entity.attributes.getEntityId().getLeastSignificantBits())) {
if (getContext().shouldRender(model, entity, entry.wearable(), entry.gear())) {
stack.push();
Gear gear = entry.gear();
gear.transform(model, stack);
gear.transform(entity, model, stack);
BodyPart part = gear.getGearLocation();
if (hasSkull && part== BodyPart.HEAD && renderStackingOffsets.getFloat(part) == 0) {
renderStackingOffsets.put(part, 0.25F);
@ -101,9 +100,9 @@ public class GearFeature<
}
}
private void renderGear(M model, T entity, Gear gear, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, float limbDistance, float limbAngle, float tickDelta) {
gear.pose(model, entity, model.getAttributes().isGoingFast, entity.getUuid(), limbDistance, limbAngle, model.getWobbleAmount(), tickDelta);
gear.render(stack, renderContext.getBuffer(gear.getLayer(entity, getContext())), lightUv, OverlayTexture.DEFAULT_UV, Colors.WHITE, entity.getUuid());
private void renderGear(M model, S entity, Gear gear, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, float limbDistance, float limbAngle, float tickDelta) {
gear.pose(model, entity, entity.attributes.isGoingFast, entity.attributes.getEntityId(), limbDistance, limbAngle, entity.getWobbleAmount(), tickDelta);
gear.render(stack, renderContext.getBuffer(gear.getLayer(entity, getContext())), lightUv, OverlayTexture.DEFAULT_UV, Colors.WHITE, entity.attributes.getEntityId());
}
static record Entry(Gear gear, Wearable wearable) { }

View file

@ -1,30 +0,0 @@
package com.minelittlepony.client.render.entity.feature;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.entity.mob.AbstractSkeletonEntity;
import net.minecraft.util.Identifier;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.SkeleponyModel;
public class StrayClothingFeature<Skeleton extends AbstractSkeletonEntity> extends AbstractClothingFeature<Skeleton, SkeleponyModel<Skeleton>> {
public static final Identifier STRAY_SKELETON_OVERLAY = MineLittlePony.id("textures/entity/skeleton/stray_pony_overlay.png");
@SuppressWarnings("unchecked")
private final SkeleponyModel<Skeleton> overlayModel = (SkeleponyModel<Skeleton>)ModelType.SKELETON_CLOTHES.createModel();
public StrayClothingFeature(LivingEntityRenderer<Skeleton, SkeleponyModel<Skeleton>> render) {
super(render);
}
@Override
protected SkeleponyModel<Skeleton> getOverlayModel() {
return overlayModel;
}
@Override
protected Identifier getOverlayTexture() {
return STRAY_SKELETON_OVERLAY;
}
}

View file

@ -4,53 +4,45 @@ import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.VillagerProfession;
import net.minecraft.village.*;
import com.minelittlepony.api.model.Models;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.meta.Race;
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,
S extends PonyRenderState
S extends SillyPonyTextureSupplier.State
> 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 -> {
private final Function<Race, Models<ClientPonyModel<S>>> models = Util.memoize(race -> {
if (race.isHuman()) {
race = Race.EARTH;
}
return ModelType.getPlayerModel(race).create(false, this::initializeModel);
});
public AbstractNpcRenderer(EntityRendererFactory.Context context, String type, TextureSupplier<T> textureSupplier, TextureSupplier<String> formatter) {
public AbstractNpcRenderer(EntityRendererFactory.Context context, String type, TextureSupplier<S> textureSupplier, TextureSupplier<String> formatter) {
super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), SillyPonyTextureSupplier.create(textureSupplier, formatter));
clothing = new NpcClothingFeature<>(this, type);
this.manager.setModelsLookup(entity -> models.apply(getEntityPony(entity).race()));
this.manager.setModelsLookup(entity -> models.apply(entity.getRace()));
addFeature(clothing);
}
@Override
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 && (
profession == VillagerProfession.CARTOGRAPHER
|| profession == VillagerProfession.FARMER
|| profession == VillagerProfession.FISHERMAN
|| profession == VillagerProfession.LIBRARIAN
|| profession == VillagerProfession.SHEPHERD);
return entity.hasSaddlebags;
}
if (wearable == Wearable.MUFFIN) {
return SillyPonyTextureSupplier.isCrownPony(entity);
return entity.hasMuffinHat;
}
return super.shouldRender(model, entity, wearable, gear);

View file

@ -1,76 +1,91 @@
package com.minelittlepony.client.render.entity.npc;
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.IllagerPonyModel;
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.mson.api.ModelKey;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.PonyRenderer;
import com.minelittlepony.client.render.entity.feature.HeldItemFeature;
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.mob.EvokerEntity;
import net.minecraft.entity.mob.IllagerEntity;
import net.minecraft.entity.mob.IllusionerEntity;
import net.minecraft.entity.mob.VindicatorEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.*;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class IllagerPonyRenderer<T extends IllagerEntity> extends PonyRenderer<T, IllagerPonyModel<T>> {
public class IllagerPonyRenderer<
T extends IllagerEntity,
S extends IllagerPonyRenderer.State,
M extends AlicornModel<S>
> extends PonyRenderer<T, S, M> {
public static final Identifier PILLAGER = MineLittlePony.id("textures/entity/illager/pillager_pony.png");
public static final Identifier ILLUSIONIST = MineLittlePony.id("textures/entity/illager/illusionist_pony.png");
public static final Identifier EVOKER = MineLittlePony.id("textures/entity/illager/evoker_pony.png");
public static final Identifier VINDICATOR = MineLittlePony.id("textures/entity/illager/vindicator_pony.png");
public IllagerPonyRenderer(EntityRendererFactory.Context context, Identifier texture) {
super(context, ModelType.ILLAGER, TextureSupplier.of(texture), BASE_MODEL_SCALE);
public IllagerPonyRenderer(EntityRendererFactory.Context context, ModelKey<? super M> key, Identifier texture) {
super(context, key, TextureSupplier.of(texture), BASE_MODEL_SCALE);
}
@SuppressWarnings("unchecked")
@Override
public S createRenderState() {
return (S)new State();
}
@Override
protected HeldItemFeature<T, IllagerPonyModel<T>> createHeldItemFeature(EntityRendererFactory.Context context) {
return new IllagerHeldItemFeature<>(this, context.getHeldItemRenderer());
protected HeldItemFeature<S, M> createHeldItemFeature(EntityRendererFactory.Context context) {
return new IllagerHeldItemFeature<>(this, context.getItemRenderer());
}
public static IllagerPonyRenderer<VindicatorEntity> vindicator(EntityRendererFactory.Context context) {
return new IllagerPonyRenderer<>(context, VINDICATOR);
public static IllagerPonyRenderer<PillagerEntity, ?, ?> pillager(EntityRendererFactory.Context context) {
return new IllagerPonyRenderer<>(context, ModelType.PILLAGER, PILLAGER);
}
public static IllagerPonyRenderer<EvokerEntity> evoker(EntityRendererFactory.Context context) {
return new IllagerPonyRenderer<>(context, EVOKER);
public static IllagerPonyRenderer<VindicatorEntity, ?, ?> vindicator(EntityRendererFactory.Context context) {
return new IllagerPonyRenderer<>(context, (ModelKey<?>)ModelType.ILLAGER, VINDICATOR);
}
public static class Illusionist extends IllagerPonyRenderer<IllusionerEntity> {
public static IllagerPonyRenderer<EvokerEntity, ?, ?> evoker(EntityRendererFactory.Context context) {
return new IllagerPonyRenderer<>(context, (ModelKey<?>)ModelType.ILLAGER, EVOKER);
}
public Illusionist(EntityRendererFactory.Context context) {
super(context, ILLUSIONIST);
public static 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 static class IllagerHeldItemFeature<
T extends IllagerEntity,
S extends IllagerPonyRenderer.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(IllusionerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
if (entity.isInvisible()) {
Vec3d[] clones = entity.getMirrorCopyOffsets(tickDelta);
float rotation = getAnimationProgress(entity, tickDelta);
for (int i = 0; i < clones.length; ++i) {
stack.push();
stack.translate(
clones[i].x + MathHelper.cos(i + rotation * 0.5F) * 0.025D,
clones[i].y + MathHelper.cos(i + rotation * 0.75F) * 0.0125D,
clones[i].z + MathHelper.cos(i + rotation * 0.7F) * 0.025D
);
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
stack.pop();
}
} else {
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
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);
}
}
@Override
protected boolean isVisible(IllusionerEntity entity) {
return true;
protected boolean shouldRender(S state) {
return state.state != IllagerEntity.State.CROSSED;
}
}
}

View file

@ -0,0 +1,62 @@
package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.IllusionerEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.IllagerPonyModel;
import java.util.Arrays;
public class IllusionistPonyRenderer extends IllagerPonyRenderer<IllusionerEntity, IllusionistPonyRenderer.State, IllagerPonyModel<IllusionistPonyRenderer.State>> {
public IllusionistPonyRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.ILLAGER, ILLUSIONIST);
}
@Override
public State createRenderState() {
return new State();
}
@Override
public void render(IllusionistPonyRenderer.State entity, MatrixStack stack, VertexConsumerProvider renderContext, int light) {
if (!entity.invisible) {
Vec3d[] clones = entity.mirrorCopyOffsets;
for (int i = 0; i < clones.length; ++i) {
stack.push();
stack.translate(
clones[i].x + MathHelper.cos(i + entity.age * 0.5F) * 0.025D,
clones[i].y + MathHelper.cos(i + entity.age * 0.75F) * 0.0125D,
clones[i].z + MathHelper.cos(i + entity.age * 0.7F) * 0.025D
);
super.render(entity, stack, renderContext, light);
stack.pop();
}
} else {
super.render(entity, stack, renderContext, light);
}
}
@Override
protected boolean isVisible(IllusionistPonyRenderer.State entity) {
return true;
}
@Override
public void updateRenderState(IllusionerEntity entity, IllusionistPonyRenderer.State state, float tickDelta) {
super.updateRenderState(entity, state, tickDelta);
Vec3d[] vec3ds = entity.getMirrorCopyOffsets(tickDelta);
state.mirrorCopyOffsets = (Vec3d[])Arrays.copyOf(vec3ds, vec3ds.length);
state.spellcasting = entity.isSpellcasting();
}
public static class State extends IllagerPonyRenderer.State {
public Vec3d[] mirrorCopyOffsets;
public boolean spellcasting;
}
}

View file

@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.render.VertexConsumerProvider;
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;
import net.minecraft.registry.Registries;
@ -15,11 +14,11 @@ import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.VillagerProfession;
import net.minecraft.village.VillagerType;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ClientPonyModel;
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.render.entity.npc.textures.SillyPonyTextureSupplier;
import com.minelittlepony.client.util.render.TextureFlattener;
import com.minelittlepony.util.ResourceUtil;
@ -27,8 +26,8 @@ import java.util.*;
class NpcClothingFeature<
T extends LivingEntity & VillagerDataContainer,
S extends PonyRenderState,
M extends EntityModel<S> & PonyModel<S>,
S extends SillyPonyTextureSupplier.State,
M extends ClientPonyModel<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 -> {
@ -53,7 +52,7 @@ class NpcClothingFeature<
return;
}
VillagerData data = entity.getVillagerData();
VillagerData data = entity.villagerData;
M entityModel = getContextModel();
if (entity.baby || data.getProfession() == VillagerProfession.NONE) {
@ -102,8 +101,8 @@ class NpcClothingFeature<
return skins;
}
public Identifier createTexture(VillagerDataContainer entity, String category) {
return createTexture(category, Registries.VILLAGER_PROFESSION.getId(entity.getVillagerData().getProfession()));
public Identifier createTexture(S entity, String category) {
return createTexture(category, Registries.VILLAGER_PROFESSION.getId(entity.villagerData.getProfession()));
}
private Identifier createTexture(String category, Identifier identifier) {

View file

@ -1,72 +0,0 @@
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.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, PillagerRenderer.State, PillagerPonyModel> {
private static final Identifier TEXTURE = MineLittlePony.id("textures/entity/illager/pillager_pony.png");
public PillagerRenderer(EntityRendererFactory.Context context) {
super(context, ModelType.PILLAGER, TextureSupplier.of(TEXTURE));
}
@Override
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

@ -1,30 +1,39 @@
package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.VariatedTextureSupplier;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.*;
public class VillagerPonyRenderer extends AbstractNpcRenderer<VillagerEntity> {
public class VillagerPonyRenderer extends AbstractNpcRenderer<VillagerEntity, VillagerPonyRenderer.State> {
private static final TextureSupplier<String> FORMATTER = TextureSupplier.formatted("minelittlepony", "textures/entity/villager/%s.png");
private static final TextureSupplier<State> TEXTURES = TextureSupplier.ofPool(
VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER))
);
public VillagerPonyRenderer(EntityRendererFactory.Context context) {
super(context, "villager",
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER))), FORMATTER);
super(context, "villager", TEXTURES, FORMATTER);
}
@Override
protected void initializeModel(ClientPonyModel<VillagerEntity> model) {
model.onSetModelAngles((m, move, swing, ticks, entity) -> {
m.getAttributes().visualHeight += SillyPonyTextureSupplier.isCrownPony(entity) ? 0.3F : -0.1F;
public State createRenderState() {
return new State();
}
if (entity.getHeadRollingTimeLeft() > 0) {
m.head.yaw = 0.3F * MathHelper.sin(0.45F * ticks);
}
});
public static class State extends SillyPonyTextureSupplier.State {
public int headRollingTime;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
if (((VillagerEntity)entity).getHeadRollingTimeLeft() > 0) {
this.yawDegrees = 0.3F * MathHelper.sin(0.45F * age);
}
}
}
}

View file

@ -2,42 +2,50 @@ package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.model.BipedEntityModel.ArmPose;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.ZombieVillagerEntity;
import com.minelittlepony.api.model.MobPosingHelper;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.VariatedTextureSupplier;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.*;
public class ZomponyVillagerRenderer extends AbstractNpcRenderer<ZombieVillagerEntity> {
public class ZomponyVillagerRenderer extends AbstractNpcRenderer<ZombieVillagerEntity, ZomponyVillagerRenderer.State> {
private static final TextureSupplier<String> FORMATTER = TextureSupplier.formatted("minelittlepony", "textures/entity/zombie_villager/zombie_%s.png");
private static final TextureSupplier<State> TEXTURES = TextureSupplier.ofPool(
VariatedTextureSupplier.BACKGROUND_ZOMPONIES_POOL,
TextureSupplier.ofPool(
VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER))
)
);
public ZomponyVillagerRenderer(EntityRendererFactory.Context context) {
super(context, "zombie_villager",
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_ZOMPONIES_POOL,
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER)))),
FORMATTER);
super(context, "zombie_villager", TEXTURES, FORMATTER);
}
@Override
protected void initializeModel(ClientPonyModel<ZombieVillagerEntity> model) {
model.onSetModelAngles((m, move, swing, ticks, entity) -> {
m.getAttributes().visualHeight += SillyPonyTextureSupplier.isCrownPony(entity) ? 0.3F : -0.1F;
public State createRenderState() {
return new State();
}
if (m.rightArmPose == ArmPose.EMPTY) {
MobPosingHelper.rotateUndeadArms(m, move, ticks);
@Override
protected void initializeModel(ClientPonyModel<State> model) {
model.onSetModelAngles((m, state) -> {
if (m.getArmPoseForSide(state, state.mainArm) == ArmPose.EMPTY) {
MobPosingHelper.rotateUndeadArms(state, m, state.limbFrequency, state.age);
}
});
}
public static class State extends SillyPonyTextureSupplier.State {
@Override
protected void setupTransforms(ZombieVillagerEntity entity, MatrixStack matrices, float animationProgress, float bodyYaw, float tickDelta, float scale) {
if (entity.isConverting()) {
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
if (((ZombieVillagerEntity)entity).isConverting()) {
bodyYaw += (float) (Math.cos(entity.age * 3.25D) * (Math.PI / 4));
}
super.setupTransforms(entity, matrices, animationProgress, bodyYaw, tickDelta, scale);
}
}
}

View file

@ -1,18 +1,18 @@
package com.minelittlepony.client.render.entity.npc.textures;
import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public class PlayerTextureSupplier {
public static <T extends LivingEntity> TextureSupplier<T> create(TextureSupplier<T> fallback) {
public static <T extends PonyRenderState> TextureSupplier<T> create(TextureSupplier<T> fallback) {
Function<String, CompletableFuture<Identifier>> customNameCache = Util.memoize(name -> {
return SkullBlockEntity.fetchProfileByName(name).thenApply(profile -> {
return profile
@ -22,7 +22,7 @@ public class PlayerTextureSupplier {
});
});
return entity -> {
Identifier override = entity.hasCustomName() ? customNameCache.apply(entity.getCustomName().getString()).getNow(null) : null;
Identifier override = entity.customName != null ? customNameCache.apply(entity.customName.getString()).getNow(null) : null;
if (override != null) {
return override;
}

View file

@ -2,15 +2,18 @@ package com.minelittlepony.client.render.entity.npc.textures;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.*;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public class SillyPonyTextureSupplier {
public static <T extends LivingEntity & VillagerDataContainer> TextureSupplier<T> create(TextureSupplier<T> fallback, TextureSupplier<String> formatter) {
public static <T extends State> TextureSupplier<T> create(TextureSupplier<T> fallback, TextureSupplier<String> formatter) {
Identifier egg = formatter.apply("silly_pony");
Identifier egg2 = formatter.apply("tiny_silly_pony");
return entity -> {
return isBestPony(entity) ? ("Dinky".equals(entity.getCustomName().getString()) ? egg2 : egg) : fallback.apply(entity);
};
return entity -> entity.isDerpy ? (entity.isDinky ? egg2 : egg) : fallback.apply(entity);
}
public static boolean isBestPony(LivingEntity entity) {
@ -24,4 +27,40 @@ public class SillyPonyTextureSupplier {
public static boolean isCrownPony(LivingEntity entity) {
return isBestPony(entity) && entity.getUuid().getLeastSignificantBits() % 20 == 0;
}
public static class State extends PonyRenderState implements VillagerDataContainer {
public VillagerData villagerData;
public boolean isDerpy;
public boolean isDinky;
public boolean hasMuffinHat;
public boolean hasSaddlebags;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
attributes.visualHeight += hasMuffinHat ? 0.3F : -0.1F;
isDerpy = SillyPonyTextureSupplier.isBestPony(entity);
isDinky = isDerpy && customName != null && "Dinky".equals(customName.getString());
hasMuffinHat = SillyPonyTextureSupplier.isCrownPony(entity);
villagerData = ((VillagerDataContainer)entity).getVillagerData();
VillagerProfession profession = villagerData.getProfession();
hasSaddlebags = !isDerpy && profession != VillagerProfession.NONE && (
profession == VillagerProfession.CARTOGRAPHER
|| profession == VillagerProfession.FARMER
|| profession == VillagerProfession.FISHERMAN
|| profession == VillagerProfession.LIBRARIAN
|| profession == VillagerProfession.SHEPHERD);
}
@Override
public VillagerData getVillagerData() {
return villagerData;
}
@Override
public void setVillagerData(VillagerData villagerData) {
}
}
}

View file

@ -1,10 +1,10 @@
package com.minelittlepony.client.render.entity.npc.textures;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.Map;
import java.util.UUID;
@ -27,13 +27,13 @@ public interface TextureSupplier<T> extends Function<T, Identifier> {
return key -> Identifier.of(domain, String.format(path, key));
}
static <T extends LivingEntity> TextureSupplier<T> ofVariations(Identifier poolId, TextureSupplier<T> fallback) {
static <T extends PonyRenderState> TextureSupplier<T> ofVariations(Identifier poolId, TextureSupplier<T> fallback) {
return entity -> {
return MineLittlePony.getInstance().getVariatedTextures().get(poolId).getId(entity.getUuid()).orElse(fallback.apply(entity));
return MineLittlePony.getInstance().getVariatedTextures().get(poolId).getId(entity.attributes.getEntityId()).orElse(fallback.apply(entity));
};
}
static <T extends LivingEntity> TextureSupplier<T> ofPool(Identifier poolId, TextureSupplier<T> fallback) {
static <T extends PonyRenderState> TextureSupplier<T> ofPool(Identifier poolId, TextureSupplier<T> fallback) {
final BiFunction<String, UUID, Identifier> cache = Util.memoize((name, uuid) -> {
return MineLittlePony.getInstance().getVariatedTextures()
.get(poolId)
@ -41,7 +41,7 @@ public interface TextureSupplier<T> extends Function<T, Identifier> {
.orElse(null);
});
return entity -> {
Identifier override = entity.hasCustomName() ? cache.apply(entity.getCustomName().getString(), entity.getUuid()) : null;
Identifier override = entity.customName != null ? cache.apply(entity.customName.getString(), entity.attributes.getEntityId()) : null;
if (override != null) {
return override;
}

View file

@ -4,8 +4,7 @@ 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.model.*;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.SkinsProxy;
import com.minelittlepony.api.pony.meta.Wearable;
@ -15,10 +14,13 @@ import java.util.Map;
public class PlayerPonyRenderState extends PonyRenderState {
public final Map<Wearable, Identifier> wearabledTextures = new HashMap<>();
public boolean isPreviewModel;
public double yOffset;
@Override
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
super.updateState(entity, model, pony, mode);
isPreviewModel = entity instanceof PreviewModel;
wearabledTextures.clear();
for (Wearable wearable : Wearable.REGISTRY.values()) {
if (isWearing(wearable)) {

View file

@ -12,6 +12,7 @@ import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.transform.PonyPosture;
public class PonyRenderState extends PlayerEntityRenderState implements PonyModel.AttributedHolder {
public final ModelAttributes attributes = new ModelAttributes();
@ -28,9 +29,9 @@ public class PonyRenderState extends PlayerEntityRenderState implements PonyMode
public Pony pony;
public void updateState(LivingEntity entity, PonyModel<?> model, Pony pony, ModelAttributes.Mode mode) {
this.pony = pony;
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);
@ -42,6 +43,7 @@ public class PonyRenderState extends PlayerEntityRenderState implements PonyMode
pose = EntityPose.SITTING;
}
PonyPosture.of(attributes).updateState(entity, this);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(attributes, model, ModelAttributes.Mode.OTHER);
}
@ -56,6 +58,10 @@ public class PonyRenderState extends PlayerEntityRenderState implements PonyMode
return PonyConfig.getEffectiveRace(attributes.metadata.race());
}
public boolean hasMagicGlow() {
return getRace().hasHorn() && attributes.metadata.glowColor() != 0;
}
public final float getScaleFactor() {
return getSize().scaleFactor();
}
@ -83,7 +89,6 @@ public class PonyRenderState extends PlayerEntityRenderState implements PonyMode
}
protected float getLegOutset() {
float outset = attributes.isLyingDown ? 3.6F : attributes.isCrouching ? 1 : 5;
if (smallArms) {

View file

@ -1,34 +0,0 @@
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

@ -3,28 +3,34 @@ package com.minelittlepony.client.transform;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.*;
import org.jetbrains.annotations.NotNull;
import com.minelittlepony.api.model.*;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
public interface PonyPosture {
PonyPosture STANDING = (PonyModel<?> model, LivingEntity entity, MatrixStack stack, double motionX, double motionY, double motionZ, float yaw, float tickDelta) -> {
model.getAttributes().motionPitch /= 10;
model.getAttributes().motionLerp /= 10;
model.getAttributes().motionRoll /= 10;
public abstract class PonyPosture {
public static final PonyPosture STANDING = new PonyPosture() {
@Override
public void updateState(LivingEntity entity, PonyRenderState state) {
super.updateState(entity, state);
state.attributes.motionPitch /= 10;
state.attributes.motionLerp /= 10;
state.attributes.motionRoll /= 10;
}
};
PonyPosture ELYTRA = (PonyModel<?> model, LivingEntity entity, MatrixStack stack, double motionX, double motionY, double motionZ, float yaw, float tickDelta) -> {
stack.translate(0, entity.isInSneakingPose() ? -0.825F : -1, 0);
public static final PonyPosture ELYTRA = new PonyPosture() {
@Override
public void transform(PonyRenderState state, MatrixStack stack) {
stack.translate(0, state.isInSneakingPose ? -0.825F : -1, 0);
}
};
PonyPosture FLYING = new PostureFlight(1, 0);
PonyPosture SWIMMING = new PostureFlight(2, -0.9F);
PonyPosture FALLING = STANDING;
public static final PonyPosture FLYING = new PostureFlight(1, 0);
public static final PonyPosture SWIMMING = new PostureFlight(2, -0.9F);
public static final PonyPosture FALLING = STANDING;
@NotNull
static PonyPosture of(ModelAttributes attributes) {
public static PonyPosture of(ModelAttributes attributes) {
if (attributes.isGliding) {
return ELYTRA;
}
@ -44,52 +50,16 @@ public interface PonyPosture {
return FALLING;
}
default void apply(LivingEntity player, PonyModel<?> model, MatrixStack stack, float yaw, float tickDelta, int invert) {
public void updateState(LivingEntity entity, PonyRenderState state) {
if (RenderPass.getCurrent() == RenderPass.GUI || RenderPass.getCurrent() == RenderPass.WORLD) {
// this reverts the rotations done in PlayerEntityRenderer#setupTransforms
if (player instanceof PlayerEntity) {
float leaningPitch = player.getLeaningPitch(tickDelta);
if (player.isGliding()) {
if (RenderPass.getCurrent() == RenderPass.GUI) {
Vec3d vec3d = player.getRotationVec(tickDelta);
Vec3d vec3d2 = ((AbstractClientPlayerEntity)player).lerpVelocity(tickDelta);
double d = vec3d2.horizontalLengthSquared();
double e = vec3d.horizontalLengthSquared();
if (d > 0.0 && e > 0.0) {
double l = (vec3d2.x * vec3d.x + vec3d2.z * vec3d.z) / Math.sqrt(d * e);
double m = vec3d2.x * vec3d.z - vec3d2.z * vec3d.x;
stack.multiply(RotationAxis.NEGATIVE_Y.rotation((float)(Math.signum(m) * Math.acos(l))));
}
}
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())));
}
} else if (leaningPitch > 0) {
if (player.isInSwimmingPose()) {
stack.translate(0.0f, 1.0f, -0.3f);
}
float pitch = MathHelper.lerp(leaningPitch, 0, player.isTouchingWater() ? -90 - player.getPitch() : -90);
stack.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(pitch));
if (entity instanceof AbstractClientPlayerEntity) {
state.isGliding = false;
state.leaningPitch = 0;
}
}
}
if (RenderPass.getCurrent() != RenderPass.WORLD) {
return;
}
public void transform(PonyRenderState state, MatrixStack stack) {
double motionX = player.getX() - player.prevX;
double motionY = player.isOnGround() ? 0 : player.getY() - player.prevY;
double motionZ = player.getZ() - player.prevZ;
transform(model, player, stack, motionX, invert * motionY, motionZ, yaw, tickDelta);
}
void transform(PonyModel<?> model, LivingEntity entity, MatrixStack stack, double motionX, double motionY, double motionZ, float yaw, float tickDelta);
}

View file

@ -3,8 +3,7 @@ package com.minelittlepony.client.transform;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.SizePreset;
@ -14,23 +13,22 @@ import java.util.function.Function;
import java.util.stream.Collectors;
public enum PonyTransformation {
NORMAL(SizePreset.NORMAL, 0, 3F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.3F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, -0.2F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.77F, 0.1F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.16F, 0);
if (model.getAttributes().isSitting) stack.translate(0, -0.2F, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isSwimming) stack.translate(0, -0.3F, 0);
if (attributes.isCrouching) stack.translate(0, -0.2F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.77F, 0.1F);
if (attributes.isSleeping) stack.translate(0, 0.16F, 0);
if (attributes.isSitting) stack.translate(0, -0.2F, -0.2F);
switch (part) {
case NECK:
if (model.getAttributes().isCrouching) stack.translate(-0.03F, 0.03F, 0.13F);
if (attributes.isCrouching) stack.translate(-0.03F, 0.03F, 0.13F);
break;
case HEAD:
if (model.getAttributes().isLyingDown) stack.translate(-0.05F, -0.05F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, 0.1F, -0);
if (attributes.isLyingDown) stack.translate(-0.05F, -0.05F, 0);
if (attributes.isCrouching) stack.translate(0, 0.1F, -0);
break;
case BACK:
translateForRider(stack);
@ -41,23 +39,23 @@ public enum PonyTransformation {
},
LANKY(SizePreset.LANKY, 0, 2.6F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.2F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.68F, 0.15F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.08F, 0);
if (model.getAttributes().isSitting) stack.translate(0, 0, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isSwimming) stack.translate(0, -0.2F, 0);
if (attributes.isCrouching) stack.translate(0, -0.15F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.68F, 0.15F);
if (attributes.isSleeping) stack.translate(0, 0.08F, 0);
if (attributes.isSitting) stack.translate(0, 0, -0.2F);
switch (part) {
case NECK:
stack.translate(0, -0.2F, -0.05F);
stack.scale(1, 1.3F, 1);
if (model.getAttributes().isCrouching) stack.translate(-0.03F, 0.01F, 0.2F);
if (attributes.isCrouching) stack.translate(-0.03F, 0.01F, 0.2F);
break;
case HEAD:
stack.translate(0, -0.14F, -0.04F);
if (model.getAttributes().isLyingDown) stack.translate(0, 0, -0.1F);
if (model.getAttributes().isCrouching) stack.translate(0, 0.15F, 0);
if (attributes.isLyingDown) stack.translate(0, 0, -0.1F);
if (attributes.isCrouching) stack.translate(0, 0.15F, 0);
break;
case BODY:
stack.translate(0, -0.2F, -0.04F);
@ -78,22 +76,22 @@ public enum PonyTransformation {
},
BULKY(SizePreset.BULKY, 0, 2.3F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.66F, 0.25F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.06F, 0);
if (model.getAttributes().isSitting) stack.translate(0, 0, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isCrouching) stack.translate(0, -0.15F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.66F, 0.25F);
if (attributes.isSleeping) stack.translate(0, 0.06F, 0);
if (attributes.isSitting) stack.translate(0, 0, -0.2F);
switch (part) {
case NECK:
stack.translate(0, -0.2F, -0.07F);
stack.scale(1, 1.3F, 1);
if (model.getAttributes().isCrouching) stack.translate(-0.03F, -0.07F, 0.09F);
if (attributes.isCrouching) stack.translate(-0.03F, -0.07F, 0.09F);
break;
case HEAD:
stack.translate(0, -0.14F, -0.06F);
if (model.getAttributes().isLyingDown) stack.translate(-0.05F, 0, -0.1F);
if (model.getAttributes().isCrouching) stack.translate(0, 0.15F, 0);
if (attributes.isLyingDown) stack.translate(-0.05F, 0, -0.1F);
if (attributes.isCrouching) stack.translate(0, 0.15F, 0);
break;
case BODY:
stack.translate(0, -0.2F, -0.04F);
@ -114,12 +112,12 @@ public enum PonyTransformation {
},
FOAL(SizePreset.FOAL, 0, 3.8F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.9F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, -0.2F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.98F, -0.3F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.18F, 0);
if (model.getAttributes().isSitting) stack.translate(0, -0.6F, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isSwimming) stack.translate(0, -0.9F, 0);
if (attributes.isCrouching) stack.translate(0, -0.2F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.98F, -0.3F);
if (attributes.isSleeping) stack.translate(0, 0.18F, 0);
if (attributes.isSitting) stack.translate(0, -0.6F, -0.2F);
stack.translate(0, 0.2F, 0);
@ -127,7 +125,7 @@ public enum PonyTransformation {
case NECK:
stack.translate(0, 0, 0.04F);
stack.scale(1.3F, 1.3F, 1.3F);
if (model.getAttributes().isCrouching) stack.translate(-0.03F, -0.16F, 0.15F);
if (attributes.isCrouching) stack.translate(-0.03F, -0.16F, 0.15F);
break;
case HEAD:
stack.scale(1.3F, 1.3F, 1.3F);
@ -145,21 +143,21 @@ public enum PonyTransformation {
},
TALL(SizePreset.TALL, 0, 2.2F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.6F, 0.35F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.1F, 0);
if (model.getAttributes().isSitting) stack.translate(0, 0.1F, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isCrouching) stack.translate(0, -0.15F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.6F, 0.35F);
if (attributes.isSleeping) stack.translate(0, 0.1F, 0);
if (attributes.isSitting) stack.translate(0, 0.1F, -0.2F);
switch (part) {
case NECK:
stack.translate(0, -0.21F, -0.01F);
stack.scale(1, 1.28F, 1);
if (model.getAttributes().isCrouching) stack.translate(-0.04F, -0.1F, 0.15F);
if (attributes.isCrouching) stack.translate(-0.04F, -0.1F, 0.15F);
break;
case HEAD:
stack.translate(0, -0.11F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, 0.04F, 0);
if (attributes.isCrouching) stack.translate(0, 0.04F, 0);
break;
case BODY:
case TAIL:
@ -168,7 +166,7 @@ public enum PonyTransformation {
case LEGS:
stack.translate(0, -0.27F, 0.03F);
stack.scale(1, 1.18F, 1);
if (model.getAttributes().isGoingFast) stack.translate(0, 0.05F, 0);
if (attributes.isGoingFast) stack.translate(0, 0.05F, 0);
break;
case BACK:
translateForRider(stack);
@ -178,22 +176,22 @@ public enum PonyTransformation {
},
YEARLING(SizePreset.YEARLING, 0, 3.8F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.6F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
if (model.getAttributes().isLyingDown) stack.translate(0, -0.71F, -0.3F);
if (model.getAttributes().isSleeping) stack.translate(0, 0.26F, 0);
if (model.getAttributes().isSitting) stack.translate(0, -0.4F, -0.2F);
public void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack) {
if (attributes.isSwimming) stack.translate(0, -0.6F, 0);
if (attributes.isCrouching) stack.translate(0, -0.15F, 0);
if (attributes.isLyingDown) stack.translate(0, -0.71F, -0.3F);
if (attributes.isSleeping) stack.translate(0, 0.26F, 0);
if (attributes.isSitting) stack.translate(0, -0.4F, -0.2F);
switch (part) {
case NECK:
stack.translate(0, -0.2F, 0);
stack.scale(1, 1.3F, 1);
if (model.getAttributes().isCrouching) stack.translate(-0.04F, -0.05F, 0.15F);
if (attributes.isCrouching) stack.translate(-0.04F, -0.05F, 0.15F);
break;
case HEAD:
stack.translate(0, -0.15F, 0);
if (model.getAttributes().isCrouching) stack.translate(0, 0.04F, 0);
if (attributes.isCrouching) stack.translate(0, 0.04F, 0);
stack.scale(1.15F, 1.15F, 1.15F);
break;
case BODY:
@ -203,7 +201,7 @@ public enum PonyTransformation {
case LEGS:
stack.translate(0, -0.265F, 0.03F);
stack.scale(1, 1.18F, 1);
if (model.getAttributes().isGoingFast) stack.translate(0, 0.05F, 0);
if (attributes.isGoingFast) stack.translate(0, 0.05F, 0);
break;
case BACK:
translateForRider(stack);
@ -230,7 +228,7 @@ public enum PonyTransformation {
stack.translate(riderOffset.x, riderOffset.y, riderOffset.z);
}
public abstract void transform(PonyModel<?> model, BodyPart part, MatrixStack stack);
public abstract void transform(ModelAttributes attributes, BodyPart part, MatrixStack stack);
public static PonyTransformation forSize(Size size) {
return REGISTRY.getOrDefault(size, NORMAL);

View file

@ -1,13 +1,14 @@
package com.minelittlepony.client.transform;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.common.util.animation.MotionCompositor;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.entity.LivingEntity;
public class PostureFlight extends MotionCompositor implements PonyPosture {
public class PostureFlight extends PonyPosture {
private final MotionCompositor compositor = new MotionCompositor();
private final float xScale;
private final float yOffset;
@ -17,15 +18,22 @@ public class PostureFlight extends MotionCompositor implements PonyPosture {
this.yOffset = yOffset;
}
public void updateState(LivingEntity entity, PonyRenderState state) {
super.updateState(entity, state);
double motionX = entity.getX() - entity.prevX;
double motionY = entity.isOnGround() ? 0 : entity.getY() - entity.prevY;
double motionZ = entity.getZ() - entity.prevZ;
state.attributes.motionPitch = (float)compositor.calculateIncline(entity, motionX, motionY, motionZ);
state.attributes.motionRoll = (float)compositor.calculateRoll(entity, motionX * xScale, motionY, motionZ * xScale);
state.attributes.motionRoll = state.attributes.getMainInterpolator().interpolate("pegasusRoll", state.attributes.motionRoll, 10);
}
@Override
public void transform(PonyModel<?> model, LivingEntity player, MatrixStack stack, double motionX, double motionY, double motionZ, float yaw, float ticks) {
model.getAttributes().motionPitch = (float)calculateIncline(player, motionX, motionY, motionZ);
model.getAttributes().motionRoll = (float)calculateRoll(player, motionX * xScale, motionY, motionZ * xScale);
model.getAttributes().motionRoll = model.getAttributes().getMainInterpolator().interpolate("pegasusRoll", model.getAttributes().motionRoll, 10);
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(model.getAttributes().motionPitch));
stack.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(model.getAttributes().motionRoll));
public void transform(PonyRenderState state, MatrixStack stack) {
stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(state.attributes.motionPitch));
stack.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(state.attributes.motionRoll));
stack.translate(0, yOffset, 0);
}
}