Rewrite pretty much everything to make more effective use of java's Records

This commit is contained in:
Sollace 2023-09-25 21:07:09 +01:00
parent 8eca1796e1
commit 0d226b51f9
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
110 changed files with 821 additions and 1142 deletions

View file

@ -2,8 +2,7 @@ package com.minelittlepony.api.config;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.common.util.GamePaths; import com.minelittlepony.common.util.GamePaths;
import com.minelittlepony.common.util.settings.*; import com.minelittlepony.common.util.settings.*;
@ -131,4 +130,18 @@ public class PonyConfig extends Config {
return race; return race;
} }
public static Size getEffectiveSize(Size size) {
Sizes sz = instance.sizeOverride.get();
if (sz != Sizes.UNSET) {
return sz;
}
if (size == Sizes.UNSET || !instance.sizes.get()) {
return Sizes.NORMAL;
}
return size;
}
} }

View file

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

View file

@ -1,11 +0,0 @@
package com.minelittlepony.api.model;
/**
* Interface for models that have a head.
*/
public interface ICapitated<T> {
/**
* Gets the head of this capitated object.
*/
T getHead();
}

View file

@ -1,10 +1,10 @@
package com.minelittlepony.api.model; package com.minelittlepony.api.model;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.PonyData;
public interface IModelWrapper { public interface IModelWrapper {
/** /**
* Updates metadata values to this wrapper's contained models. * Updates metadata values to this wrapper's contained models.
*/ */
IModelWrapper applyMetadata(IPonyData meta); IModelWrapper applyMetadata(PonyData meta);
} }

View file

@ -1,30 +0,0 @@
package com.minelittlepony.api.model;
public interface IUnicorn extends IModel {
/**
* Returns true if this model is being applied to a race that can use magic.
*/
default boolean hasMagic() {
return hasHorn() && getMagicColor() != 0;
}
/**
* Returns true if this model has an visible horns.
*/
default boolean hasHorn() {
return getRace().hasHorn();
}
/**
* Returns true if this model is currently using magic (horn is lit).
* @return
*/
boolean isCasting();
/**
* Gets the preferred magic color for this mode.
*/
default int getMagicColor() {
return getMetadata().glowColor();
}
}

View file

@ -1,15 +1,16 @@
package com.minelittlepony.client.model; package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.mson.util.PartUtil; import com.minelittlepony.mson.util.PartUtil;
/** /**
* Common interface for all undead enemies. * Common interface for all undead enemies.
*/ */
public interface IMobModel { public final class MobPosingHelper {
/** /**
* Rotates the provided arm to the correct orientation for holding an item. * Rotates the provided arm to the correct orientation for holding an item.
* *
@ -18,7 +19,7 @@ public interface IMobModel {
* @param swingProgress How far we are through the current swing * @param swingProgress How far we are through the current swing
* @param ticks Render partial ticks * @param ticks Render partial ticks
*/ */
static void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) { public static void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) {
float swing = MathHelper.sin(swingProgress * MathHelper.PI); float swing = MathHelper.sin(swingProgress * MathHelper.PI);
float roll = MathHelper.sin((1 - (1 - swingProgress) * (1 - swingProgress)) * MathHelper.PI); float roll = MathHelper.sin((1 - (1 - swingProgress) * (1 - swingProgress)) * MathHelper.PI);
@ -33,20 +34,20 @@ public interface IMobModel {
arm.roll = cos; arm.roll = cos;
} }
static void rotateUndeadArms(ClientPonyModel<?> model, float move, float ticks) { public static void rotateUndeadArms(ClientPonyModel<?> model, float move, float ticks) {
ModelPart leftArm = model.getArm(Arm.LEFT); ModelPart leftArm = model.getArm(Arm.LEFT);
ModelPart rightArm = model.getArm(Arm.RIGHT); ModelPart rightArm = model.getArm(Arm.RIGHT);
if (islookAngleRight(move)) { if (islookAngleRight(move)) {
IMobModel.rotateArmHolding(rightArm, 1, model.getSwingAmount(), ticks); rotateArmHolding(rightArm, 1, model.getSwingAmount(), ticks);
PartUtil.shift(rightArm, 0.5F, 1.5F, 3); PartUtil.shift(rightArm, 0.5F, 1.5F, 3);
} else { } else {
IMobModel.rotateArmHolding(leftArm, -1, model.getSwingAmount(), ticks); rotateArmHolding(leftArm, -1, model.getSwingAmount(), ticks);
PartUtil.shift(leftArm, -0.5F, 1.5F, 3); PartUtil.shift(leftArm, -0.5F, 1.5F, 3);
} }
} }
static boolean islookAngleRight(float move) { public static boolean islookAngleRight(float move) {
return MathHelper.sin(move / 20) < 0; return MathHelper.sin(move / 20) < 0;
} }
} }

View file

@ -2,7 +2,6 @@ package com.minelittlepony.api.model;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.*; import com.minelittlepony.client.*;
import com.minelittlepony.client.pony.PonyData;
import com.minelittlepony.common.util.animation.Interpolator; import com.minelittlepony.common.util.animation.Interpolator;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -108,7 +107,7 @@ public class ModelAttributes {
/** /**
* Contains the skin metadata associated with this model. * Contains the skin metadata associated with this model.
*/ */
public IPonyData metadata = PonyData.NULL; public PonyData metadata = PonyData.NULL;
public Arm mainArm; public Arm mainArm;
public Hand activeHand; public Hand activeHand;
@ -118,11 +117,11 @@ public class ModelAttributes {
/** /**
* Checks flying and speed conditions and sets rainboom to true if we're a species with wings and is going faaast. * Checks flying and speed conditions and sets rainboom to true if we're a species with wings and is going faaast.
*/ */
public void checkRainboom(LivingEntity entity, boolean hasWings, float ticks) { public void checkRainboom(LivingEntity entity, PonyModel<?> model, float ticks) {
Vec3d motion = entity.getVelocity(); Vec3d motion = entity.getVelocity();
double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z); double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
isGoingFast = (isFlying && hasWings) || isGliding; isGoingFast = (isFlying && model instanceof WingedPonyModel) || isGliding;
isGoingFast &= zMotion > 0.4F; isGoingFast &= zMotion > 0.4F;
isGoingFast |= entity.isUsingRiptide(); isGoingFast |= entity.isUsingRiptide();
isGoingFast |= entity.isFallFlying(); isGoingFast |= entity.isFallFlying();
@ -137,12 +136,12 @@ public class ModelAttributes {
return (MathHelper.sin(ticks * 0.136f) / 2) + MathUtil.Angles._270_DEG; return (MathHelper.sin(ticks * 0.136f) / 2) + MathUtil.Angles._270_DEG;
} }
if (isFlying) { if (isFlying) {
return MathHelper.sin(ticks * 0.536f) + IPegasus.WINGS_FULL_SPREAD_ANGLE; return MathHelper.sin(ticks * 0.536f) + WingedPonyModel.WINGS_FULL_SPREAD_ANGLE;
} }
return IPegasus.WINGS_RAISED_ANGLE; return WingedPonyModel.WINGS_RAISED_ANGLE;
} }
public void updateLivingState(LivingEntity entity, IPony pony, Mode mode) { public void updateLivingState(LivingEntity entity, Pony pony, Mode mode) {
visualHeight = entity.getHeight() + 0.125F; visualHeight = entity.getHeight() + 0.125F;
isSitting = PonyPosture.isSitting(entity); isSitting = PonyPosture.isSitting(entity);
isCrouching = !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity); isCrouching = !isSitting && mode == Mode.THIRD_PERSON && PonyPosture.isCrouching(pony, entity);
@ -153,7 +152,7 @@ public class ModelAttributes {
isSwimmingRotated = isSwimming; isSwimmingRotated = isSwimming;
isRiptide = entity.isUsingRiptide(); isRiptide = entity.isUsingRiptide();
isRidingInteractive = PonyPosture.isRidingAPony(entity); isRidingInteractive = PonyPosture.isRidingAPony(entity);
if (!(entity instanceof IPreviewModel)) { if (!(entity instanceof PreviewModel)) {
interpolatorId = entity.getUuid(); interpolatorId = entity.getUuid();
} }
isLeftHanded = entity.getMainArm() == Arm.LEFT; isLeftHanded = entity.getMainArm() == Arm.LEFT;

View file

@ -1,66 +1,49 @@
package com.minelittlepony.api.model; package com.minelittlepony.api.model;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.mson.api.MsonModel;
public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithArms, ModelWithHat, ModelWithHead {
void copyAttributes(BipedEntityModel<T> other);
void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode);
ModelPart getBodyPart(BodyPart part);
public interface IModel {
/** /**
* Applies a transform particular to a certain body part. * Applies a transform particular to a certain body part.
*/ */
void transform(BodyPart part, MatrixStack stack); void transform(BodyPart part, MatrixStack stack);
/**
* Gets the active scaling profile used to lay out this model's parts.
*/
Size getSize();
/** /**
* Gets the transitive properties of this model. * Gets the transitive properties of this model.
*/ */
ModelAttributes getAttributes(); ModelAttributes getAttributes();
/**
* Gets the skin metadata associated with this model.
*/
default IPonyData getMetadata() {
return getAttributes().metadata;
}
/** /**
* Sets the pony metadata object associated with this model. * Sets the pony metadata object associated with this model.
*/ */
void setMetadata(IPonyData meta); void setMetadata(PonyData meta);
/** /**
* Returns true if the model is flying. * Gets the active scaling profile used to lay out this model's parts.
*/ */
default boolean isFlying() { default Size getSize() {
return getAttributes().isFlying && canFly(); return PonyConfig.getEffectiveSize(getAttributes().metadata.size());
}
/**
* Returns true if this model is riding a boat, horse, or other animals.
*
* @deprecated User model#getAttributes().isSitting
*/
@Deprecated
default boolean isRiding() {
return getAttributes().isSitting;
} }
default Race getRace() { default Race getRace() {
return PonyConfig.getEffectiveRace(getMetadata().race()); return PonyConfig.getEffectiveRace(getAttributes().metadata.race());
}
/**
* Returns true if this model is being applied to a race that has wings.
*/
default boolean canFly() {
return getRace().hasWings();
} }
/** /**
@ -72,7 +55,6 @@ public interface IModel {
* Gets the step wobble used for various hair bits and animations. * Gets the step wobble used for various hair bits and animations.
*/ */
default float getWobbleAmount() { default float getWobbleAmount() {
if (getSwingAmount() <= 0) { if (getSwingAmount() <= 0) {
return 0; return 0;
} }
@ -97,6 +79,7 @@ public interface IModel {
* i.e. Used to change wing rendering when using saddlebags. * i.e. Used to change wing rendering when using saddlebags.
*/ */
default boolean isEmbedded(Wearable wearable) { default boolean isEmbedded(Wearable wearable) {
return getMetadata().isWearing(wearable); return getAttributes().metadata.isWearing(wearable);
} }
} }

View file

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

View file

@ -3,7 +3,7 @@ package com.minelittlepony.api.model.armour;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import com.minelittlepony.client.model.IPonyModel; import com.minelittlepony.api.model.PonyModel;
public interface IArmourModel<T extends LivingEntity> { public interface IArmourModel<T extends LivingEntity> {
/** /**
@ -13,5 +13,5 @@ public interface IArmourModel<T extends LivingEntity> {
*/ */
boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch, boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch,
EquipmentSlot slot, ArmourLayer layer, EquipmentSlot slot, ArmourLayer layer,
IPonyModel<T> mainModel); PonyModel<T> mainModel);
} }

View file

@ -4,7 +4,7 @@ import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory; import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
public interface PonyModelPrepareCallback { public interface PonyModelPrepareCallback {
@ -15,5 +15,5 @@ public interface PonyModelPrepareCallback {
} }
}); });
void onPonyModelPrepared(Entity entity, IModel model, ModelAttributes.Mode mode); void onPonyModelPrepared(Entity entity, PonyModel<?> model, ModelAttributes.Mode mode);
} }

View file

@ -1,4 +1,4 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.api.model.gear;
import net.minecraft.client.model.Model; import net.minecraft.client.model.Model;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
@ -6,22 +6,24 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.api.model.gear.IGear;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public abstract class AbstractGear extends Model implements IGear { public abstract class AbstractGearModel extends Model implements Gear {
private final List<ModelPart> parts = new ArrayList<>(); private final List<ModelPart> parts = new ArrayList<>();
public AbstractGear() { private final float stackingHeight;
public AbstractGearModel(float stackingHeight) {
super(RenderLayer::getEntitySolid); super(RenderLayer::getEntitySolid);
this.stackingHeight = stackingHeight;
} }
public void addPart(ModelPart t) { public AbstractGearModel addPart(ModelPart t) {
parts.add(t); parts.add(t);
return this;
} }
@Override @Override
@ -35,4 +37,14 @@ public abstract class AbstractGear extends Model implements IGear {
part.render(stack, renderContext, overlayUv, lightUv, red, green, blue, alpha); part.render(stack, renderContext, overlayUv, lightUv, red, green, blue, alpha);
}); });
} }
@Override
public boolean isStackable() {
return stackingHeight > 0;
}
@Override
public float getStackingHeight() {
return stackingHeight;
}
} }

View file

@ -7,10 +7,8 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.IModel;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.render.entity.feature.GearFeature; import com.minelittlepony.client.render.entity.feature.GearFeature;
import java.util.UUID; import java.util.UUID;
@ -19,13 +17,13 @@ import java.util.function.Supplier;
/** /**
* Interface for an accessory on a pony's body. * Interface for an accessory on a pony's body.
*/ */
public interface IGear { public interface Gear {
/** /**
* Registers a custom gear to be used with the mod. * Registers a custom gear to be used with the mod.
* <p> * <p>
* This would be awesome for creating socks. * This would be awesome for creating socks.
*/ */
static Supplier<IGear> register(Supplier<IGear> gear) { static Supplier<Gear> register(Supplier<Gear> gear) {
GearFeature.addModGear(gear); GearFeature.addModGear(gear);
return gear; return gear;
} }
@ -38,13 +36,26 @@ public interface IGear {
* *
* @return True to render this wearable * @return True to render this wearable
*/ */
boolean canRender(IModel model, Entity entity); boolean canRender(PonyModel<?> model, Entity entity);
/** /**
* Gets the body location that this wearable appears on. * Gets the body location that this wearable appears on.
*/ */
BodyPart getGearLocation(); BodyPart getGearLocation();
default boolean isStackable() {
return false;
}
/**
* The vertical height of this gear when present in a stack.
*
* Any gear rendered after this one will be shifted to sit on top of it.
*/
default float getStackingHeight() {
return 0;
}
/** /**
* Gets the texture to use for this wearable. * Gets the texture to use for this wearable.
* *
@ -62,7 +73,7 @@ public interface IGear {
/** /**
* Applies body transformations for this wearable * Applies body transformations for this wearable
*/ */
default <M extends EntityModel<?> & IPonyModel<?>> void transform(M model, MatrixStack matrices) { default <M extends EntityModel<?> & PonyModel<?>> void transform(M model, MatrixStack matrices) {
BodyPart part = getGearLocation(); BodyPart part = getGearLocation();
model.transform(part, matrices); model.transform(part, matrices);
model.getBodyPart(part).rotate(matrices); model.getBodyPart(part).rotate(matrices);
@ -73,23 +84,10 @@ public interface IGear {
* *
* See {@link AbstractPonyMode.setRotationAndAngle} for an explanation of the various parameters. * See {@link AbstractPonyMode.setRotationAndAngle} for an explanation of the various parameters.
*/ */
default void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { default void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
setModelAttributes(model, entity);
pose(rainboom, interpolatorId, move, swing, bodySwing, ticks);
} }
/**
* @deprecated Use pose(model, entity, rainboom, interpolatorId, move, swing, bodySwing, ticks) instead
*/
@Deprecated(forRemoval = true)
default void setModelAttributes(IModel model, Entity entity) { }
/**
* @deprecated Use pose(model, entity, rainboom, interpolatorId, move, swing, bodySwing, ticks) instead
*/
@Deprecated(forRemoval = true)
default void pose(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { }
/** /**
* Renders this model component. * Renders this model component.
*/ */
@ -101,7 +99,7 @@ public interface IGear {
* @param <T> The type of entity being rendered. * @param <T> The type of entity being rendered.
* @param <M> The type of the entity's primary model. * @param <M> The type of the entity's primary model.
*/ */
public interface Context<T extends Entity, M extends IModel> { public interface Context<T extends Entity, M extends PonyModel<?>> {
/** /**
* The empty context. * The empty context.
*/ */
@ -110,7 +108,7 @@ public interface IGear {
/** /**
* Checks whether the given wearable and gear are able to render for this specific entity and its renderer. * Checks whether the given wearable and gear are able to render for this specific entity and its renderer.
*/ */
default boolean shouldRender(M model, T entity, Wearable wearable, IGear gear) { default boolean shouldRender(M model, T entity, Wearable wearable, Gear gear) {
return gear.canRender(model, entity); return gear.canRender(model, entity);
} }

View file

@ -1,14 +0,0 @@
package com.minelittlepony.api.model.gear;
/**
* Interface for any gear that changes its position based on where it is in the hat stack.
*/
public interface IStackable {
/**
* The vertical height of this gear when present in a stack.
*
* Any gear rendered after this one will be shifted to sit on top of it.
*/
float getStackingHeight();
}

View file

@ -1,18 +1,19 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.api.model.gear;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public abstract class AbstractWearableGear extends AbstractGear { public class WearableGear extends AbstractGearModel {
protected final Wearable wearable; protected final Wearable wearable;
protected final BodyPart location; protected final BodyPart location;
protected AbstractWearableGear(Wearable wearable, BodyPart location) { public WearableGear(Wearable wearable, BodyPart location, float stackingHeight) {
super(stackingHeight);
this.wearable = wearable; this.wearable = wearable;
this.location = location; this.location = location;
} }
@ -23,7 +24,7 @@ public abstract class AbstractWearableGear extends AbstractGear {
} }
@Override @Override
public boolean canRender(IModel model, Entity entity) { public boolean canRender(PonyModel<?> model, Entity entity) {
return model.isWearing(wearable); return model.isWearing(wearable);
} }

View file

@ -28,7 +28,7 @@ public final class DefaultPonySkinHelper {
public static String getModelType(UUID id) { public static String getModelType(UUID id) {
SkinTextures textures = DefaultSkinHelper.getTexture(id); SkinTextures textures = DefaultSkinHelper.getTexture(id);
return getModelType(IPony.getManager().getPony(textures.texture(), id).race(), textures.model()); return getModelType(Pony.getManager().getPony(textures.texture(), id).race(), textures.model());
} }
public static String getModelType(Race race, SkinTextures.Model armShape) { public static String getModelType(Race race, SkinTextures.Model armShape) {

View file

@ -1,82 +0,0 @@
package com.minelittlepony.api.pony;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ComparisonChain;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.util.animation.Interpolator;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
/**
* Metadata for a pony.
*/
public interface IPonyData extends Comparable<IPonyData> {
/**
* Gets this pony's race.
*
* This is the actual race value. For the effective race, prefer going through {@link IPony#race}
*/
Race race();
/**
* Gets the length of the pony's tail.
*/
TailLength tailLength();
/**
* Gets the shape of the pony's tail.
*/
TailShape tailShape();
/**
* Get the pony's gender (usually female).
*/
Gender gender();
/**
* Gets the current pony size.
*/
Size size();
/**
* Gets the magical glow colour for magic-casting races. Returns 0 otherwise.
*/
int glowColor();
/**
* Returns an array of wearables that this pony is carrying.
*/
Wearable[] gear();
/**
* Checks it this pony is wearing the given accessory.
*/
boolean isWearing(Wearable wearable);
/**
* Gets an interpolator for interpolating values.
*/
default Interpolator getInterpolator(UUID interpolatorId) {
return Interpolator.linear(interpolatorId);
}
/**
* Gets the trigger pixel values as they appeared in the underlying image.
*/
Map<String, TriggerPixelType<?>> attributes();
@Override
default int compareTo(@Nullable IPonyData o) {
return o == this ? 0 : o == null ? 1 : ComparisonChain.start()
.compare(race(), o.race())
.compare(tailLength(), o.tailLength())
.compare(gender(), o.gender())
.compare(size().ordinal(), o.size().ordinal())
.compare(glowColor(), o.glowColor())
.compare(0, Arrays.compare(gear(), o.gear()))
.result();
}
}

View file

@ -7,64 +7,64 @@ import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Size;
public interface IPony extends Comparable<IPony> { import java.util.Optional;
import java.util.function.Supplier;
public record Pony (
/**
* Gets the texture used for rendering this pony.
*/
Identifier texture,
Supplier<Optional<PonyData>> metadataGetter
) implements Comparable<Pony> {
/** /**
* Gets the global pony manager instance. * Gets the global pony manager instance.
*/ */
static IPonyManager getManager() { public static PonyManager getManager() {
return IPonyManager.Instance.instance; return PonyManager.Instance.instance;
} }
/** /**
* Gets or creates a new pony associated with the provided resource location. * Gets the metadata associated with this pony's model texture.
* The results of this method should not be cached.
*
* @deprecated User IPony.getManager().getPony(texture) instead
*/ */
@Deprecated public PonyData metadata() {
static IPony forResource(Identifier texture) { return metadataGetter().get().orElse(PonyData.NULL);
return getManager().getPony(texture);
} }
/**
* Returns whether this is one of the default ponies assigned to a player without a custom skin.
*/
boolean defaulted();
/** /**
* Returns whether this pony's metadata block has been initialized. * Returns whether this pony's metadata block has been initialized.
*/ */
boolean hasMetadata(); public boolean hasMetadata() {
return metadataGetter().get().isPresent();
}
public Pony immutableCopy() {
final Optional<PonyData> metadata = metadataGetter().get();
return new Pony(texture(), () -> metadata);
}
/** /**
* Gets the race associated with this pony. * Gets the race associated with this pony.
*/ */
default Race race() { public Race race() {
return PonyConfig.getEffectiveRace(metadata().race()); return PonyConfig.getEffectiveRace(metadata().race());
} }
public Size size() {
return PonyConfig.getEffectiveSize(metadata().size());
}
/** /**
* Returns true if and only if this metadata represents a pony that can cast magic. * Returns true if and only if this metadata represents a pony that can cast magic.
*/ */
default boolean hasMagic() { public boolean hasMagic() {
return race().hasHorn() && metadata().glowColor() != 0; return race().hasHorn() && metadata().glowColor() != 0;
} }
/**
* Gets the texture used for rendering this pony.
*/
Identifier texture();
/**
* Gets the metadata associated with this pony's model texture.
*/
IPonyData metadata();
@Override @Override
default int compareTo(@Nullable IPony o) { public int compareTo(@Nullable Pony o) {
return o == this ? 0 : o == null ? 1 : ComparisonChain.start() return o == this ? 0 : o == null ? 1 : ComparisonChain.start()
.compare(texture(), o.texture()) .compare(texture(), o.texture())
.compare(metadata(), o.metadata()) .compare(metadata(), o.metadata())

View file

@ -0,0 +1,127 @@
package com.minelittlepony.api.pony;
import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ComparisonChain;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.util.animation.Interpolator;
import java.util.*;
import java.util.function.Function;
/**
* Metadata for a pony.
*/
public record PonyData (
/**
* Gets this pony's race.
*
* This is the actual race value. For the effective race, prefer going through {@link Pony#race}
*/
Race race,
/**
* Gets the length of the pony's tail.
*/
TailLength tailLength,
/**
* Gets the shape of the pony's tail.
*/
TailShape tailShape,
/**
* Get the pony's gender (usually female).
*/
Gender gender,
/**
* Gets the current pony size.
*/
Size size,
/**
* Gets the magical glow colour for magic-casting races. Returns 0 otherwise.
*/
int glowColor,
/**
* Returns an array of wearables that this pony is carrying.
*/
Flags<Wearable> gear,
/**
* Indicates whether this pony data corresponds to one of the default/built-in skins
* rather than a user-uploaded one.
*/
boolean noSkin,
/**
* Gets the trigger pixel values as they appeared in the underlying image.
*/
Map<String, TriggerPixelType<?>> attributes
) implements Comparable<PonyData> {
private static final Function<Race, PonyData> OF_RACE = Util.memoize(race -> {
return new PonyData(race, TailLength.FULL, TailShape.STRAIGHT, Gender.MARE, Sizes.NORMAL, 0x4444aa, Wearable.EMPTY_FLAGS, true, Util.make(new TreeMap<>(), attributes -> {
attributes.put("race", race);
attributes.put("tailLength", TailLength.FULL);
attributes.put("tailShape", TailShape.STRAIGHT);
attributes.put("gender", Gender.MARE);
attributes.put("size", Sizes.NORMAL);
attributes.put("magic", TriggerPixelType.of(0x4444aa));
attributes.put("gear", TriggerPixelType.of(0));
}));
});
public static final PonyData NULL = OF_RACE.apply(Race.HUMAN);
public static PonyData emptyOf(Race race) {
return OF_RACE.apply(race);
}
public PonyData(Race race, TailLength tailLength, TailShape tailShape, Gender gender, Size size, int glowColor, boolean noSkin, Flags<Wearable> wearables) {
this(race, tailLength, tailShape, gender, size, glowColor, wearables, noSkin, Util.make(new TreeMap<>(), map -> {
map.put("race", race);
map.put("tailLength", tailLength);
map.put("tailShape", tailShape);
map.put("gender", gender);
map.put("size", size);
map.put("magic", TriggerPixelType.of(glowColor));
map.put("gear", TriggerPixelType.of(wearables.colorCode()));
}));
}
public PonyData(Race race, TailLength tailLength, TailShape tailShape, Gender gender, Size size, int glowColor, TriggerPixelType.Multiple<Wearable> wearables, boolean noSkin) {
this(race, tailLength, tailShape, gender, size, glowColor,
Flags.of(Wearable.class, wearables.colorCode(), wearables.value()),
noSkin, Util.make(new TreeMap<>(), map -> {
map.put("race", race);
map.put("tailLength", tailLength);
map.put("tailShape", tailShape);
map.put("gender", gender);
map.put("size", size);
map.put("magic", TriggerPixelType.of(glowColor));
map.put("gear", wearables);
})
);
}
/**
* Checks it this pony is wearing the given accessory.
*/
public boolean isWearing(Wearable wearable) {
return gear().includes(wearable);
}
/**
* Gets an interpolator for interpolating values.
*/
public Interpolator getInterpolator(UUID interpolatorId) {
return Interpolator.linear(interpolatorId);
}
@Override
public int compareTo(@Nullable PonyData o) {
return o == this ? 0 : o == null ? 1 : ComparisonChain.start()
.compare(race(), o.race())
.compare(tailLength(), o.tailLength())
.compare(gender(), o.gender())
.compare(size().ordinal(), o.size().ordinal())
.compare(glowColor(), o.glowColor())
.compare(0, gear().compareTo(o.gear()))
.result();
}
}

View file

@ -13,13 +13,13 @@ import java.util.UUID;
* The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin. * The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin.
* *
*/ */
public interface IPonyManager { public interface PonyManager {
/** /**
* Gets a pony representation of the passed in entity. * Gets a pony representation of the passed in entity.
* *
* If the supplied entity is null or can't be determined to be a pony, returns the empty optional. * If the supplied entity is null or can't be determined to be a pony, returns the empty optional.
*/ */
Optional<IPony> getPony(@Nullable Entity entity); Optional<Pony> getPony(@Nullable Entity entity);
/** /**
* Gets or creates a pony for the given player. * Gets or creates a pony for the given player.
@ -27,14 +27,14 @@ public interface IPonyManager {
* *
* @param player the player * @param player the player
*/ */
IPony getPony(PlayerEntity player); Pony getPony(PlayerEntity player);
/** /**
* Gets or creates a pony for the given skin resource and vanilla model type. * Gets or creates a pony for the given skin resource and vanilla model type.
* *
* @param resource A texture resource * @param resource A texture resource
*/ */
IPony getPony(Identifier resource); Pony getPony(Identifier resource);
/** /**
* Gets or creates a pony for the given skin resource and entity id. * Gets or creates a pony for the given skin resource and entity id.
@ -46,7 +46,7 @@ public interface IPonyManager {
* @param resource A texture resource * @param resource A texture resource
* @param uuid id of a player * @param uuid id of a player
*/ */
IPony getPony(Identifier resource, UUID uuid); Pony getPony(Identifier resource, UUID uuid);
/** /**
* Gets a random background pony determined by the given uuid. * Gets a random background pony determined by the given uuid.
@ -55,16 +55,18 @@ public interface IPonyManager {
* *
* @param uuid A UUID. Either a user or an entity. * @param uuid A UUID. Either a user or an entity.
*/ */
IPony getBackgroundPony(UUID uuid); Pony getBackgroundPony(UUID uuid);
/** /**
* De-registers a pony from the cache. * De-registers a pony from the cache.
*/ */
void removePony(Identifier resource); void removePony(Identifier resource);
void clearCache();
interface ForcedPony {} interface ForcedPony {}
final class Instance { final class Instance {
public static IPonyManager instance; public static PonyManager instance;
} }
} }

View file

@ -1,7 +1,7 @@
package com.minelittlepony.api.pony; package com.minelittlepony.api.pony;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.IPreviewModel; import com.minelittlepony.client.PreviewModel;
import com.minelittlepony.client.SkinsProxy; import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer; import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
@ -17,13 +17,13 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public final class PonyPosture { public final class PonyPosture {
public static Optional<IPony> getMountPony(LivingEntity entity) { public static Optional<Pony> getMountPony(LivingEntity entity) {
return entity.getVehicle() instanceof LivingEntity mount return entity.getVehicle() instanceof LivingEntity mount
? IPony.getManager().getPony(mount) ? Pony.getManager().getPony(mount)
: Optional.empty(); : Optional.empty();
} }
public static boolean isCrouching(IPony pony, LivingEntity entity) { public static boolean isCrouching(Pony pony, LivingEntity entity) {
boolean isSneak = entity.isInSneakingPose(); boolean isSneak = entity.isInSneakingPose();
boolean isFlying = isFlying(entity); boolean isFlying = isFlying(entity);
boolean isSwimming = isSwimming(entity); boolean isSwimming = isSwimming(entity);
@ -31,7 +31,7 @@ public final class PonyPosture {
return !isPerformingRainboom(pony, entity) && !isSwimming && isSneak && !isFlying; return !isPerformingRainboom(pony, entity) && !isSwimming && isSneak && !isFlying;
} }
private static boolean isPerformingRainboom(IPony pony, LivingEntity entity) { private static boolean isPerformingRainboom(Pony pony, LivingEntity entity) {
Vec3d motion = entity.getVelocity(); Vec3d motion = entity.getVelocity();
double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z); double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
@ -85,21 +85,21 @@ public final class PonyPosture {
} }
public static boolean isRidingAPony(LivingEntity entity) { public static boolean isRidingAPony(LivingEntity entity) {
return isSitting(entity) && getMountPony(entity).map(IPony::race).orElse(Race.HUMAN) != Race.HUMAN; return isSitting(entity) && getMountPony(entity).map(Pony::race).orElse(Race.HUMAN) != Race.HUMAN;
} }
public static boolean isSeaponyModifier(LivingEntity entity) { public static boolean isSeaponyModifier(LivingEntity entity) {
if (entity instanceof IPreviewModel preview) { if (entity instanceof PreviewModel preview) {
return preview.forceSeapony(); return preview.forceSeapony();
} }
return hasSeaponyForm(entity) && isPartiallySubmerged(entity); return hasSeaponyForm(entity) && isPartiallySubmerged(entity);
} }
public static boolean hasSeaponyForm(LivingEntity entity) { public static boolean hasSeaponyForm(LivingEntity entity) {
if (entity instanceof IPreviewModel preview) { if (entity instanceof PreviewModel preview) {
return preview.forceSeapony(); return preview.forceSeapony();
} }
return IPony.getManager().getPony(entity).filter(pony -> { return Pony.getManager().getPony(entity).filter(pony -> {
return (pony.race() == Race.SEAPONY return (pony.race() == Race.SEAPONY
|| (entity instanceof AbstractClientPlayerEntity player && SkinsProxy.instance.getSkin(AquaticPlayerPonyRenderer.SKIN_TYPE_ID, player).isPresent()) || (entity instanceof AbstractClientPlayerEntity player && SkinsProxy.instance.getSkin(AquaticPlayerPonyRenderer.SKIN_TYPE_ID, player).isPresent())
); );

View file

@ -0,0 +1,53 @@
package com.minelittlepony.api.pony.meta;
import net.minecraft.network.PacketByteBuf;
import java.util.*;
public record Flags<T extends Enum<T>> (
boolean[] flags,
List<T> values,
int colorCode
) implements Comparable<Flags<T>> {
public static <T extends Enum<T>> Flags<T> of(Class<T> type) {
return new Flags<>(new boolean[type.getEnumConstants().length], List.<T>of(), 0);
}
public static <T extends Enum<T>> Flags<T> of(Class<T> type, int colorCode, boolean...flags) {
return new Flags<>(flags, flags(type.getEnumConstants(), flags), colorCode);
}
public static <T extends Enum<T>> Flags<T> read(Class<T> type, PacketByteBuf buffer) {
int length = buffer.readVarInt();
List<T> values = new ArrayList<>();
T[] all = type.getEnumConstants();
boolean[] flags = new boolean[all.length];
for (int i = 0; i < length; i++) {
values.add(all[buffer.readInt()]);
flags[i] = true;
}
return new Flags<>(flags, values, buffer.readInt());
}
public static <T> List<T> flags(T[] values, boolean[] flags) {
List<T> wears = new ArrayList<>();
for (int i = 0; i < values.length; i++) {
if (flags[i]) wears.add(values[i]);
}
return wears;
}
public boolean includes(T t) {
return flags[t.ordinal()];
}
public int compareTo(Flags<T> other) {
return Arrays.compare(flags, other.flags);
}
public void write(PacketByteBuf buffer) {
buffer.writeCollection(values, (buf, value) -> buf.writeInt(value.ordinal()));
buffer.writeInt(colorCode);
}
}

View file

@ -1,7 +1,5 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import com.minelittlepony.api.pony.TriggerPixelType;
public enum Gender implements TriggerPixelType<Gender> { public enum Gender implements TriggerPixelType<Gender> {
MARE(0), MARE(0),
STALLION(0xffffff), STALLION(0xffffff),

View file

@ -1,7 +1,5 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import com.minelittlepony.api.pony.TriggerPixelType;
import java.util.*; import java.util.*;
public enum Race implements TriggerPixelType<Race> { public enum Race implements TriggerPixelType<Race> {

View file

@ -1,7 +1,5 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import com.minelittlepony.api.pony.TriggerPixelType;
/** /**
* Represents the different model sizes that are possible. * Represents the different model sizes that are possible.
* *

View file

@ -1,7 +1,5 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import com.minelittlepony.api.pony.TriggerPixelType;
public enum TailLength implements TriggerPixelType<TailLength> { public enum TailLength implements TriggerPixelType<TailLength> {
STUB (0x425844), STUB (0x425844),
QUARTER (0xd19fe4), QUARTER (0xd19fe4),

View file

@ -1,7 +1,5 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import com.minelittlepony.api.pony.TriggerPixelType;
public enum TailShape implements TriggerPixelType<TailShape> { public enum TailShape implements TriggerPixelType<TailShape> {
STRAIGHT(0), STRAIGHT(0),
BUMPY (0xfc539f), BUMPY (0xfc539f),

View file

@ -2,7 +2,6 @@ package com.minelittlepony.api.pony.meta;
import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.NativeImage;
import com.minelittlepony.api.pony.TriggerPixelType;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
import java.util.Arrays; import java.util.Arrays;
@ -21,12 +20,12 @@ public enum TriggerPixel {
WEARABLES(Wearable.NONE, Channel.RAW, 1, 1), WEARABLES(Wearable.NONE, Channel.RAW, 1, 1),
TAIL_SHAPE(TailShape.STRAIGHT, Channel.ALL, 2, 1); TAIL_SHAPE(TailShape.STRAIGHT, Channel.ALL, 2, 1);
private int x; private final int x;
private int y; private final int y;
private Channel channel; private final Channel channel;
TriggerPixelType<?> def; private final TriggerPixelType<?> def;
private static final TriggerPixel[] VALUES = values(); private static final TriggerPixel[] VALUES = values();
private static final int MAX_READ_X = Arrays.stream(VALUES).mapToInt(i -> i.x).max().getAsInt(); private static final int MAX_READ_X = Arrays.stream(VALUES).mapToInt(i -> i.x).max().getAsInt();
@ -53,20 +52,20 @@ public enum TriggerPixel {
* *
* @param image Image to read * @param image Image to read
*/ */
public <T extends TriggerPixelType<T>> TriggerPixelType.Value<T> readValue(NativeImage image) { public <T extends TriggerPixelType<T>> T readValue(NativeImage image) {
int color = readColor(image); int color = readColor(image);
if (Channel.ALPHA.readValue(x, y, image) < 255) { if (Channel.ALPHA.readValue(x, y, image) < 255) {
return new TriggerPixelType.Value<>(color, (T)def); return (T)def;
} }
return new TriggerPixelType.Value<>(color, TriggerPixelType.getByTriggerPixel((T)def, color)); return TriggerPixelType.getByTriggerPixel((T)def, color);
} }
public <T extends Enum<T> & TriggerPixelType<T>> TriggerPixelType.Flags<T> readFlags(NativeImage image) { public <T extends Enum<T> & TriggerPixelType<T>> TriggerPixelType.Multiple<T> readFlags(NativeImage image) {
boolean[] out = new boolean[def.getClass().getEnumConstants().length]; boolean[] out = new boolean[def.getClass().getEnumConstants().length];
readFlags(out, image); readFlags(out, image);
return new TriggerPixelType.Flags<>(readColor(image), (T)def, out); return new TriggerPixelType.Multiple<>(readColor(image), (T)def, out);
} }
public <T extends Enum<T> & TriggerPixelType<T>> void readFlags(boolean[] out, NativeImage image) { public <T extends Enum<T> & TriggerPixelType<T>> void readFlags(boolean[] out, NativeImage image) {

View file

@ -1,4 +1,4 @@
package com.minelittlepony.api.pony; package com.minelittlepony.api.pony.meta;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -73,7 +73,7 @@ public interface TriggerPixelType<T> {
return "#" + v; return "#" + v;
} }
public record Flags<T extends Enum<T> & TriggerPixelType<T>> ( public record Multiple<T extends Enum<T> & TriggerPixelType<T>> (
int colorCode, int colorCode,
T def, T def,
boolean[] value boolean[] value
@ -94,21 +94,4 @@ public interface TriggerPixelType<T> {
return o.getClass() == def.getClass() && value()[((Enum<?>)o).ordinal()]; return o.getClass() == def.getClass() && value()[((Enum<?>)o).ordinal()];
} }
} }
public record Value<T> (
int colorCode,
T value
) implements TriggerPixelType<T> {
@Override
public String name() {
return value instanceof TriggerPixelType t ? t.name() : TriggerPixelType.super.name();
}
@SuppressWarnings("unchecked")
@Override
public <Option extends TriggerPixelType<T>> List<Option> getOptions() {
return value instanceof TriggerPixelType t ? t.getOptions() : TriggerPixelType.super.getOptions();
}
}
} }

View file

@ -2,7 +2,6 @@ package com.minelittlepony.api.pony.meta;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.TriggerPixelType;
import com.minelittlepony.client.model.gear.SaddleBags; import com.minelittlepony.client.model.gear.SaddleBags;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
@ -30,6 +29,8 @@ public enum Wearable implements TriggerPixelType<Wearable> {
public static final List<Wearable> VALUES = Arrays.stream(values()).toList(); public static final List<Wearable> VALUES = Arrays.stream(values()).toList();
public static final Map<Identifier, Wearable> REGISTRY = VALUES.stream().collect(Collectors.toMap(Wearable::getId, Function.identity())); public static final Map<Identifier, Wearable> REGISTRY = VALUES.stream().collect(Collectors.toMap(Wearable::getId, Function.identity()));
public static final Flags<Wearable> EMPTY_FLAGS = Flags.of(Wearable.class);
Wearable(int pixel, Identifier texture) { Wearable(int pixel, Identifier texture) {
triggerValue = pixel; triggerValue = pixel;
id = new Identifier("minelittlepony", name().toLowerCase(Locale.ROOT)); id = new Identifier("minelittlepony", name().toLowerCase(Locale.ROOT));
@ -57,20 +58,4 @@ public enum Wearable implements TriggerPixelType<Wearable> {
public int getChannelAdjustedColorCode() { public int getChannelAdjustedColorCode() {
return triggerValue == 0 ? 0 : Color.argbToHex(255, triggerValue, triggerValue, triggerValue); return triggerValue == 0 ? 0 : Color.argbToHex(255, triggerValue, triggerValue, triggerValue);
} }
public static boolean[] flags(Wearable[] wears) {
boolean[] flags = new boolean[VALUES.size()];
for (int i = 0; i < wears.length; i++) {
flags[wears[i].ordinal()] = true;
}
return flags;
}
public static Wearable[] flags(boolean[] flags) {
List<Wearable> wears = new ArrayList<>();
for (int i = 0; i < VALUES.size(); i++) {
if (flags[i]) wears.add(VALUES.get(i));
}
return wears.toArray(new Wearable[0]);
}
} }

View file

@ -1,177 +1,46 @@
package com.minelittlepony.api.pony.network; package com.minelittlepony.api.pony.network;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Util;
import com.google.common.base.MoreObjects; import com.minelittlepony.api.pony.PonyData;
import com.google.common.base.Suppliers;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.api.pony.TriggerPixelType;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.util.animation.Interpolator;
import java.util.Map; public class MsgPonyData {
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Supplier;
public class MsgPonyData implements IPonyData {
private static final short API_IDENTIFIER = (short) 0xABCD; private static final short API_IDENTIFIER = (short) 0xABCD;
// API version - increment this number before any time any data is added/removed/moved in the data stream // API version - increment this number before any time any data is added/removed/moved in the data stream
private static final byte API_VERSION = 2; private static final byte API_VERSION = 2;
private final Race race; public static PonyData read(PacketByteBuf buffer) {
private final TailLength tailLength;
private final TailShape tailShape;
private final Gender gender;
private final Size size;
private final int glowColor;
private final boolean noSkin;
private final int wearableColor;
private final boolean[] wearables;
private final Supplier<Map<String, TriggerPixelType<?>>> triggerPixels = Suppliers.memoize(() -> Util.make(new TreeMap<>(), this::initTriggerPixels));
private void initTriggerPixels(Map<String, TriggerPixelType<?>> map) {
map.put("race", race);
map.put("tailLength", tailLength);
map.put("tailShape", tailShape);
map.put("gender", gender);
map.put("size", size);
map.put("magic", TriggerPixelType.of(glowColor));
map.put("gear", TriggerPixelType.of(wearableColor));
}
public MsgPonyData(PacketByteBuf buffer) {
short data = buffer.readShort(); short data = buffer.readShort();
if (data != API_IDENTIFIER || buffer.readByte() != API_VERSION) { if (data != API_IDENTIFIER || buffer.readByte() != API_VERSION) {
race = null; return PonyData.NULL;
tailLength = null;
tailShape = null;
gender = null;
size = null;
glowColor = 0;
noSkin = true;
wearables = null;
wearableColor = 0;
return;
} }
race = buffer.readEnumConstant(Race.class); return new PonyData(
tailLength = buffer.readEnumConstant(TailLength.class); buffer.readEnumConstant(Race.class),
tailShape = buffer.readEnumConstant(TailShape.class); buffer.readEnumConstant(TailLength.class),
gender = buffer.readEnumConstant(Gender.class); buffer.readEnumConstant(TailShape.class),
size = new MsgSize(buffer); buffer.readEnumConstant(Gender.class),
glowColor = buffer.readInt(); new MsgSize(buffer),
noSkin = buffer.readBoolean(); buffer.readInt(),
Wearable[] gear = new Wearable[buffer.readInt()]; buffer.readBoolean(),
Wearable[] all = Wearable.values(); Flags.read(Wearable.class, buffer)
for (int i = 0; i < gear.length; i++) { );
gear[i] = all[buffer.readInt()];
}
wearables = Wearable.flags(gear);
wearableColor = buffer.readInt();
} }
public MsgPonyData(IPonyData data, boolean noSkin) { public static PacketByteBuf write(PonyData data, PacketByteBuf buffer) {
race = data.race();
tailLength = data.tailLength();
tailShape = data.tailShape();
gender = data.gender();
size = data.size();
glowColor = data.glowColor();
wearables = Wearable.flags(data.gear());
wearableColor = data.attributes().get("gear").colorCode();
this.noSkin = noSkin;
}
public PacketByteBuf toBuffer(PacketByteBuf buffer) {
buffer.writeShort(API_IDENTIFIER); buffer.writeShort(API_IDENTIFIER);
buffer.writeByte(API_VERSION); buffer.writeByte(API_VERSION);
buffer.writeEnumConstant(race); buffer.writeEnumConstant(data.race());
buffer.writeEnumConstant(tailLength); buffer.writeEnumConstant(data.tailLength());
buffer.writeEnumConstant(tailShape); buffer.writeEnumConstant(data.tailShape());
buffer.writeEnumConstant(gender); buffer.writeEnumConstant(data.gender());
new MsgSize(size).toBuffer(buffer); new MsgSize(data.size()).toBuffer(buffer);
buffer.writeInt(glowColor); buffer.writeInt(data.glowColor());
buffer.writeBoolean(noSkin); buffer.writeBoolean(data.noSkin());
data.gear().write(buffer);
Wearable[] gear = gear();
buffer.writeInt(gear.length);
for (int i = 0; i < gear.length; i++) {
buffer.writeInt(gear[i].ordinal());
}
buffer.writeInt(wearableColor);
return buffer; return buffer;
} }
public boolean isNoSkin() {
return noSkin;
}
@Override
public Race race() {
return race;
}
@Override
public TailLength tailLength() {
return tailLength;
}
@Override
public TailShape tailShape() {
return tailShape;
}
@Override
public Gender gender() {
return gender;
}
@Override
public Size size() {
return size;
}
@Override
public int glowColor() {
return glowColor;
}
@Override
public Wearable[] gear() {
return Wearable.flags(wearables);
}
@Override
public boolean isWearing(Wearable wearable) {
return wearables[wearable.ordinal()];
}
@Override
public Interpolator getInterpolator(UUID interpolatorId) {
return Interpolator.linear(interpolatorId);
}
@Override
public Map<String, TriggerPixelType<?>> attributes() {
return triggerPixels.get();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("race", race)
.add("tailLength", tailLength)
.add("tailShape", tailShape)
.add("gender", gender)
.add("size", size)
.add("wearables", gear())
.add("glowColor", TriggerPixelType.toHex(glowColor))
.toString();
}
private record MsgSize ( private record MsgSize (
int ordinal, int ordinal,
String name, String name,
@ -179,7 +48,7 @@ public class MsgPonyData implements IPonyData {
float scaleFactor, float scaleFactor,
float eyeHeightFactor, float eyeHeightFactor,
float eyeDistanceFactor, float eyeDistanceFactor,
int triggerPixel) implements Size { int colorCode) implements Size {
MsgSize(Size size) { MsgSize(Size size) {
this(size.ordinal(), size.name(), size.shadowSize(), size.scaleFactor(), size.eyeHeightFactor(), size.eyeDistanceFactor(), size.colorCode()); this(size.ordinal(), size.name(), size.shadowSize(), size.scaleFactor(), size.eyeHeightFactor(), size.eyeDistanceFactor(), size.colorCode());
@ -196,17 +65,12 @@ public class MsgPonyData implements IPonyData {
buffer.writeFloat(scaleFactor); buffer.writeFloat(scaleFactor);
buffer.writeFloat(eyeHeightFactor); buffer.writeFloat(eyeHeightFactor);
buffer.writeFloat(eyeDistanceFactor); buffer.writeFloat(eyeDistanceFactor);
buffer.writeFloat(triggerPixel); buffer.writeFloat(colorCode);
} }
@Override @Override
public String toString() { public String toString() {
return name; return name;
} }
@Override
public int colorCode() {
return triggerPixel;
}
} }
} }

View file

@ -11,7 +11,8 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.network.MsgPonyData; import com.minelittlepony.api.pony.network.MsgPonyData;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
@ -35,22 +36,22 @@ public class Channel {
ClientPlayNetworking.registerGlobalReceiver(REQUEST_PONY_DATA, (client, handler, ignored, sender) -> { ClientPlayNetworking.registerGlobalReceiver(REQUEST_PONY_DATA, (client, handler, ignored, sender) -> {
if (client.player != null) { if (client.player != null) {
IPony pony = IPony.getManager().getPony(client.player); Pony pony = Pony.getManager().getPony(client.player);
registered = true; registered = true;
MineLittlePony.logger.info("Server has just consented"); MineLittlePony.logger.info("Server has just consented");
sender.sendPacket(CLIENT_PONY_DATA, new MsgPonyData(pony.metadata(), pony.defaulted()).toBuffer(PacketByteBufs.create())); sender.sendPacket(CLIENT_PONY_DATA, MsgPonyData.write(pony.metadata(), PacketByteBufs.create()));
} }
}); });
ServerPlayNetworking.registerGlobalReceiver(CLIENT_PONY_DATA, (server, player, ignore, buffer, ignore2) -> { ServerPlayNetworking.registerGlobalReceiver(CLIENT_PONY_DATA, (server, player, ignore, buffer, ignore2) -> {
MsgPonyData packet = new MsgPonyData(buffer); PonyData packet = MsgPonyData.read(buffer);
server.execute(() -> { server.execute(() -> {
PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, packet, packet.isNoSkin(), EnvType.SERVER); PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, packet, EnvType.SERVER);
}); });
}); });
} }
public static void broadcastPonyData(MsgPonyData packet) { public static void broadcastPonyData(PonyData packet) {
if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) {
throw new RuntimeException("Client packet send called by the server"); throw new RuntimeException("Client packet send called by the server");
} }
@ -64,6 +65,6 @@ public class Channel {
} }
} }
ClientPlayNetworking.send(CLIENT_PONY_DATA, packet.toBuffer(PacketByteBufs.create())); ClientPlayNetworking.send(CLIENT_PONY_DATA, MsgPonyData.write(packet, PacketByteBufs.create()));
} }
} }

View file

@ -5,17 +5,16 @@ import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory; import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.PonyData;
/** /**
* Callback triggered on the server when receiving pony data from a client. * Callback triggered on the server when receiving pony data from a client.
* *
*/ */
public interface PonyDataCallback { public interface PonyDataCallback {
Event<PonyDataCallback> EVENT = EventFactory.createArrayBacked(PonyDataCallback.class, listeners -> (sender, data, env) -> {
Event<PonyDataCallback> EVENT = EventFactory.createArrayBacked(PonyDataCallback.class, listeners -> (sender, data, noSkin, env) -> {
for (PonyDataCallback event : listeners) { for (PonyDataCallback event : listeners) {
event.onPonyDataAvailable(sender, data, noSkin, env); event.onPonyDataAvailable(sender, data, env);
} }
}); });
@ -23,8 +22,7 @@ public interface PonyDataCallback {
* Called when pony data is received. * Called when pony data is received.
* @param sender The player who sent the data - this is the owner of the skin/pony data. * @param sender The player who sent the data - this is the owner of the skin/pony data.
* @param data The skin/pony data * @param data The skin/pony data
* @param noSkin Whether the data is for a player with a default/unset custom skin.
* @param env The environment. Whether this call is coming from the client or server. Clients may get two calls, one for both. * @param env The environment. Whether this call is coming from the client or server. Clients may get two calls, one for both.
*/ */
void onPonyDataAvailable(PlayerEntity sender, IPonyData data, boolean noSkin, EnvType env); void onPonyDataAvailable(PlayerEntity sender, PonyData data, EnvType env);
} }

View file

@ -1,4 +1,4 @@
package com.minelittlepony.client.settings; package com.minelittlepony.client;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;

View file

@ -5,7 +5,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.common.util.settings.Setting; import com.minelittlepony.common.util.settings.Setting;
public class HorseCam { public class HorseCam {
@ -48,7 +48,7 @@ public class HorseCam {
return pitch; return pitch;
} }
IPony pony = IPony.getManager().getPony(player); Pony pony = Pony.getManager().getPony(player);
if (!pony.race().isHuman()) { if (!pony.race().isHuman()) {
Setting<Boolean> fillyCam = MineLittlePony.getInstance().getConfig().fillycam; Setting<Boolean> fillyCam = MineLittlePony.getInstance().getConfig().fillycam;

View file

@ -13,7 +13,6 @@ import static com.minelittlepony.common.event.SkinFilterCallback.copy;
* *
*/ */
class LegacySkinConverter implements SkinFilterCallback { class LegacySkinConverter implements SkinFilterCallback {
@Override @Override
public void processImage(NativeImage image, boolean legacy) { public void processImage(NativeImage image, boolean legacy) {
if (legacy) { if (legacy) {

View file

@ -1,12 +1,10 @@
package com.minelittlepony.client; package com.minelittlepony.client;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.PonyManager;
import com.minelittlepony.api.pony.network.fabric.Channel; import com.minelittlepony.api.pony.network.fabric.Channel;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.pony.PonyManager;
import com.minelittlepony.client.pony.VariatedTextureSupplier;
import com.minelittlepony.client.render.PonyRenderDispatcher; import com.minelittlepony.client.render.PonyRenderDispatcher;
import com.minelittlepony.client.settings.ClientPonyConfig;
import com.minelittlepony.common.client.gui.VisibilityMode; import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.common.client.gui.sprite.TextureSprite; import com.minelittlepony.common.client.gui.sprite.TextureSprite;
@ -41,7 +39,7 @@ public class MineLittlePony implements ClientModInitializer {
public static final Logger logger = LogManager.getLogger("MineLittlePony"); public static final Logger logger = LogManager.getLogger("MineLittlePony");
private ClientPonyConfig config; private ClientPonyConfig config;
private PonyManager ponyManager; private PonyManagerImpl ponyManager;
private VariatedTextureSupplier variatedTextures; private VariatedTextureSupplier variatedTextures;
private final KeyBinding keyBinding = new KeyBinding("key.minelittlepony.settings", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F9, "key.categories.misc"); private final KeyBinding keyBinding = new KeyBinding("key.minelittlepony.settings", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F9, "key.categories.misc");
@ -68,7 +66,7 @@ public class MineLittlePony implements ClientModInitializer {
hasModMenu = FabricLoader.getInstance().isModLoaded("modmenu"); hasModMenu = FabricLoader.getInstance().isModLoaded("modmenu");
config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json")); config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json"));
ponyManager = new PonyManager(config); ponyManager = new PonyManagerImpl(config);
variatedTextures = new VariatedTextureSupplier(); variatedTextures = new VariatedTextureSupplier();
KeyBindingHelper.registerKeyBinding(keyBinding); KeyBindingHelper.registerKeyBinding(keyBinding);
@ -105,7 +103,7 @@ public class MineLittlePony implements ClientModInitializer {
} }
if ((mainMenu || inGame) && keyBinding.isPressed()) { if ((mainMenu || inGame) && keyBinding.isPressed()) {
client.setScreen(new GuiPonySettings(client.currentScreen)); client.setScreen(new PonySettingsscreen(client.currentScreen));
} }
} }
@ -119,7 +117,7 @@ public class MineLittlePony implements ClientModInitializer {
if (show) { if (show) {
int y = hasHdSkins ? 75 : 50; int y = hasHdSkins ? 75 : 50;
Button button = buttons.addButton(new Button(screen.width - 50, screen.height - y, 20, 20)) Button button = buttons.addButton(new Button(screen.width - 50, screen.height - y, 20, 20))
.onClick(sender -> MinecraftClient.getInstance().setScreen(new GuiPonySettings(screen))); .onClick(sender -> MinecraftClient.getInstance().setScreen(new PonySettingsscreen(screen)));
button.getStyle() button.getStyle()
.setIcon(new TextureSprite() .setIcon(new TextureSprite()
.setPosition(2, 2) .setPosition(2, 2)

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client; package com.minelittlepony.client;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.transform.PonyTransformation; import com.minelittlepony.client.transform.PonyTransformation;
@ -16,7 +16,7 @@ public class PonyBounds {
return PonyPosture.getMountPony(entity).map(ridingPony -> { return PonyPosture.getMountPony(entity).map(ridingPony -> {
LivingEntity vehicle = (LivingEntity)entity.getVehicle(); LivingEntity vehicle = (LivingEntity)entity.getVehicle();
Vec3d offset = PonyTransformation.forSize(ridingPony.metadata().size()).getRiderOffset(); Vec3d offset = PonyTransformation.forSize(ridingPony.size()).getRiderOffset();
float scale = ridingPony.metadata().size().scaleFactor(); float scale = ridingPony.metadata().size().scaleFactor();
return getAbsoluteRidingOffset(vehicle).add( return getAbsoluteRidingOffset(vehicle).add(
@ -40,8 +40,8 @@ public class PonyBounds {
); );
} }
public static Box getBoundingBox(IPony pony, LivingEntity entity) { public static Box getBoundingBox(Pony pony, LivingEntity entity) {
final float scale = pony.metadata().size().scaleFactor() + 0.1F; final float scale = pony.size().scaleFactor() + 0.1F;
final float width = entity.getWidth() * scale; final float width = entity.getWidth() * scale;
final float height = entity.getHeight() * scale; final float height = entity.getHeight() * scale;

View file

@ -0,0 +1,97 @@
package com.minelittlepony.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.resource.metadata.ResourceMetadataReader;
import net.minecraft.util.Identifier;
import com.google.gson.*;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.util.render.NativeUtil;
import java.io.IOException;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
class PonyDataLoader {
static final Supplier<Optional<PonyData>> NULL = loaded(PonyData.NULL);
private static final ResourceMetadataReader<PonyData> SERIALIZER = new ResourceMetadataReader<PonyData>() {
private static final Gson GSON = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
@Override
public String getKey() {
return "pony";
}
@Override
public PonyData fromJson(JsonObject json) {
return GSON.fromJson(json, PonyData.class);
}
};
/**
* Parses the given resource into a new IPonyData.
* This may either come from an attached json file or the image itself.
*/
public static Supplier<Optional<PonyData>> parse(@Nullable Identifier identifier, boolean noSkin) {
if (identifier == null) {
return NULL;
}
return MinecraftClient.getInstance().getResourceManager().getResource(identifier).flatMap(res -> {
try {
return res.getMetadata().decode(SERIALIZER);
} catch (IOException e) {
MineLittlePony.logger.warn("Unable to read {} metadata", identifier, e);
}
return Optional.empty();
}).map(PonyDataLoader::loaded).orElseGet(() -> {
return load(callback -> {
NativeUtil.parseImage(identifier, image -> {
callback.accept(new PonyData(
TriggerPixel.RACE.readValue(image),
TriggerPixel.TAIL.readValue(image),
TriggerPixel.TAIL_SHAPE.readValue(image),
TriggerPixel.GENDER.readValue(image),
TriggerPixel.SIZE.readValue(image),
TriggerPixel.GLOW.readColor(image),
TriggerPixel.WEARABLES.readFlags(image),
noSkin
));
}, e -> {
MineLittlePony.logger.fatal("Unable to read {} metadata", identifier, e);
callback.accept(PonyData.NULL);
});
});
});
}
private static <T> Supplier<Optional<T>> loaded(T t) {
final Optional<T> value = Optional.of(t);
return () -> value;
}
private static <T> Supplier<Optional<T>> load(Consumer<Consumer<T>> factory) {
return new Supplier<Optional<T>>() {
Optional<T> value = Optional.empty();
boolean loadRequested;
@Override
public Optional<T> get() {
synchronized (this) {
if (!loadRequested) {
loadRequested = true;
factory.accept(value -> {
this.value = Optional.ofNullable(value);
});
}
}
return value;
}
};
}
}

View file

@ -1,11 +1,9 @@
package com.minelittlepony.client.pony; package com.minelittlepony.client;
import com.google.common.cache.*; import com.google.common.cache.*;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.config.PonyLevel; import com.minelittlepony.api.config.PonyLevel;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.IPonyManager;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer; import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -26,39 +24,44 @@ import java.util.concurrent.TimeUnit;
/** /**
* The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin. * The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin.
*
*/ */
public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloadListener { class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadListener {
private static final Identifier ID = new Identifier("minelittlepony", "background_ponies"); private static final Identifier ID = new Identifier("minelittlepony", "background_ponies");
public static final Identifier BACKGROUND_PONIES = new Identifier("minelittlepony", "textures/entity/pony");
public static final Identifier BACKGROUND_ZOMPONIES = new Identifier("minelittlepony", "textures/entity/zompony");
private final PonyConfig config; private final PonyConfig config;
private final Cache<Identifier, IPony> defaultedPoniesCache = CacheBuilder.newBuilder() private final LoadingCache<Identifier, Pony> defaultedPoniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterAccess(30, TimeUnit.SECONDS)
.build(); .build(CacheLoader.from(resource -> {
return new Pony(resource, PonyDataLoader.parse(resource, true));
}));
private final LoadingCache<Identifier, IPony> poniesCache = CacheBuilder.newBuilder() private final LoadingCache<Identifier, Pony> poniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS) .expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(Pony::new)); .build(CacheLoader.from(resource -> {
return new Pony(resource, PonyDataLoader.parse(resource, false));
}));
public PonyManager(PonyConfig config) { public PonyManagerImpl(PonyConfig config) {
this.config = config; this.config = config;
Instance.instance = this; Instance.instance = this;
} }
@Override private Pony loadPony(Identifier resource, boolean defaulted) {
public IPony getPony(Identifier resource) {
try { try {
return poniesCache.get(resource); return (defaulted ? defaultedPoniesCache : poniesCache).get(resource);
} catch (ExecutionException e) { } catch (ExecutionException e) {
return new Pony(resource, PonyData.MEM_NULL, true); return new Pony(resource, PonyDataLoader.NULL);
} }
} }
@Override @Override
public Optional<IPony> getPony(@Nullable Entity entity) { public Pony getPony(Identifier resource) {
return loadPony(resource, false);
}
@Override
public Optional<Pony> getPony(@Nullable Entity entity) {
if (entity instanceof PlayerEntity player) { if (entity instanceof PlayerEntity player) {
return Optional.of(getPony(player)); return Optional.of(getPony(player));
} }
@ -71,12 +74,12 @@ public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloa
} }
@Override @Override
public IPony getPony(PlayerEntity player) { public Pony getPony(PlayerEntity player) {
Identifier skin = getSkin(player); Identifier skin = getSkin(player);
UUID uuid = player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId(); UUID uuid = player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId();
if (skin != null) { if (skin != null) {
if (player instanceof IPonyManager.ForcedPony) { if (player instanceof PonyManager.ForcedPony) {
return getPony(skin); return getPony(skin);
} }
@ -87,12 +90,12 @@ public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloa
return getBackgroundPony(uuid); return getBackgroundPony(uuid);
} }
return getAsDefaulted(getPony(DefaultSkinHelper.getTexture(uuid).texture())); return loadPony(DefaultSkinHelper.getTexture(uuid).texture(), true);
} }
@Override @Override
public IPony getPony(Identifier resource, UUID uuid) { public Pony getPony(Identifier resource, UUID uuid) {
IPony pony = getPony(resource); Pony pony = getPony(resource);
if (config.ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) { if (config.ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) {
return getBackgroundPony(uuid); return getBackgroundPony(uuid);
@ -102,16 +105,8 @@ public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloa
} }
@Override @Override
public IPony getBackgroundPony(UUID uuid) { public Pony getBackgroundPony(UUID uuid) {
return getAsDefaulted(getPony(MineLittlePony.getInstance().getVariatedTextures().get(BACKGROUND_PONIES, uuid).orElse(DefaultSkinHelper.getTexture(uuid).texture()))); return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getTexture(uuid).texture()), true);
}
private IPony getAsDefaulted(IPony pony) {
try {
return defaultedPoniesCache.get(pony.texture(), () -> new Pony(pony.texture(), ((Pony)pony).memoizedData(), true));
} catch (ExecutionException e) {
return pony;
}
} }
@Nullable @Nullable
@ -132,6 +127,7 @@ public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloa
defaultedPoniesCache.invalidate(resource); defaultedPoniesCache.invalidate(resource);
} }
@Override
public void clearCache() { public void clearCache() {
MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size()); MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size());
poniesCache.invalidateAll(); poniesCache.invalidateAll();
@ -148,5 +144,4 @@ public class PonyManager implements IPonyManager, SimpleSynchronousResourceReloa
public Identifier getFabricId() { public Identifier getFabricId() {
return ID; return ID;
} }
} }

View file

@ -6,7 +6,6 @@ import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.*; import net.minecraft.text.*;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.settings.ClientPonyConfig;
import com.minelittlepony.common.client.gui.GameGui; import com.minelittlepony.common.client.gui.GameGui;
import com.minelittlepony.common.client.gui.ScrollContainer; import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.Tooltip; import com.minelittlepony.common.client.gui.Tooltip;
@ -24,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
* In-Game options menu. * In-Game options menu.
* *
*/ */
public class GuiPonySettings extends GameGui { public class PonySettingsscreen extends GameGui {
private static final String OPTIONS_PREFIX = "minelp.options."; private static final String OPTIONS_PREFIX = "minelp.options.";
private static final String PONY_LEVEL = OPTIONS_PREFIX + "ponylevel"; private static final String PONY_LEVEL = OPTIONS_PREFIX + "ponylevel";
private static final String MOB_PREFIX = "minelp.mobs."; private static final String MOB_PREFIX = "minelp.mobs.";
@ -41,7 +40,7 @@ public class GuiPonySettings extends GameGui {
private final boolean hiddenOptions; private final boolean hiddenOptions;
public GuiPonySettings(@Nullable Screen parent) { public PonySettingsscreen(@Nullable Screen parent) {
super(Text.literal(OPTIONS_PREFIX + "title"), parent); super(Text.literal(OPTIONS_PREFIX + "title"), parent);
config = (ClientPonyConfig)MineLittlePony.getInstance().getConfig(); config = (ClientPonyConfig)MineLittlePony.getInstance().getConfig();

View file

@ -1,5 +1,5 @@
package com.minelittlepony.client; package com.minelittlepony.client;
public interface IPreviewModel { public interface PreviewModel {
boolean forceSeapony(); boolean forceSeapony();
} }

View file

@ -1,4 +1,4 @@
package com.minelittlepony.client.pony; package com.minelittlepony.client;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -6,13 +6,14 @@ import net.minecraft.entity.Entity;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
import java.util.*; import java.util.*;
public class VariatedTextureSupplier implements SimpleSynchronousResourceReloadListener { public class VariatedTextureSupplier implements SimpleSynchronousResourceReloadListener {
private static final Identifier ID = new Identifier("minelittlepony", "variated_textures"); private static final Identifier ID = new Identifier("minelittlepony", "variated_textures");
public static final Identifier BACKGROUND_PONIES_POOL = new Identifier("minelittlepony", "textures/entity/pony");
public static final Identifier BACKGROUND_ZOMPONIES_POOL = new Identifier("minelittlepony", "textures/entity/zompony");
private final Map<Identifier, SkinList> entries = new HashMap<>(); private final Map<Identifier, SkinList> entries = new HashMap<>();

View file

@ -1,9 +1,9 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.compat.hdskins;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.IPreviewModel; import com.minelittlepony.client.PreviewModel;
import com.minelittlepony.client.render.EquineRenderManager; import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.hdskins.client.gui.player.*; import com.minelittlepony.hdskins.client.gui.player.*;
import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins; import com.minelittlepony.hdskins.client.gui.player.skins.PlayerSkins;
@ -13,7 +13,7 @@ import java.util.UUID;
/** /**
* Dummy model used for the skin uploading screen. * Dummy model used for the skin uploading screen.
*/ */
class DummyPony extends DummyPlayer implements IPreviewModel, IPonyManager.ForcedPony, EquineRenderManager.RegistrationHandler { class DummyPony extends DummyPlayer implements PreviewModel, PonyManager.ForcedPony, EquineRenderManager.RegistrationHandler {
public DummyPony(ClientWorld world, PlayerSkins<?> textures) { public DummyPony(ClientWorld world, PlayerSkins<?> textures) {
super(world, textures); super(world, textures);
@ -21,7 +21,7 @@ class DummyPony extends DummyPlayer implements IPreviewModel, IPonyManager.Force
} }
@Override @Override
public boolean shouldUpdateRegistration(IPony pony) { public boolean shouldUpdateRegistration(Pony pony) {
return false; return false;
} }

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.compat.hdskins;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.GuiPonySettings; import com.minelittlepony.client.PonySettingsscreen;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
@ -29,22 +29,22 @@ class GuiSkinsMineLP extends GuiSkins {
chooser.addSkinChangedEventListener(type -> { chooser.addSkinChangedEventListener(type -> {
MineLittlePony.logger.debug("Invalidating old local skin, checking updated local skin"); MineLittlePony.logger.debug("Invalidating old local skin, checking updated local skin");
if (type == SkinType.SKIN) { if (type == SkinType.SKIN) {
IPony.getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId()); Pony.getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId());
} }
}); });
uploader.addSkinLoadedEventListener((type, location, profileTexture) -> { uploader.addSkinLoadedEventListener((type, location, profileTexture) -> {
MineLittlePony.logger.debug("Invalidating old remote skin, checking updated remote skin"); MineLittlePony.logger.debug("Invalidating old remote skin, checking updated remote skin");
if (type == SkinType.SKIN) { if (type == SkinType.SKIN) {
IPony.getManager().removePony(location); Pony.getManager().removePony(location);
} }
}); });
} }
@Override @Override
protected void initServerPreviewButtons(Bounds area) { protected void initServerPreviewButtons(Bounds area) {
if (!(parent instanceof GuiPonySettings)) { if (!(parent instanceof PonySettingsscreen)) {
addButton(new Button(area.right() - 20, area.bottom() + 5, 20, 20)) addButton(new Button(area.right() - 20, area.bottom() + 5, 20, 20))
.onClick(sender -> client.setScreen(new GuiPonySettings(this))) .onClick(sender -> client.setScreen(new PonySettingsscreen(this)))
.getStyle() .getStyle()
.setIcon(new TextureSprite() .setIcon(new TextureSprite()
.setPosition(2, 2) .setPosition(2, 2)

View file

@ -1,9 +1,10 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.compat.hdskins;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.TriggerPixelType;
import com.minelittlepony.common.client.gui.ITextContext; import com.minelittlepony.common.client.gui.ITextContext;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.hdskins.client.gui.Carousel; import com.minelittlepony.hdskins.client.gui.Carousel;
@ -23,7 +24,7 @@ class LegendOverlayWidget implements Carousel.Element, ITextContext {
@Override @Override
public void render(DummyPlayer player, DrawContext context, int mouseX, int mouseY) { public void render(DummyPlayer player, DrawContext context, int mouseX, int mouseY) {
IPonyData data = IPony.getManager().getPony(player).metadata(); PonyData data = Pony.getManager().getPony(player).metadata();
int[] index = new int[1]; int[] index = new int[1];
data.attributes().forEach((key, value) -> { data.attributes().forEach((key, value) -> {
context.getMatrices().push(); context.getMatrices().push();

View file

@ -1,10 +1,8 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.compat.hdskins;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.common.client.gui.ScrollContainer; import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.common.event.ClientReadyCallback; import com.minelittlepony.common.event.ClientReadyCallback;
@ -28,7 +26,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.pony.PonyManager; import com.minelittlepony.client.*;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer; import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
/** /**
@ -53,8 +51,7 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
ClientReadyCallback.EVENT.register(client -> { ClientReadyCallback.EVENT.register(client -> {
// Clear ponies when skins are cleared // Clear ponies when skins are cleared
PonyManager ponyManager = (PonyManager) MineLittlePony.getInstance().getManager(); SkinCacheClearCallback.EVENT.register(MineLittlePony.getInstance().getManager()::clearCache);
SkinCacheClearCallback.EVENT.register(ponyManager::clearCache);
// Ponify the skins GUI. // Ponify the skins GUI.
GuiSkins.setSkinsGui(GuiSkinsMineLP::new); GuiSkins.setSkinsGui(GuiSkinsMineLP::new);
@ -102,7 +99,7 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
PlayerSkin main = dummy.getTextures().get(SkinType.SKIN); PlayerSkin main = dummy.getTextures().get(SkinType.SKIN);
Wearable wearable = Wearable.REGISTRY.getOrDefault(type.getId(), Wearable.NONE); Wearable wearable = Wearable.REGISTRY.getOrDefault(type.getId(), Wearable.NONE);
IPonyData metadata = IPony.getManager().getPony(main.getId()).metadata(); PonyData metadata = Pony.getManager().getPony(main.getId()).metadata();
if (wearable != Wearable.NONE && metadata.isWearing(wearable)) { if (wearable != Wearable.NONE && metadata.isWearing(wearable)) {
if (wearable.isSaddlebags() && metadata.race().supportsLegacySaddlebags()) { if (wearable.isSaddlebags() && metadata.race().supportsLegacySaddlebags()) {

View file

@ -1,4 +1,4 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.compat.hdskins;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;

View file

@ -1,13 +1,13 @@
package com.minelittlepony.client.modmenu; package com.minelittlepony.client.compat.modmenu;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
import com.minelittlepony.client.GuiPonySettings; import com.minelittlepony.client.PonySettingsscreen;
public class MineLPModMenuFactory implements ModMenuApi { public class MineLPModMenuFactory implements ModMenuApi {
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return GuiPonySettings::new; return PonySettingsscreen::new;
} }
} }

View file

@ -5,7 +5,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
@ -18,10 +18,10 @@ abstract class MixinCamera {
private void redirectCameraDistance(double initial, CallbackInfoReturnable<Double> info) { private void redirectCameraDistance(double initial, CallbackInfoReturnable<Double> info) {
double value = info.getReturnValueD(); double value = info.getReturnValueD();
IPony pony = IPony.getManager().getPony(MinecraftClient.getInstance().player); Pony pony = Pony.getManager().getPony(MinecraftClient.getInstance().player);
if (!pony.race().isHuman()) { if (!pony.race().isHuman()) {
value *= pony.metadata().size().eyeDistanceFactor(); value *= pony.size().eyeDistanceFactor();
} }
info.setReturnValue(value); info.setReturnValue(value);

View file

@ -1,7 +1,6 @@
package com.minelittlepony.client.mixin; package com.minelittlepony.client.mixin;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.pony.Pony;
import com.minelittlepony.client.render.EquineRenderManager; import com.minelittlepony.client.render.EquineRenderManager;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
@ -22,7 +21,7 @@ abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implem
public MixinClientPlayerEntity() { super(null, null); } public MixinClientPlayerEntity() { super(null, null); }
@Nullable @Nullable
private IPony pony; private Pony pony;
@Inject(method = "startRiding(Lnet/minecraft/entity/Entity;Z)Z", at = @At("RETURN")) @Inject(method = "startRiding(Lnet/minecraft/entity/Entity;Z)Z", at = @At("RETURN"))
private void onStartRiding(Entity entity, boolean bl, CallbackInfoReturnable<Boolean> info) { private void onStartRiding(Entity entity, boolean bl, CallbackInfoReturnable<Boolean> info) {
@ -35,9 +34,9 @@ abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implem
} }
@Override @Override
public boolean shouldUpdateRegistration(IPony pony) { public boolean shouldUpdateRegistration(Pony pony) {
if (this.pony != pony && (this.pony == null || this.pony.metadata().compareTo(pony.metadata()) != 0)) { if (this.pony != pony && (this.pony == null || this.pony.metadata().compareTo(pony.metadata()) != 0)) {
this.pony = Pony.snapshot(pony); this.pony = pony.immutableCopy();
return true; return true;
} }
return false; return false;
@ -47,10 +46,10 @@ abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implem
public float getActiveEyeHeight(EntityPose pose, EntityDimensions dimensions) { public float getActiveEyeHeight(EntityPose pose, EntityDimensions dimensions) {
float value = super.getActiveEyeHeight(pose, dimensions); float value = super.getActiveEyeHeight(pose, dimensions);
IPony pony = IPony.getManager().getPony(this); Pony pony = Pony.getManager().getPony(this);
if (!pony.race().isHuman()) { if (!pony.race().isHuman()) {
float factor = pony.metadata().size().eyeHeightFactor(); float factor = pony.size().eyeHeightFactor();
if (factor != 1) { if (factor != 1) {
value *= factor; value *= factor;

View file

@ -102,7 +102,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
*/ */
@Override @Override
public final void setAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) { public final void setAngles(T entity, float limbAngle, float limbSpeed, float animationProgress, float headYaw, float headPitch) {
attributes.checkRainboom(entity, canFly(), animationProgress); attributes.checkRainboom(entity, this, animationProgress);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, ModelAttributes.Mode.OTHER); PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, ModelAttributes.Mode.OTHER);
super.setAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch); super.setAngles(entity, limbAngle, limbSpeed, animationProgress, headYaw, headPitch);
@ -388,7 +388,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
if (attributes.shouldLiftArm(pose, complement, sigma)) { if (attributes.shouldLiftArm(pose, complement, sigma)) {
float swag = 1; float swag = 1;
if (!isFlying() && both) { if (!getAttributes().isFlying && both) {
swag -= (float)Math.pow(limbSpeed, 2); swag -= (float)Math.pow(limbSpeed, 2);
} }

View file

@ -8,10 +8,10 @@ import net.minecraft.util.Hand;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback; import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes; import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.mson.api.model.biped.MsonPlayer; import com.minelittlepony.mson.api.model.biped.MsonPlayer;
@ -23,7 +23,7 @@ import com.minelittlepony.mson.api.model.biped.MsonPlayer;
* *
* Modders can extend this class to make their own pony models if they wish. * Modders can extend this class to make their own pony models if they wish.
*/ */
public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer<T> implements IPonyModel<T>, ModelWithHat, ModelWithArms { public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer<T> implements PonyModel<T> {
/** /**
* The model attributes. * The model attributes.
@ -47,7 +47,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
} }
@Override @Override
public void updateLivingState(T entity, IPony pony, ModelAttributes.Mode mode) { public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
child = entity.isBaby(); child = entity.isBaby();
attributes.updateLivingState(entity, pony, mode); attributes.updateLivingState(entity, pony, mode);
PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, mode); PonyModelPrepareCallback.EVENT.invoker().onPonyModelPrepared(entity, this, mode);
@ -60,6 +60,18 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
copyStateTo(other); copyStateTo(other);
} }
/**
* Copies this model's attributes into the passed model.
*/
@Override
public void copyStateTo(EntityModel<T> model) {
super.copyStateTo(model);
if (model instanceof ClientPonyModel) {
((ClientPonyModel<T>)model).attributes = attributes;
}
}
@Override @Override
public final ModelAttributes getAttributes() { public final ModelAttributes getAttributes() {
return attributes; return attributes;
@ -67,11 +79,11 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
@Override @Override
public Size getSize() { public Size getSize() {
return child ? Sizes.FOAL : getMetadata().size(); return child ? Sizes.FOAL : PonyModel.super.getSize();
} }
@Override @Override
public void setMetadata(IPonyData meta) { public void setMetadata(PonyData meta) {
attributes.metadata = meta; attributes.metadata = meta;
} }
@ -89,18 +101,6 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
return side == Arm.RIGHT ? rightArmPose : leftArmPose; return side == Arm.RIGHT ? rightArmPose : leftArmPose;
} }
/**
* Copies this model's attributes into the passed model.
*/
@Override
public void copyStateTo(EntityModel<T> model) {
super.copyStateTo(model);
if (model instanceof ClientPonyModel) {
((ClientPonyModel<T>)model).attributes = attributes;
}
}
@Override @Override
public void setHatVisible(boolean visible) { public void setHatVisible(boolean visible) {

View file

@ -7,16 +7,14 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.IUnicorn; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.api.pony.meta.Size; import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter; import com.minelittlepony.mson.api.model.BoxBuilder.RenderLayerSetter;
public interface IPonyMixinModel<T extends LivingEntity, M extends IPonyModel<T>> extends IPonyModel<T>, ModelWithArms { public interface IPonyMixinModel<T extends LivingEntity, M extends PonyModel<T>> extends PonyModel<T> {
M mixin(); M mixin();
@ -29,7 +27,7 @@ public interface IPonyMixinModel<T extends LivingEntity, M extends IPonyModel<T>
} }
@Override @Override
default void updateLivingState(T entity, IPony pony, ModelAttributes.Mode mode) { default void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
mixin().updateLivingState(entity, pony, mode); mixin().updateLivingState(entity, pony, mode);
} }
@ -54,7 +52,7 @@ public interface IPonyMixinModel<T extends LivingEntity, M extends IPonyModel<T>
} }
@Override @Override
default void setMetadata(IPonyData meta) { default void setMetadata(PonyData meta) {
mixin().setMetadata(meta); mixin().setMetadata(meta);
} }
@ -90,7 +88,12 @@ public interface IPonyMixinModel<T extends LivingEntity, M extends IPonyModel<T>
return mixin().getBodyPart(part); return mixin().getBodyPart(part);
} }
interface Caster<T extends LivingEntity, M extends IPonyModel<T> & IUnicorn, ArmModel> extends IPonyMixinModel<T, M>, IUnicorn { @Override
default void setHatVisible(boolean hatVisible) {
mixin().setHatVisible(hatVisible);
}
interface Caster<T extends LivingEntity, M extends PonyModel<T> & HornedPonyModel<T>, ArmModel> extends IPonyMixinModel<T, M>, HornedPonyModel<T> {
@Override @Override
default boolean isCasting() { default boolean isCasting() {
return mixin().isCasting(); return mixin().isCasting();

View file

@ -1,22 +0,0 @@
package com.minelittlepony.client.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.entity.LivingEntity;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.ICapitated;
import com.minelittlepony.api.model.IModel;
import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.mson.api.MsonModel;
public interface IPonyModel<T extends LivingEntity> extends IModel, ICapitated<ModelPart>, ModelWithArms, MsonModel {
void copyAttributes(BipedEntityModel<T> other);
void updateLivingState(T entity, IPony pony, ModelAttributes.Mode mode);
ModelPart getBodyPart(BodyPart part);
}

View file

@ -8,8 +8,9 @@ import net.minecraft.entity.mob.VexEntity;
import net.minecraft.entity.passive.*; import net.minecraft.entity.passive.*;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IGear; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.*;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
@ -29,7 +30,7 @@ import java.util.stream.Stream;
public final class ModelType { 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 IGear>> GEAR_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); public static final ModelKey<DJPon3EarsModel> DJ_PON_3 = register("dj_pon_three", DJPon3EarsModel::new);
@ -55,14 +56,14 @@ public final class ModelType {
public static final ModelKey<PonyArmourModel<?>> INNER_PONY_ARMOR = register("armor/inner_pony_armor", PonyArmourModel::new); 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 ModelKey<PonyArmourModel<?>> OUTER_PONY_ARMOR = register("armor/outer_pony_armor", PonyArmourModel::new);
public static final GearModelKey<Stetson> STETSON = registerGear("stetson", Wearable.STETSON, Stetson::new); public static final GearModelKey<AbstractGearModel> STETSON = registerGear("stetson", Wearable.STETSON, t -> new WearableGear(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_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_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<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<Crown> CROWN = registerGear("crown", Wearable.CROWN, Crown::new);
public static final GearModelKey<Muffin> MUFFIN = registerGear("muffin", Wearable.MUFFIN, Muffin::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<WitchHat> WITCH_HAT = registerGear("witch_hat", Wearable.HAT, WitchHat::new); 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<ChristmasHat> ANTLERS = registerGear("antlers", Wearable.ANTLERS, ChristmasHat::new); 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, 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, UnicornModel<?>> UNICORN = registerPlayer("unicorn", Race.UNICORN, UnicornModel::new);
@ -77,27 +78,27 @@ public final class ModelType {
public static final PlayerModelKey<LivingEntity, ChangelingModel<?>> CHANGEDLING = registerPlayer("reformed_changeling", Race.CHANGEDLING, 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<LivingEntity, EarthPonyModel<?>> ZEBRA = registerPlayer("zebra", Race.ZEBRA, EarthPonyModel::new);
static <E extends LivingEntity, T extends Model & MsonModel & IModel> PlayerModelKey<E, T> registerPlayer(String name, Race race, static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> registerPlayer(String name, Race race,
BiFunction<ModelPart, Boolean, T> constructor) { BiFunction<ModelPart, Boolean, T> constructor) {
return registerPlayer(name, race, constructor, PonyArmourModel::new); return registerPlayer(name, race, constructor, PonyArmourModel::new);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <E extends LivingEntity, T extends Model & MsonModel & IModel> PlayerModelKey<E, T> registerPlayer(String name, Race race, static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> registerPlayer(String name, Race race,
BiFunction<ModelPart, Boolean, T> constructor, BiFunction<ModelPart, Boolean, T> constructor,
MsonModel.Factory<PonyArmourModel<E>> armorFactory) { MsonModel.Factory<PonyArmourModel<E>> armorFactory) {
return (PlayerModelKey<E, T>)PLAYER_MODELS.computeIfAbsent(race, r -> new PlayerModelKey<>(name, constructor, armorFactory)); return (PlayerModelKey<E, T>)PLAYER_MODELS.computeIfAbsent(race, r -> new PlayerModelKey<>(name, constructor, armorFactory));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends AbstractGear> GearModelKey<T> registerGear(String name, Wearable wearable, MsonModel.Factory<T> constructor) { static <T extends AbstractGearModel> GearModelKey<T> registerGear(String name, Wearable wearable, MsonModel.Factory<T> constructor) {
return (GearModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> { return (GearModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> {
return new GearModelKey<T>(Mson.getInstance().registerModel(new Identifier("minelittlepony", "gear/" + name), constructor), constructor); return new GearModelKey<T>(Mson.getInstance().registerModel(new Identifier("minelittlepony", "gear/" + name), constructor), constructor);
}); });
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends AbstractGear> GearModelKey<T> registerGear(GearModelKey<T> key, Wearable wearable, MsonModel.Factory<T> constructor) { static <T extends AbstractGearModel> GearModelKey<T> registerGear(GearModelKey<T> key, Wearable wearable, MsonModel.Factory<T> constructor) {
return (GearModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> new GearModelKey<T>(key.key, constructor)); return (GearModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> new GearModelKey<T>(key.key, constructor));
} }
@ -107,17 +108,17 @@ public final class ModelType {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
public static <E extends LivingEntity, T extends Model & MsonModel & IModel> PlayerModelKey<E, T> getPlayerModel(Race race) { public static <E extends LivingEntity, T extends Model & MsonModel & PonyModel<?>> PlayerModelKey<E, T> getPlayerModel(Race race) {
return (PlayerModelKey<E, T>)PLAYER_MODELS.get(race); return (PlayerModelKey<E, T>)PLAYER_MODELS.get(race);
} }
public static Stream<Map.Entry<Wearable, GearModelKey<? extends IGear>>> getWearables() { public static Stream<Map.Entry<Wearable, GearModelKey<? extends Gear>>> getWearables() {
return GEAR_MODELS.entrySet().stream(); return GEAR_MODELS.entrySet().stream();
} }
public static void bootstrap() { } public static void bootstrap() { }
public record GearModelKey<T extends IGear>(ModelKey<T> key, MsonModel.Factory<T> constructor) { public record GearModelKey<T extends Gear>(ModelKey<T> key, MsonModel.Factory<T> constructor) {
public T createModel() { public T createModel() {
return key.createModel(constructor); return key.createModel(constructor);
} }

View file

@ -6,10 +6,10 @@ import net.minecraft.item.ItemStack;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.IModelWrapper; import com.minelittlepony.api.model.IModelWrapper;
import com.minelittlepony.api.model.armour.*; import com.minelittlepony.api.model.armour.*;
import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.*; import com.minelittlepony.mson.api.*;
@ -19,7 +19,7 @@ import java.util.function.Consumer;
/** /**
* Container class for the various models and their associated piece of armour. * Container class for the various models and their associated piece of armour.
*/ */
public class ModelWrapper<T extends LivingEntity, M extends IModel> implements IModelWrapper { public class ModelWrapper<T extends LivingEntity, M extends PonyModel<?>> implements IModelWrapper {
@Nullable @Nullable
private final MsonModel.Factory<PonyArmourModel<T>> armorFactory; private final MsonModel.Factory<PonyArmourModel<T>> armorFactory;
private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>(); private final Map<ModelKey<PonyArmourModel<?>>, PonyArmourModel<T>> armor = new HashMap<>();
@ -51,7 +51,7 @@ public class ModelWrapper<T extends LivingEntity, M extends IModel> implements I
} }
@Override @Override
public ModelWrapper<T, M> applyMetadata(IPonyData meta) { public ModelWrapper<T, M> applyMetadata(PonyData meta) {
body.setMetadata(meta); body.setMetadata(meta);
armor.values().forEach(a -> a.setMetadata(meta)); armor.values().forEach(a -> a.setMetadata(meta));
return this; return this;

View file

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

View file

@ -5,9 +5,9 @@ import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.armour.*; import com.minelittlepony.api.model.armour.*;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.IPonyModel;
public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T> implements IArmourModel<T> { public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T> implements IArmourModel<T> {
@ -18,7 +18,7 @@ public class PonyArmourModel<T extends LivingEntity> extends AbstractPonyModel<T
@Override @Override
public boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch, public boolean poseModel(T entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch,
EquipmentSlot slot, ArmourLayer layer, EquipmentSlot slot, ArmourLayer layer,
IPonyModel<T> mainModel) { PonyModel<T> mainModel) {
if (!setVisibilities(slot, layer)) { if (!setVisibilities(slot, layer)) {
return false; return false;

View file

@ -6,6 +6,8 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.EndermanEntity; import net.minecraft.entity.mob.EndermanEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.meta.Race;
public class EnderStallionModel extends SkeleponyModel<EndermanEntity> { public class EnderStallionModel extends SkeleponyModel<EndermanEntity> {
public boolean isCarrying; public boolean isCarrying;
@ -54,8 +56,8 @@ public class EnderStallionModel extends SkeleponyModel<EndermanEntity> {
} }
@Override @Override
public boolean canFly() { public Race getRace() {
return isAlicorn; return isAlicorn ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
} }
@Override @Override

View file

@ -7,7 +7,7 @@ import net.minecraft.entity.mob.PiglinActivity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
public class PiglinPonyModel extends ZomponyModel<HostileEntity> { public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
@ -23,7 +23,7 @@ public class PiglinPonyModel extends ZomponyModel<HostileEntity> {
} }
@Override @Override
public void updateLivingState(HostileEntity entity, IPony pony, ModelAttributes.Mode mode) { public void updateLivingState(HostileEntity entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode); super.updateLivingState(entity, pony, mode);
leftArmPose = ArmPose.EMPTY; leftArmPose = ArmPose.EMPTY;
rightArmPose = entity.getMainHandStack().isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM; rightArmPose = entity.getMainHandStack().isEmpty() ? ArmPose.EMPTY : ArmPose.ITEM;

View file

@ -8,10 +8,10 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import com.minelittlepony.client.model.IMobModel; import com.minelittlepony.api.model.MobPosingHelper;
import com.minelittlepony.client.model.entity.race.AlicornModel; import com.minelittlepony.client.model.entity.race.AlicornModel;
public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> implements IMobModel { public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> {
public boolean isUnicorn; public boolean isUnicorn;
@ -68,7 +68,7 @@ public class SkeleponyModel<T extends HostileEntity> extends AlicornModel<T> imp
} }
protected void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) { protected void rotateArmHolding(ModelPart arm, float direction, float swingProgress, float ticks) {
IMobModel.rotateArmHolding(arm, direction, swingProgress, ticks); MobPosingHelper.rotateArmHolding(arm, direction, swingProgress, ticks);
} }
@Override @Override

View file

@ -8,7 +8,7 @@ import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.*; import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.model.entity.race.EarthPonyModel; import com.minelittlepony.client.model.entity.race.EarthPonyModel;
@ -19,7 +19,7 @@ public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
} }
@Override @Override
public void updateLivingState(WitchEntity entity, IPony pony, ModelAttributes.Mode mode) { public void updateLivingState(WitchEntity entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode); super.updateLivingState(entity, pony, mode);
if (entity.hasCustomName() && "Filly".equals(entity.getCustomName().getString())) { if (entity.hasCustomName() && "Filly".equals(entity.getCustomName().getString())) {
@ -71,9 +71,6 @@ public class WitchPonyModel extends EarthPonyModel<WitchEntity> {
@Override @Override
public boolean isWearing(Wearable wearable) { public boolean isWearing(Wearable wearable) {
if (wearable == Wearable.HAT) { return wearable == Wearable.HAT || super.isWearing(wearable);
return true;
}
return super.isWearing(wearable);
} }
} }

View file

@ -1,11 +1,12 @@
package com.minelittlepony.client.model.entity; package com.minelittlepony.client.model.entity;
import com.minelittlepony.client.model.IMobModel; import com.minelittlepony.api.model.MobPosingHelper;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.entity.race.AlicornModel; import com.minelittlepony.client.model.entity.race.AlicornModel;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.mob.HostileEntity;
public class ZomponyModel<Zombie extends HostileEntity> extends AlicornModel<Zombie> implements IMobModel { public class ZomponyModel<Zombie extends HostileEntity> extends AlicornModel<Zombie> {
private boolean isPegasus; private boolean isPegasus;
@ -23,13 +24,13 @@ public class ZomponyModel<Zombie extends HostileEntity> extends AlicornModel<Zom
protected void rotateLegs(float move, float swing, float ticks, Zombie entity) { protected void rotateLegs(float move, float swing, float ticks, Zombie entity) {
super.rotateLegs(move, swing, ticks, entity); super.rotateLegs(move, swing, ticks, entity);
if (isZombified(entity)) { if (isZombified(entity)) {
IMobModel.rotateUndeadArms(this, move, ticks); MobPosingHelper.rotateUndeadArms(this, move, ticks);
} }
} }
@Override @Override
public boolean canFly() { public Race getRace() {
return isPegasus; return isPegasus ? (super.getRace().hasHorn() ? Race.ALICORN : Race.PEGASUS) : super.getRace();
} }
protected boolean isZombified(Zombie entity) { protected boolean isZombified(Zombie entity) {

View file

@ -1,14 +1,14 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.IPart;
import com.minelittlepony.api.model.IPegasus; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public class AlicornModel<T extends LivingEntity> extends UnicornModel<T> implements IPegasus { public class AlicornModel<T extends LivingEntity> extends UnicornModel<T> implements WingedPonyModel<T> {
private PonyWings<AlicornModel<T>> wings; private PonyWings<AlicornModel<T>> wings;
@ -20,7 +20,7 @@ public class AlicornModel<T extends LivingEntity> extends UnicornModel<T> implem
public void init(ModelView context) { public void init(ModelView context) {
super.init(context); super.init(context);
wings = addPart(context.findByName("wings")); wings = addPart(context.findByName("wings"));
bodyRenderList.add(forPart(this::getWings).checked(this::canFly)); bodyRenderList.add(forPart(this::getWings).checked(() -> getRace().hasWings()));
} }
@Override @Override

View file

@ -12,12 +12,12 @@ public class ChangelingModel<T extends LivingEntity> extends AlicornModel<T> {
@Override @Override
public boolean wingsAreOpen() { public boolean wingsAreOpen() {
return (isFlying() || attributes.isCrouching) && !getAttributes().isGliding; return (getAttributes().isFlying || getAttributes().isCrouching) && !getAttributes().isGliding;
} }
@Override @Override
public float getWingRotationFactor(float ticks) { public float getWingRotationFactor(float ticks) {
if (isFlying()) { if (getAttributes().isFlying) {
return MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE; return MathHelper.sin(ticks * 3) + WINGS_HALF_SPREAD_ANGLE;
} }
return WINGS_RAISED_ANGLE; return WINGS_RAISED_ANGLE;

View file

@ -1,14 +1,14 @@
package com.minelittlepony.client.model.entity.race; package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.model.IPart; import com.minelittlepony.api.model.IPart;
import com.minelittlepony.api.model.IPegasus; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.client.model.part.PonyWings; import com.minelittlepony.client.model.part.PonyWings;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public class PegasusModel<T extends LivingEntity> extends EarthPonyModel<T> implements IPegasus { public class PegasusModel<T extends LivingEntity> extends EarthPonyModel<T> implements WingedPonyModel<T> {
private PonyWings<PegasusModel<T>> wings; private PonyWings<PegasusModel<T>> wings;

View file

@ -3,7 +3,7 @@ package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.client.model.armour.PonyArmourModel; import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.mson.api.ModelView; import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.api.model.*; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
@ -45,7 +45,7 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
} }
@Override @Override
public void updateLivingState(T entity, IPony pony, ModelAttributes.Mode mode) { public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode); super.updateLivingState(entity, pony, mode);
// Seaponies can't sneak, silly // Seaponies can't sneak, silly
@ -123,7 +123,7 @@ public class SeaponyModel<T extends LivingEntity> extends UnicornModel<T> {
} }
@Override @Override
public void updateLivingState(T entity, IPony pony, ModelAttributes.Mode mode) { public void updateLivingState(T entity, Pony pony, ModelAttributes.Mode mode) {
super.updateLivingState(entity, pony, mode); super.updateLivingState(entity, pony, mode);
// Seaponies can't sneak, silly // Seaponies can't sneak, silly

View file

@ -16,7 +16,7 @@ import net.minecraft.util.*;
/** /**
* Used for both unicorns and alicorns since there's no logical way to keep them distinct and not duplicate stuff. * Used for both unicorns and alicorns since there's no logical way to keep them distinct and not duplicate stuff.
*/ */
public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> implements IUnicorn { public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> implements HornedPonyModel<T> {
protected final ModelPart unicornArmRight; protected final ModelPart unicornArmRight;
protected final ModelPart unicornArmLeft; protected final ModelPart unicornArmLeft;
@ -33,10 +33,10 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
public void init(ModelView context) { public void init(ModelView context) {
super.init(context); super.init(context);
horn = addPart(context.findByName("horn")); horn = addPart(context.findByName("horn"));
headRenderList.add(RenderList.of().add(head::rotate).add(forPart(horn)).checked(this::hasHorn)); headRenderList.add(RenderList.of().add(head::rotate).add(forPart(horn)).checked(() -> getRace().hasHorn()));
this.mainRenderList.add(withStage(BodyPart.HEAD, RenderList.of().add(head::rotate).add((stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> { this.mainRenderList.add(withStage(BodyPart.HEAD, RenderList.of().add(head::rotate).add((stack, vertices, overlayUv, lightUv, red, green, blue, alpha) -> {
horn.renderMagic(stack, vertices, getMagicColor()); horn.renderMagic(stack, vertices, getAttributes().metadata.glowColor());
})).checked(() -> hasHorn() && hasMagic() && isCasting())); })).checked(() -> hasMagic() && isCasting()));
} }
@Override @Override

View file

@ -7,19 +7,19 @@ import net.minecraft.entity.mob.ZombifiedPiglinEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.IStackable; import com.minelittlepony.api.model.gear.WearableGear;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class Crown extends AbstractWearableGear implements IStackable { public class Crown extends WearableGear {
public Crown(ModelPart tree) { public Crown(ModelPart tree) {
super(Wearable.CROWN, BodyPart.HEAD); super(Wearable.CROWN, BodyPart.HEAD, 0.1F);
addPart(tree.getChild("crown")); addPart(tree.getChild("crown"));
} }
@Override @Override
public boolean canRender(IModel model, Entity entity) { public boolean canRender(PonyModel<?> model, Entity entity) {
return super.canRender(model, entity) return super.canRender(model, entity)
|| (( || ((
entity instanceof AbstractPiglinEntity entity instanceof AbstractPiglinEntity
@ -28,9 +28,4 @@ public class Crown extends AbstractWearableGear implements IStackable {
) && entity.hasCustomName() && entity.getCustomName().getString().equalsIgnoreCase("technoblade") ) && entity.hasCustomName() && entity.getCustomName().getString().equalsIgnoreCase("technoblade")
); );
} }
@Override
public float getStackingHeight() {
return 0.1F;
}
} }

View file

@ -7,15 +7,15 @@ import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.WearableGear;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
import java.util.Calendar; import java.util.Calendar;
import java.util.UUID; import java.util.UUID;
public class ChristmasHat extends AbstractWearableGear { public class DeerAntlers extends WearableGear {
private static boolean dayChecked = false; private static boolean dayChecked = false;
private static boolean dayResult = false; private static boolean dayResult = false;
private static boolean isChristmasDay() { private static boolean isChristmasDay() {
@ -35,19 +35,19 @@ public class ChristmasHat extends AbstractWearableGear {
private int tint; private int tint;
public ChristmasHat(ModelPart tree) { public DeerAntlers(ModelPart tree) {
super(Wearable.ANTLERS, BodyPart.HEAD); super(Wearable.ANTLERS, BodyPart.HEAD, 0);
left = tree.getChild("left"); left = tree.getChild("left");
right = tree.getChild("right"); right = tree.getChild("right");
} }
@Override @Override
public boolean canRender(IModel model, Entity entity) { public boolean canRender(PonyModel<?> model, Entity entity) {
return isChristmasDay() || super.canRender(model, entity); return isChristmasDay() || super.canRender(model, entity);
} }
@Override @Override
public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { public void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
float pi = MathHelper.PI * (float) Math.pow(swing, 16); float pi = MathHelper.PI * (float) Math.pow(swing, 16);
float mve = move * 0.6662f; float mve = move * 0.6662f;
@ -57,7 +57,7 @@ public class ChristmasHat extends AbstractWearableGear {
bodySwing += 0.1F; bodySwing += 0.1F;
tint = model.getMetadata().glowColor(); tint = model.getAttributes().metadata.glowColor();
left.roll = bodySwing; left.roll = bodySwing;
right.roll = -bodySwing; right.roll = -bodySwing;
} }

View file

@ -1,19 +0,0 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable;
public class Muffin extends AbstractWearableGear implements IStackable {
public Muffin(ModelPart tree) {
super(Wearable.MUFFIN, BodyPart.HEAD);
addPart(tree.getChild("crown"));
}
@Override
public float getStackingHeight() {
return 0.45F;
}
}

View file

@ -1,8 +1,9 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.client.model.gear;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.IPegasus; import com.minelittlepony.api.model.WingedPonyModel;
import com.minelittlepony.api.model.gear.WearableGear;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -15,7 +16,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class SaddleBags extends AbstractWearableGear { public class SaddleBags extends WearableGear {
public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png"); public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png");
@ -29,19 +30,15 @@ public class SaddleBags extends AbstractWearableGear {
private float dropAmount = 0; private float dropAmount = 0;
public SaddleBags(ModelPart tree, Wearable wearable) { public SaddleBags(ModelPart tree, Wearable wearable) {
super(wearable, BodyPart.BODY); super(wearable, BodyPart.BODY, 0);
strap = tree.getChild("strap"); strap = tree.getChild("strap");
leftBag = tree.getChild("left_bag"); leftBag = tree.getChild("left_bag");
rightBag = tree.getChild("right_bag"); rightBag = tree.getChild("right_bag");
} }
@Override @Override
public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { public void pose(PonyModel<?> model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
hangLow = false; hangLow = model instanceof WingedPonyModel pegasus && pegasus.wingsAreOpen();
if (model instanceof IPegasus) {
hangLow = model.canFly() && ((IPegasus)model).wingsAreOpen();
}
float pi = MathHelper.PI * (float) Math.pow(swing, 16); float pi = MathHelper.PI * (float) Math.pow(swing, 16);
@ -53,8 +50,8 @@ public class SaddleBags extends AbstractWearableGear {
leftBag.pitch = bodySwing; leftBag.pitch = bodySwing;
rightBag.pitch = bodySwing; rightBag.pitch = bodySwing;
if (model instanceof IPegasus && model.isFlying()) { if (model instanceof WingedPonyModel pegasus && pegasus.getAttributes().isFlying) {
bodySwing = ((IPegasus)model).getWingRotationFactor(ticks) - MathUtil.Angles._270_DEG; bodySwing = pegasus.getWingRotationFactor(ticks) - MathUtil.Angles._270_DEG;
bodySwing /= 10; bodySwing /= 10;
} }
@ -66,7 +63,7 @@ public class SaddleBags extends AbstractWearableGear {
strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH; strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH;
dropAmount = hangLow ? 0.15F : 0; dropAmount = hangLow ? 0.15F : 0;
dropAmount = model.getMetadata().getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3); dropAmount = model.getAttributes().metadata.getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3);
} }
@Override @Override

View file

@ -1,19 +0,0 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable;
public class Stetson extends AbstractWearableGear implements IStackable {
public Stetson(ModelPart tree) {
super(Wearable.STETSON, BodyPart.HEAD);
addPart(tree.getChild("rim"));
}
@Override
public float getStackingHeight() {
return 0.15F;
}
}

View file

@ -1,19 +0,0 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable;
public class WitchHat extends AbstractWearableGear implements IStackable {
public WitchHat(ModelPart tree) {
super(Wearable.HAT, BodyPart.HEAD);
addPart(tree.getChild("hat"));
}
@Override
public float getStackingHeight() {
return 0.7F;
}
}

View file

@ -12,7 +12,7 @@ import com.minelittlepony.mson.api.ModelView;
import com.minelittlepony.mson.api.MsonModel; import com.minelittlepony.mson.api.MsonModel;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
public class PonyWings<T extends Model & IPegasus> implements IPart, MsonModel { public class PonyWings<T extends Model & WingedPonyModel<?>> implements IPart, MsonModel {
protected T pegasus; protected T pegasus;
@ -49,7 +49,11 @@ public class PonyWings<T extends Model & IPegasus> implements IPart, MsonModel {
} }
public Wing getRight() { public Wing getRight() {
return (pegasus.isEmbedded(Wearable.SADDLE_BAGS_BOTH) || pegasus.isEmbedded(Wearable.SADDLE_BAGS_LEFT) || pegasus.isEmbedded(Wearable.SADDLE_BAGS_RIGHT)) ? legacyWing : rightWing; return (
pegasus.isEmbedded(Wearable.SADDLE_BAGS_BOTH)
|| pegasus.isEmbedded(Wearable.SADDLE_BAGS_LEFT)
|| pegasus.isEmbedded(Wearable.SADDLE_BAGS_RIGHT)
) ? legacyWing : rightWing;
} }
@Override @Override
@ -82,7 +86,7 @@ public class PonyWings<T extends Model & IPegasus> implements IPart, MsonModel {
flapAngle = MathUtil.Angles._270_DEG - 0.9F + (float)Math.sin(ticks / 10) / 15F; flapAngle = MathUtil.Angles._270_DEG - 0.9F + (float)Math.sin(ticks / 10) / 15F;
} }
if (!pegasus.isFlying()) { if (!pegasus.getAttributes().isFlying) {
flapAngle = attributes.getMainInterpolator().interpolate("wingFlap", flapAngle, 10); flapAngle = attributes.getMainInterpolator().interpolate("wingFlap", flapAngle, 10);
} }
@ -99,7 +103,7 @@ public class PonyWings<T extends Model & IPegasus> implements IPart, MsonModel {
public static class Wing implements MsonModel { public static class Wing implements MsonModel {
protected IPegasus pegasus; protected WingedPonyModel<?> pegasus;
protected final ModelPart extended; protected final ModelPart extended;
protected final ModelPart folded; protected final ModelPart folded;
@ -119,14 +123,14 @@ public class PonyWings<T extends Model & IPegasus> implements IPart, MsonModel {
public void rotateWalking(float swing) { public void rotateWalking(float swing) {
folded.yaw = swing * walkingRotationSpeed; folded.yaw = swing * walkingRotationSpeed;
if (pegasus.getMetadata().race().hasBugWings()) { if (pegasus.getRace().hasBugWings()) {
extended.yaw = folded.yaw; extended.yaw = folded.yaw;
} }
} }
public void rotateFlying(float roll) { public void rotateFlying(float roll) {
extended.roll = roll; extended.roll = roll;
if (pegasus.getMetadata().race().hasBugWings()) { if (pegasus.getRace().hasBugWings()) {
folded.roll = roll; folded.roll = roll;
} }
} }

View file

@ -1,43 +0,0 @@
package com.minelittlepony.client.pony;
import java.util.function.Consumer;
public interface Memoize<T> {
T get();
default T get(T fallback) {
T value = get();
return value == null ? fallback : value;
}
default boolean isPresent() {
return true;
}
static <T> Memoize<T> of(T value) {
return () -> value;
}
static <T> Memoize<T> load(Consumer<Consumer<T>> factory) {
return new Memoize<>() {
T value;
boolean loadRequested;
@Override
public T get() {
synchronized (this) {
if (!loadRequested) {
loadRequested = true;
factory.accept(value -> {
this.value = value;
});
}
}
return value;
}
@Override
public boolean isPresent() {
return value != null;
}
};
}
}

View file

@ -1,32 +0,0 @@
package com.minelittlepony.client.pony;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.api.pony.network.MsgPonyData;
import net.minecraft.util.Identifier;
public record Pony (
Identifier texture,
Memoize<IPonyData> memoizedData,
boolean defaulted
) implements IPony {
Pony(Identifier resource) {
this(resource, PonyData.parse(resource), false);
}
@Override
public boolean hasMetadata() {
return memoizedData.isPresent();
}
@Override
public IPonyData metadata() {
return memoizedData.get(PonyData.NULL);
}
public static IPony snapshot(IPony pony) {
return new Pony(pony.texture(), Memoize.of(new MsgPonyData(pony.metadata(), pony.defaulted())), pony.defaulted());
}
}

View file

@ -1,118 +0,0 @@
package com.minelittlepony.client.pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.api.pony.TriggerPixelType;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.util.render.NativeUtil;
import java.io.IOException;
import java.util.*;
import org.jetbrains.annotations.Nullable;
/**
* Implementation for IPonyData.
*/
public record PonyData (
Race race,
TailLength tailLength,
TailShape tailShape,
Gender gender,
Size size,
int glowColor,
boolean[] wearables,
Map<String, TriggerPixelType<?>> attributes
) implements IPonyData {
private static final PonyDataSerialiser SERIALISER = new PonyDataSerialiser();
public static final IPonyData NULL = new PonyData(Race.HUMAN);
public static final Memoize<IPonyData> MEM_NULL = Memoize.of(NULL);
/**
* Parses the given resource into a new IPonyData.
* This may either come from an attached json file or the image itself.
*/
public static Memoize<IPonyData> parse(@Nullable Identifier identifier) {
if (identifier == null) {
return MEM_NULL;
}
return MinecraftClient.getInstance().getResourceManager().getResource(identifier).flatMap(res -> {
try {
return res.getMetadata().decode(SERIALISER);
} catch (IOException e) {
MineLittlePony.logger.warn("Unable to read {} metadata", identifier, e);
}
return null;
}).map(Memoize::of).orElseGet(() -> {
return Memoize.load(callback -> {
NativeUtil.parseImage(identifier, image -> {
callback.accept(new PonyData(
TriggerPixel.RACE.<Race>readValue(image),
TriggerPixel.TAIL.<TailLength>readValue(image),
TriggerPixel.TAIL_SHAPE.<TailShape>readValue(image),
TriggerPixel.GENDER.<Gender>readValue(image),
TriggerPixel.SIZE.<Size>readValue(image),
TriggerPixel.GLOW.readColor(image),
TriggerPixel.WEARABLES.readFlags(image)
));
}, e -> {
MineLittlePony.logger.fatal("Unable to read {} metadata", identifier, e);
callback.accept(NULL);
});
});
});
}
public PonyData(Race race) {
this(race, TailLength.FULL, TailShape.STRAIGHT, Gender.MARE, Sizes.NORMAL, 0x4444aa, new boolean[Wearable.values().length], new TreeMap<>());
attributes.put("race", race);
attributes.put("tailLength", tailLength);
attributes.put("tailShape", tailShape);
attributes.put("gender", gender);
attributes.put("size", size);
attributes.put("magic", TriggerPixelType.of(glowColor));
attributes.put("gear", TriggerPixelType.of(0));
}
PonyData(TriggerPixelType.Value<Race> race, TriggerPixelType.Value<TailLength> tailLength, TriggerPixelType.Value<TailShape> tailShape,
TriggerPixelType.Value<Gender> gender, TriggerPixelType.Value<Size> size, int glowColor, TriggerPixelType.Flags<Wearable> wearables) {
this(race.value(), tailLength.value(), tailShape.value(), gender.value(), size.value(), glowColor, wearables.value(), new TreeMap<>());
attributes.put("race", race);
attributes.put("tailLength", tailLength);
attributes.put("tailShape", tailShape);
attributes.put("gender", gender);
attributes.put("size", size);
attributes.put("magic", TriggerPixelType.of(glowColor));
attributes.put("gear", wearables);
}
@Override
public Size size() {
Sizes sz = MineLittlePony.getInstance().getConfig().sizeOverride.get();
if (sz != Sizes.UNSET) {
return sz;
}
if (size == Sizes.UNSET || !MineLittlePony.getInstance().getConfig().sizes.get()) {
return Sizes.NORMAL;
}
return size;
}
@Override
public Wearable[] gear() {
return Wearable.flags(wearables);
}
@Override
public boolean isWearing(Wearable wearable) {
return wearables[wearable.ordinal()];
}
}

View file

@ -1,26 +0,0 @@
package com.minelittlepony.client.pony;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.minelittlepony.api.pony.IPonyData;
import net.minecraft.resource.metadata.ResourceMetadataReader;
class PonyDataSerialiser implements ResourceMetadataReader<IPonyData> {
private static final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
@Override
public String getKey() {
return "pony";
}
@Override
public IPonyData fromJson(JsonObject json) {
return gson.fromJson(json, PonyData.class);
}
}

View file

@ -13,12 +13,12 @@ import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.RenderPass; import com.minelittlepony.api.model.RenderPass;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.PonyBounds; import com.minelittlepony.client.PonyBounds;
public final class DebugBoundingBoxRenderer { public final class DebugBoundingBoxRenderer {
public static <T extends LivingEntity> void render(IPony pony, EntityRenderer<T> renderer, T entity, MatrixStack stack, VertexConsumerProvider renderContext, float tickDelta) { public static <T extends LivingEntity> void render(Pony pony, EntityRenderer<T> renderer, T entity, MatrixStack stack, VertexConsumerProvider renderContext, float tickDelta) {
if (RenderPass.getCurrent() != RenderPass.WORLD) { if (RenderPass.getCurrent() != RenderPass.WORLD) {
return; return;

View file

@ -1,13 +1,10 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.RenderPass; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.network.MsgPonyData;
import com.minelittlepony.api.pony.network.fabric.Channel; import com.minelittlepony.api.pony.network.fabric.Channel;
import com.minelittlepony.api.pony.network.fabric.PonyDataCallback; import com.minelittlepony.api.pony.network.fabric.PonyDataCallback;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.transform.PonyPosture; import com.minelittlepony.client.transform.PonyPosture;
import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.mson.api.ModelKey;
@ -25,7 +22,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> { public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> {
private ModelWrapper<T, M> playerModel; private ModelWrapper<T, M> playerModel;
@ -104,7 +101,7 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
// negate vanilla translations so the rider begins at the ridees feet. // negate vanilla translations so the rider begins at the ridees feet.
stack.translate(0, -ridingEntity.getHeight(), 0); stack.translate(0, -ridingEntity.getHeight(), 0);
IPony riderPony = renderer.getEntityPony(ridingEntity); Pony riderPony = renderer.getEntityPony(ridingEntity);
renderer.translateRider(ridingEntity, riderPony, entity, renderer.getEntityPony(entity), stack, ticks); renderer.translateRider(ridingEntity, riderPony, entity, renderer.getEntityPony(entity), stack, ticks);
} }
@ -119,8 +116,8 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, -1); PonyPosture.of(getModel().getAttributes()).apply(entity, getModel(), stack, yaw, tickDelta, -1);
} }
public IPony updateModel(T entity, ModelAttributes.Mode mode) { public Pony updateModel(T entity, ModelAttributes.Mode mode) {
IPony pony = renderer.getEntityPony(entity); Pony pony = renderer.getEntityPony(entity);
playerModel.applyMetadata(pony.metadata()); playerModel.applyMetadata(pony.metadata());
if (pony.hasMetadata() && entity instanceof RegistrationHandler && ((RegistrationHandler)entity).shouldUpdateRegistration(pony)) { if (pony.hasMetadata() && entity instanceof RegistrationHandler && ((RegistrationHandler)entity).shouldUpdateRegistration(pony)) {
@ -129,10 +126,10 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
PlayerEntity clientPlayer = MinecraftClient.getInstance().player; PlayerEntity clientPlayer = MinecraftClient.getInstance().player;
if (clientPlayer != null) { if (clientPlayer != null) {
if (Objects.equals(entity, clientPlayer) || Objects.equals(((PlayerEntity)entity).getGameProfile(), clientPlayer.getGameProfile())) { if (Objects.equals(entity, clientPlayer) || Objects.equals(((PlayerEntity)entity).getGameProfile(), clientPlayer.getGameProfile())) {
Channel.broadcastPonyData(new MsgPonyData(pony.metadata(), pony.defaulted())); Channel.broadcastPonyData(pony.metadata());
} }
} }
PonyDataCallback.EVENT.invoker().onPonyDataAvailable((PlayerEntity)entity, pony.metadata(), pony.defaulted(), EnvType.CLIENT); PonyDataCallback.EVENT.invoker().onPonyDataAvailable((PlayerEntity)entity, pony.metadata(), EnvType.CLIENT);
} }
getModel().updateLivingState(entity, pony, mode); getModel().updateLivingState(entity, pony, mode);
@ -168,6 +165,6 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
} }
public interface RegistrationHandler { public interface RegistrationHandler {
boolean shouldUpdateRegistration(IPony pony); boolean shouldUpdateRegistration(Pony pony);
} }
} }

View file

@ -1,25 +1,25 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IGear; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.client.model.*; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public interface IPonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends IGear.Context<T, M> { public interface IPonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
IPony getEntityPony(T entity); Pony getEntityPony(T entity);
EquineRenderManager<T, M> getInternalRenderer(); EquineRenderManager<T, M> getInternalRenderer();
/** /**
* Called by riders to have their transportation adjust their position. * Called by riders to have their transportation adjust their position.
*/ */
default void translateRider(T entity, IPony entityPony, LivingEntity passenger, IPony passengerPony, MatrixStack stack, float ticks) { default void translateRider(T entity, Pony entityPony, LivingEntity passenger, Pony passengerPony, MatrixStack stack, float ticks) {
if (!passengerPony.race().isHuman()) { if (!passengerPony.race().isHuman()) {
float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), ticks); float yaw = MathUtil.interpolateDegress((float)entity.prevY, (float)entity.getY(), ticks);

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.util.render.RenderLayerUtil; import com.minelittlepony.client.util.render.RenderLayerUtil;
@ -21,7 +21,7 @@ import net.minecraft.util.math.RotationAxis;
import net.minecraft.world.World; import net.minecraft.world.World;
public class LevitatingItemRenderer { public class LevitatingItemRenderer {
private VertexConsumerProvider getProvider(IPony pony, VertexConsumerProvider renderContext) { private VertexConsumerProvider getProvider(Pony pony, VertexConsumerProvider renderContext) {
final int color = pony.metadata().glowColor(); final int color = pony.metadata().glowColor();
return layer -> { return layer -> {
Identifier texture = RenderLayerUtil.getTexture(layer).orElse(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); Identifier texture = RenderLayerUtil.getTexture(layer).orElse(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE);
@ -39,7 +39,7 @@ public class LevitatingItemRenderer {
if (entity instanceof PlayerEntity && (mode.isFirstPerson() || mode == ModelTransformationMode.THIRD_PERSON_LEFT_HAND || mode == ModelTransformationMode.THIRD_PERSON_RIGHT_HAND)) { if (entity instanceof PlayerEntity && (mode.isFirstPerson() || mode == ModelTransformationMode.THIRD_PERSON_LEFT_HAND || mode == ModelTransformationMode.THIRD_PERSON_RIGHT_HAND)) {
IPony pony = IPony.getManager().getPony((PlayerEntity)entity); Pony pony = Pony.getManager().getPony((PlayerEntity)entity);
matrix.push(); matrix.push();

View file

@ -1,10 +1,11 @@
package com.minelittlepony.client.render; package com.minelittlepony.client.render;
import java.util.function.Function; import java.util.function.Function;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.mixin.MixinEntityRenderers; import com.minelittlepony.client.mixin.MixinEntityRenderers;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.render.entity.PlayerPonyRenderer; import com.minelittlepony.client.render.entity.PlayerPonyRenderer;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer; import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
@ -45,7 +46,7 @@ public class PonyRenderDispatcher {
Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer( Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer(
new Identifier("minelittlepony", "sea/" + armShape.getName()), new Identifier("minelittlepony", "sea/" + armShape.getName()),
player -> { player -> {
return !IPony.getManager().getPony(player).race().isHuman() return !Pony.getManager().getPony(player).race().isHuman()
&& PonyPosture.hasSeaponyForm(player) && PonyPosture.hasSeaponyForm(player)
&& player.method_52814().model() == armShape; && player.method_52814().model() == armShape;
}, },
@ -54,7 +55,7 @@ public class PonyRenderDispatcher {
Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer( Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer(
new Identifier("minelittlepony", "land/" + armShape.getName()), new Identifier("minelittlepony", "land/" + armShape.getName()),
player -> { player -> {
return !IPony.getManager().getPony(player).race().isHuman() return !Pony.getManager().getPony(player).race().isHuman()
&& !PonyPosture.hasSeaponyForm(player) && !PonyPosture.hasSeaponyForm(player)
&& player.method_52814().model() == armShape; && player.method_52814().model() == armShape;
}, },
@ -82,7 +83,7 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
public <T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> IPonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) { public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> IPonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) {
if (entity == null) { if (entity == null) {
return null; return null;
} }

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer.ISkull; import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer.ISkull;
@ -43,7 +43,7 @@ public class MobSkull implements ISkull {
} }
@Override @Override
public boolean bindPony(IPony pony) { public boolean bindPony(Pony pony) {
ponyHead.get().setMetadata(pony.metadata()); ponyHead.get().setMetadata(pony.metadata());
return true; return true;
} }

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.config.PonyLevel; import com.minelittlepony.api.config.PonyLevel;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.SkinsProxy; import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
@ -52,7 +52,7 @@ public class PlayerPonySkull implements ISkull {
} }
@Override @Override
public boolean bindPony(IPony pony) { public boolean bindPony(Pony pony) {
Race race = pony.race(); Race race = pony.race();
if (race.isHuman()) { if (race.isHuman()) {
race = Race.EARTH; race = Race.EARTH;

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.blockentity.skull;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.minelittlepony.api.config.PonyConfig; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.render.MobRenderers; import com.minelittlepony.client.render.MobRenderers;
@ -68,7 +68,7 @@ public class PonySkullRenderer {
return false; return false;
} }
if (!selectedSkull.bindPony(IPony.getManager().getPony(selectedSkin))) { if (!selectedSkull.bindPony(Pony.getManager().getPony(selectedSkin))) {
return false; return false;
} }
@ -112,6 +112,6 @@ public class PonySkullRenderer {
Identifier getSkinResource(@Nullable GameProfile profile); Identifier getSkinResource(@Nullable GameProfile profile);
boolean bindPony(IPony pony); boolean bindPony(Pony pony);
} }
} }

View file

@ -1,6 +1,7 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.*; import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer; import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
@ -26,7 +27,7 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & IPonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements IPonyRenderContext<T, M> { public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements IPonyRenderContext<T, M> {
protected final EquineRenderManager<T, M> manager = new EquineRenderManager<>(this); protected final EquineRenderManager<T, M> manager = new EquineRenderManager<>(this);
@ -132,8 +133,8 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
} }
@Override @Override
public IPony getEntityPony(T entity) { public Pony getEntityPony(T entity) {
return IPony.getManager().getPony(getTexture(entity)); return Pony.getManager().getPony(getTexture(entity));
} }
public static <E extends MobEntity, M extends ClientPonyModel<E>, T extends PonyRenderer<E, M>, F extends FeatureRenderer<E, M>> public static <E extends MobEntity, M extends ClientPonyModel<E>, T extends PonyRenderer<E, M>, F extends FeatureRenderer<E, M>>
@ -143,7 +144,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public static <T extends MobEntity, M extends EntityModel<T> & IPonyModel<T> & ModelWithArms> AbstractPonyRenderer<T, M> proxy(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale, public static <T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> AbstractPonyRenderer<T, M> proxy(EntityRendererFactory.Context context, ModelKey<? super M> key, TextureSupplier<T> texture, float scale,
List exportedLayers, Consumer<M> modelConsumer) { List exportedLayers, Consumer<M> modelConsumer) {
var renderer = new AbstractPonyRenderer<T, M>(context, key, texture, scale) { var renderer = new AbstractPonyRenderer<T, M>(context, key, texture, scale) {
@Override @Override

View file

@ -1,9 +1,9 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.IPreviewModel; import com.minelittlepony.client.PreviewModel;
import com.minelittlepony.client.SkinsProxy; import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
@ -37,7 +37,7 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
updateSeaponyState(player); updateSeaponyState(player);
super.render(player, entityYaw, tickDelta, stack, renderContext, light); super.render(player, entityYaw, tickDelta, stack, renderContext, light);
if (!(player instanceof IPreviewModel) && wet && player.getVelocity().length() > 0.1F) { if (!(player instanceof PreviewModel) && wet && player.getVelocity().length() > 0.1F) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1); double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);
double y = player.getEntityWorld().getRandom().nextTriangular(player.getY(), 1); double y = player.getEntityWorld().getRandom().nextTriangular(player.getY(), 1);
double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1); double z = player.getEntityWorld().getRandom().nextTriangular(player.getZ(), 1);
@ -46,7 +46,7 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
} }
} }
protected Race getPlayerRace(AbstractClientPlayerEntity entity, IPony pony) { protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
Race race = super.getPlayerRace(entity, pony); Race race = super.getPlayerRace(entity, pony);
return wet ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race; return wet ? Race.SEAPONY : race == Race.SEAPONY ? Race.UNICORN : race;
} }
@ -69,10 +69,10 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
} }
private void updateSeaponyState(AbstractClientPlayerEntity player) { private void updateSeaponyState(AbstractClientPlayerEntity player) {
IPony pony = getEntityPony(player); Pony pony = getEntityPony(player);
wet = PonyPosture.isSeaponyModifier(player); wet = PonyPosture.isSeaponyModifier(player);
if (!(player instanceof IPreviewModel)) { if (!(player instanceof PreviewModel)) {
float state = wet ? 100 : 0; float state = wet ? 100 : 0;
float interpolated = pony.metadata().getInterpolator(player.getUuid()).interpolate("seapony_state", state, 5); float interpolated = pony.metadata().getInterpolator(player.getUuid()).interpolate("seapony_state", state, 5);

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.render.entity; package com.minelittlepony.client.render.entity;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.SkinsProxy; import com.minelittlepony.client.SkinsProxy;
@ -77,7 +77,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
@Override @Override
public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) { public void render(AbstractClientPlayerEntity entity, float entityYaw, float tickDelta, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv) {
IPony pony = getEntityPony(entity); Pony pony = getEntityPony(entity);
model = manager.setModel(modelsCache.apply(getPlayerRace(entity, pony))).body(); model = manager.setModel(modelsCache.apply(getPlayerRace(entity, pony))).body();
// EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering // EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering
shadowRadius = manager.getModel().getSize().shadowSize(); shadowRadius = manager.getModel().getSize().shadowSize();
@ -88,7 +88,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
// (shadows are drawn after us) // (shadows are drawn after us)
if (!entity.hasVehicle() && !entity.isSleeping()) { if (!entity.hasVehicle() && !entity.isSleeping()) {
float yaw = MathHelper.lerpAngleDegrees(tickDelta, entity.prevBodyYaw, entity.bodyYaw); float yaw = MathHelper.lerpAngleDegrees(tickDelta, entity.prevBodyYaw, entity.bodyYaw);
float l = entity.getWidth() / 2 * pony.metadata().size().scaleFactor(); float l = entity.getWidth() / 2 * pony.size().scaleFactor();
stack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw)); stack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw));
stack.translate(0, 0, -l); stack.translate(0, 0, -l);
@ -96,7 +96,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
} }
} }
protected Race getPlayerRace(AbstractClientPlayerEntity entity, IPony pony) { protected Race getPlayerRace(AbstractClientPlayerEntity entity, Pony pony) {
return pony.race(); return pony.race();
} }
@ -144,7 +144,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
} }
protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) { protected void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, AbstractClientPlayerEntity player, Arm side) {
IPony pony = getEntityPony(player); Pony pony = getEntityPony(player);
model = manager.setModel(modelsCache.apply(getPlayerRace(player, pony))).body(); model = manager.setModel(modelsCache.apply(getPlayerRace(player, pony))).body();
manager.updateModel(player, ModelAttributes.Mode.FIRST_PERSON); manager.updateModel(player, ModelAttributes.Mode.FIRST_PERSON);
@ -184,14 +184,14 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
} }
@Override @Override
public IPony getEntityPony(AbstractClientPlayerEntity entity) { public Pony getEntityPony(AbstractClientPlayerEntity entity) {
return IPony.getManager().getPony(entity); return Pony.getManager().getPony(entity);
} }
@Override @Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) { public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) {
return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> { return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> {
if (wearable.isSaddlebags() && getInternalRenderer().getModel().getMetadata().race().supportsLegacySaddlebags()) { if (wearable.isSaddlebags() && getInternalRenderer().getModel().getRace().supportsLegacySaddlebags()) {
return getTexture(entity); return getTexture(entity);
} }

View file

@ -12,12 +12,12 @@ import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.armour.ArmourLayer; import com.minelittlepony.api.model.armour.ArmourLayer;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.model.entity.PonyArmourStandModel; import com.minelittlepony.client.model.entity.PonyArmourStandModel;
import com.minelittlepony.client.model.entity.race.EarthPonyModel; import com.minelittlepony.client.model.entity.race.EarthPonyModel;
import com.minelittlepony.client.pony.PonyData;
import com.minelittlepony.client.render.entity.feature.ArmourFeature; import com.minelittlepony.client.render.entity.feature.ArmourFeature;
public class PonyStandRenderer extends ArmorStandEntityRenderer { public class PonyStandRenderer extends ArmorStandEntityRenderer {
@ -69,7 +69,7 @@ public class PonyStandRenderer extends ArmorStandEntityRenderer {
context.getModelManager() context.getModelManager()
); );
pony.applyMetadata(new PonyData(Race.EARTH)); pony.applyMetadata(PonyData.emptyOf(Race.EARTH));
} }
@Override @Override

View file

@ -10,10 +10,10 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.PonyModel;
// separate class in case I need it later // separate class in case I need it later
public abstract class AbstractClothingFeature<T extends LivingEntity, M extends BipedEntityModel<T> & IModel> extends FeatureRenderer<T, M> { public abstract class AbstractClothingFeature<T extends LivingEntity, M extends BipedEntityModel<T> & PonyModel<T>> extends FeatureRenderer<T, M> {
protected final FeatureRendererContext<T, M> renderer; protected final FeatureRendererContext<T, M> renderer;

View file

@ -1,6 +1,6 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.client.model.IPonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
@ -11,7 +11,7 @@ import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public abstract class AbstractPonyFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends FeatureRenderer<T, M> { public abstract class AbstractPonyFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends FeatureRenderer<T, M> {
private final IPonyRenderContext<T, M> context; private final IPonyRenderContext<T, M> context;

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.armour.*; import com.minelittlepony.api.model.armour.*;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.model.armour.DefaultArmourTextureResolver; import com.minelittlepony.client.model.armour.DefaultArmourTextureResolver;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
@ -21,7 +21,7 @@ import net.minecraft.item.*;
import net.minecraft.item.trim.ArmorTrim; import net.minecraft.item.trim.ArmorTrim;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends AbstractPonyFeature<T, M> { public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
public ArmourFeature(IPonyRenderContext<T, M> context, BakedModelManager bakery) { public ArmourFeature(IPonyRenderContext<T, M> context, BakedModelManager bakery) {
super(context); super(context);
@ -40,7 +40,7 @@ public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & IP
} }
public static <T extends LivingEntity, V extends BipedEntityModel<T> & IArmourModel<T>> void renderArmor( public static <T extends LivingEntity, V extends BipedEntityModel<T> & IArmourModel<T>> void renderArmor(
ModelWrapper<T, ? extends IPonyModel<T>> pony, MatrixStack matrices, ModelWrapper<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
VertexConsumerProvider renderContext, int light, T entity, VertexConsumerProvider renderContext, int light, T entity,
float limbDistance, float limbAngle, float limbDistance, float limbAngle,
float age, float headYaw, float headPitch, float age, float headYaw, float headPitch,

View file

@ -7,13 +7,13 @@ import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.DJPon3EarsModel; import com.minelittlepony.client.model.DJPon3EarsModel;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
public class DJPon3Feature<T extends AbstractClientPlayerEntity, M extends EntityModel<T> & IPonyModel<T>> extends AbstractPonyFeature<T, M> { public class DJPon3Feature<T extends AbstractClientPlayerEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
private final DJPon3EarsModel deadMau5 = ModelType.DJ_PON_3.createModel(); private final DJPon3EarsModel deadMau5 = ModelType.DJ_PON_3.createModel();

View file

@ -1,8 +1,8 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.PonyElytra; import com.minelittlepony.client.model.PonyElytra;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
@ -22,7 +22,7 @@ import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends AbstractPonyFeature<T, M> { public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
private static final Identifier TEXTURE_ELYTRA = new Identifier("textures/entity/elytra.png"); private static final Identifier TEXTURE_ELYTRA = new Identifier("textures/entity/elytra.png");

View file

@ -11,10 +11,9 @@ import net.minecraft.util.math.random.Random;
import com.google.common.cache.*; import com.google.common.cache.*;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.gear.IGear; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.IStackable; import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
@ -23,11 +22,11 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends AbstractPonyFeature<T, M> { public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
private static final List<Supplier<IGear>> MOD_GEARS = new ArrayList<>(); private static final List<Supplier<Gear>> MOD_GEARS = new ArrayList<>();
public static void addModGear(Supplier<IGear> gear) { public static void addModGear(Supplier<Gear> gear) {
MOD_GEARS.add(gear); MOD_GEARS.add(gear);
} }
@ -64,29 +63,30 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & IPon
final Object2FloatMap<BodyPart> renderStackingOffsets = new Object2FloatLinkedOpenHashMap<>(); final Object2FloatMap<BodyPart> renderStackingOffsets = new Object2FloatLinkedOpenHashMap<>();
for (var entry : randomisedGearCache.getUnchecked(entity.getUuid().getLeastSignificantBits())) { for (var entry : randomisedGearCache.getUnchecked(entity.getUuid().getLeastSignificantBits())) {
if (getContext().shouldRender(model, entity, entry.wearable, entry.gear)) { if (getContext().shouldRender(model, entity, entry.wearable(), entry.gear())) {
stack.push(); stack.push();
BodyPart part = entry.gear.getGearLocation(); Gear gear = entry.gear();
entry.gear.transform(model, stack); gear.transform(model, stack);
if (entry.gear instanceof IStackable s) { if (gear.isStackable()) {
BodyPart part = gear.getGearLocation();
float v = renderStackingOffsets.getFloat(part); float v = renderStackingOffsets.getFloat(part);
if (v != 0) { if (v != 0) {
stack.translate(0, -v, 0); stack.translate(0, -v, 0);
} }
renderStackingOffsets.put(part, v + s.getStackingHeight()); renderStackingOffsets.put(part, v + gear.getStackingHeight());
} }
renderGear(model, entity, entry.gear, stack, renderContext, lightUv, limbDistance, limbAngle, tickDelta); renderGear(model, entity, gear, stack, renderContext, lightUv, limbDistance, limbAngle, tickDelta);
stack.pop(); stack.pop();
} }
} }
} }
private void renderGear(M model, T entity, IGear gear, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, float limbDistance, float limbAngle, float tickDelta) { 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.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, 1, 1, 1, 1, entity.getUuid()); gear.render(stack, renderContext.getBuffer(gear.getLayer(entity, getContext())), lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1, entity.getUuid());
} }
static record Entry(IGear gear, Wearable wearable) {} static record Entry(Gear gear, Wearable wearable) { }
} }

View file

@ -7,10 +7,10 @@ import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import com.minelittlepony.client.model.IPonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
public class GlowingEyesFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends EyesFeatureRenderer<T, M> { public class GlowingEyesFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends EyesFeatureRenderer<T, M> {
private final RenderLayer layer; private final RenderLayer layer;

View file

@ -1,7 +1,7 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.client.model.IPonyModel; import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.IPonyRenderContext;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
@ -16,7 +16,7 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
public class HeldItemFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T> & ModelWithArms> extends HeldItemFeatureRenderer<T, M> { public class HeldItemFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends HeldItemFeatureRenderer<T, M> {
private final IPonyRenderContext<T, M> context; private final IPonyRenderContext<T, M> context;

Some files were not shown because too many files have changed in this diff Show more