Rewrites round tri

This commit is contained in:
Sollace 2023-09-26 15:59:07 +01:00
parent 0e30b2c8dd
commit b37ffa9860
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
54 changed files with 417 additions and 567 deletions

View file

@ -3,6 +3,7 @@ package com.minelittlepony.api.config;
import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.pony.meta.*;
import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.util.GamePaths;
import com.minelittlepony.common.util.settings.*;
@ -54,7 +55,7 @@ public class PonyConfig extends Config {
public final Setting<Boolean> horsieMode = value("settings", "horsieMode", false)
.addComment("Enables the alternative horsey models from the April Fools 2023 update");
public final Setting<Sizes> sizeOverride = value("debug", "sizeOverride", Sizes.UNSET)
public final Setting<SizePreset> sizeOverride = value("debug", "sizeOverride", SizePreset.UNSET)
.addComment("Overrides pony sizes")
.addComment("Possible values: TALL, BULKY, LANKY, NORMAL, YEARLING, FOAL, UNSET (default)");
@ -72,6 +73,12 @@ public class PonyConfig extends Config {
.addComment("Disables certain easter eggs and secrets (party pooper)")
.addComment("Turning this off may help with compatibility in some cases");
public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO)
.addComment("Whether to show the mine little pony settings button on the main menu")
.addComment("AUTO (default) - only show when HDSkins is not installed")
.addComment("ON - always show")
.addComment("OFF - never show");
public PonyConfig(Path path) {
super(HEIRARCHICAL_JSON_ADAPTER, path);
instance = this;
@ -132,14 +139,14 @@ public class PonyConfig extends Config {
}
public static Size getEffectiveSize(Size size) {
Sizes sz = instance.sizeOverride.get();
SizePreset sz = instance.sizeOverride.get();
if (sz != Sizes.UNSET) {
if (sz != SizePreset.UNSET) {
return sz;
}
if (size == Sizes.UNSET || !instance.sizes.get()) {
return Sizes.NORMAL;
if (size == SizePreset.UNSET || !instance.sizes.get()) {
return SizePreset.NORMAL;
}
return size;

View file

@ -23,7 +23,7 @@ public class MsgPonyData {
new MsgSize(buffer),
buffer.readInt(),
buffer.readBoolean(),
Flags.read(Wearable.class, buffer)
Flags.read(Wearable.NONE, buffer)
);
}

View file

@ -165,7 +165,7 @@ public class ModelAttributes {
}
public Interpolator getMainInterpolator() {
return metadata.getInterpolator(interpolatorId);
return Interpolator.linear(interpolatorId);
}
public boolean shouldLiftArm(ArmPose pose, ArmPose complement, float sigma) {

View file

@ -79,7 +79,7 @@ public interface PonyModel<T extends LivingEntity> extends MsonModel, ModelWithH
* i.e. Used to change wing rendering when using saddlebags.
*/
default boolean isEmbedded(Wearable wearable) {
return getAttributes().metadata.isWearing(wearable);
return getAttributes().metadata.gear().matches(wearable);
}
}

View file

@ -6,7 +6,6 @@ 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;
@ -53,64 +52,40 @@ public record PonyData (
/**
* Gets the trigger pixel values as they appeared in the underlying image.
*/
Map<String, TriggerPixelType<?>> attributes
Map<String, TValue<?>> 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 int DEFAULT_MAGIC_COLOR = 0x4444aa;
private static final Function<Race, PonyData> OF_RACE = Util.memoize(race -> new PonyData(race, TailLength.FULL, TailShape.STRAIGHT, Gender.MARE, SizePreset.NORMAL, DEFAULT_MAGIC_COLOR, true, Wearable.EMPTY_FLAGS));
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);
})
public PonyData(TriggerPixel.Mat image, boolean noSkin) {
this(
TriggerPixel.RACE.read(image),
TriggerPixel.TAIL.read(image),
TriggerPixel.TAIL_SHAPE.read(image),
TriggerPixel.GENDER.read(image),
TriggerPixel.SIZE.read(image),
TriggerPixel.GLOW.read(image),
noSkin,
TriggerPixel.WEARABLES.read(image)
);
}
/**
* 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);
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", new TValue.Numeric(glowColor));
map.put("gear", wearables);
})
);
}
@Override

View file

@ -1,6 +1,7 @@
package com.minelittlepony.api.pony;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
@ -10,8 +11,7 @@ import java.util.Optional;
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 the skin of an entity.
*/
public interface PonyManager {
/**
@ -19,7 +19,25 @@ public interface PonyManager {
*
* If the supplied entity is null or can't be determined to be a pony, returns the empty optional.
*/
Optional<Pony> getPony(@Nullable Entity entity);
default Optional<Pony> getPony(@Nullable Entity entity) {
return entity instanceof LivingEntity living ? getPony(living) : Optional.empty();
}
/**
* 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.
*/
Optional<Pony> getPony(LivingEntity entity);
/**
* Gets a random background pony determined by the given uuid.
*
* Useful for mods that offer customisation, especially ones that have a whole lot of NPCs.
*
* @param uuid id of a player
*/
Pony getBackgroundPony(UUID uuid);
/**
* Gets or creates a pony for the given player.
@ -29,13 +47,6 @@ public interface PonyManager {
*/
Pony getPony(PlayerEntity player);
/**
* Gets or creates a pony for the given skin resource and vanilla model type.
*
* @param resource A texture resource
*/
Pony getPony(Identifier resource);
/**
* Gets or creates a pony for the given skin resource and entity id.
*
@ -46,23 +57,16 @@ public interface PonyManager {
* @param resource A texture resource
* @param uuid id of a player
*/
Pony getPony(Identifier resource, UUID uuid);
Pony getPony(@Nullable Identifier resource, @Nullable UUID uuid);
/**
* Gets a random background pony determined by the given uuid.
* Gets or creates a pony for the given skin resource and vanilla model type.
*
* Useful for mods that offer customisation, especially ones that have a whole lot of NPCs.
*
* @param uuid A UUID. Either a user or an entity.
* @param resource A texture resource
*/
Pony getBackgroundPony(UUID uuid);
/**
* De-registers a pony from the cache.
*/
void removePony(Identifier resource);
void clearCache();
default Pony getPony(Identifier resource) {
return getPony(resource, null);
}
interface ForcedPony {}

View file

@ -4,30 +4,30 @@ import net.minecraft.network.PacketByteBuf;
import java.util.*;
public record Flags<T extends Enum<T>> (
boolean[] flags,
List<T> values,
public record Flags<T extends Enum<T> & TValue<T>> (
T def,
Set<T> values,
int colorCode
) implements Comparable<Flags<T>> {
) implements Comparable<Flags<T>>, TValue<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> & TValue<T>> Flags<T> of(T def) {
return new Flags<>(def, Set.<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> & TValue<T>> Flags<T> of(T def, int colorCode, Set<T> values) {
return new Flags<>(def, values, colorCode);
}
public static <T extends Enum<T>> Flags<T> read(Class<T> type, PacketByteBuf buffer) {
public static <T extends Enum<T> & TValue<T>> Flags<T> read(T def, PacketByteBuf buffer) {
int length = buffer.readVarInt();
List<T> values = new ArrayList<>();
T[] all = type.getEnumConstants();
boolean[] flags = new boolean[all.length];
@SuppressWarnings("unchecked")
Set<T> values = EnumSet.noneOf((Class<T>)def.getClass());
@SuppressWarnings("unchecked")
T[] all = (T[])def.getClass().getEnumConstants();
for (int i = 0; i < length; i++) {
values.add(all[buffer.readInt()]);
flags[i] = true;
}
return new Flags<>(flags, values, buffer.readInt());
return new Flags<>(def, values, buffer.readInt());
}
public static <T> List<T> flags(T[] values, boolean[] flags) {
@ -38,16 +38,30 @@ public record Flags<T extends Enum<T>> (
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);
}
@Override
public String name() {
return "[Flags " + values + "]";
}
@Override
public List<TValue<T>> getOptions() {
return def.getOptions();
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(TValue<?> o) {
return o.getClass() == def.getClass() && values.contains((T)o);
}
@Override
public int compareTo(Flags<T> other) {
return Integer.compare(colorCode(), other.colorCode());
}
}

View file

@ -1,6 +1,6 @@
package com.minelittlepony.api.pony.meta;
public enum Gender implements TriggerPixelType<Gender> {
public enum Gender implements TValue<Gender> {
MARE(0),
STALLION(0xffffff),
ABOMONATION(0x888888);

View file

@ -1,8 +1,6 @@
package com.minelittlepony.api.pony.meta;
import java.util.*;
public enum Race implements TriggerPixelType<Race> {
public enum Race implements TValue<Race> {
HUMAN (0x000000, false, false),
EARTH (0xf9b131, false, false),
PEGASUS (0x88caf0, true, false),
@ -17,16 +15,13 @@ public enum Race implements TriggerPixelType<Race> {
BATPONY (0xeeeeee, true, false),
SEAPONY (0x3655dd, false, true);
private boolean wings;
private boolean horn;
private final boolean wings;
private final boolean horn;
private int triggerPixel;
public static final List<Race> REGISTRY = Arrays.asList(values());
Race(int triggerPixel, boolean wings, boolean horn) {
this.triggerPixel = triggerPixel;
private final int colorCode;
Race(int colorCode, boolean wings, boolean horn) {
this.colorCode = colorCode;
this.wings = wings;
this.horn = horn;
}
@ -68,6 +63,6 @@ public enum Race implements TriggerPixelType<Race> {
@Override
public int colorCode() {
return triggerPixel;
return colorCode;
}
}

View file

@ -3,13 +3,13 @@ package com.minelittlepony.api.pony.meta;
/**
* Represents the different model sizes that are possible.
*
* For a list of possible presets, look at {@link Sizes}.
* For a list of possible presets, look at {@link SizePreset}.
* This interface exists for servers so they can work with this information even though they might not have access to the client config.
*
*/
public interface Size extends TriggerPixelType<Size> {
public interface Size extends TValue<Size> {
/**
* The Enum index of this size. May be used on the client to convert to an instance of Sizes or use {@link Sizes#of}
* The Enum index of this size. May be used on the client to convert to an instance of Sizes or use {@link SizePreset#of}
*
* Made to be compatible with the enum variant.
*/

View file

@ -9,7 +9,7 @@ import com.minelittlepony.api.config.PonyConfig;
*
* For spooky things at a distance, use {@link Size} instead.
*/
public enum Sizes implements Size {
public enum SizePreset implements Size {
TALL (0x534b76, 0.45f, 1.1F, 1.15F),
BULKY (0xce3254, 0.5f, 1, 1.05F),
LANKY (0x3254ce, 0.45F, 0.85F, 0.9F),
@ -18,13 +18,12 @@ public enum Sizes implements Size {
FOAL (0xffbe53, 0.25f, 0.6F, 0.5F),
UNSET (0x000000, 1, 1, 1);
private int triggerValue;
private final int triggerValue;
private final float shadowSize;
private final float scale;
private final float camera;
private float shadowSize;
private float scale;
private float camera;
Sizes(int pixel, float shadowSz, float scaleF, float cameraF) {
SizePreset(int pixel, float shadowSz, float scaleF, float cameraF) {
triggerValue = pixel;
shadowSize = shadowSz;
scale = scaleF;
@ -58,5 +57,4 @@ public enum Sizes implements Size {
public float eyeDistanceFactor() {
return eyeHeightFactor();
}
}

View file

@ -0,0 +1,66 @@
package com.minelittlepony.api.pony.meta;
import java.util.Arrays;
import java.util.List;
/**
* Interface for enums that can be parsed from an image trigger pixel value.
*/
public interface TValue<T> {
/**
* Gets the pixel colour matching this enum value.
*/
int colorCode();
/**
* Gets the pixel colour matching this enum value, adjusted to fill all three channels.
*/
default int getChannelAdjustedColorCode() {
return colorCode();
}
/**
* Gets a string representation of this value.
*/
String name();
default String getHexValue() {
return toHex(colorCode());
}
/**
* Returns a list of possible values this trigger pixel can accept.
*/
@SuppressWarnings("unchecked")
default List<TValue<T>> getOptions() {
if (this instanceof Enum) {
// cast is required because gradle's compiler is more strict
return Arrays.asList(getClass().getEnumConstants());
}
return List.of();
}
default boolean matches(TValue<?> o) {
return o != null && colorCode() == o.colorCode();
}
static String toHex(int color) {
String v = Integer.toHexString(color).toUpperCase();
while (v.length() < 6) {
v = "0" + v;
}
return "#" + v;
}
public record Numeric(int colorCode) implements TValue<Integer> {
@Override
public String name() {
return "[Numeric " + getHexValue() + "]";
}
@Override
public List<TValue<Integer>> getOptions() {
return List.of();
}
}
}

View file

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

View file

@ -1,6 +1,6 @@
package com.minelittlepony.api.pony.meta;
public enum TailShape implements TriggerPixelType<TailShape> {
public enum TailShape implements TValue<TailShape> {
STRAIGHT(0),
BUMPY (0xfc539f),
SWIRLY (0x3eff22),

View file

@ -1,112 +1,91 @@
package com.minelittlepony.api.pony.meta;
import net.minecraft.client.texture.NativeImage;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.util.math.ColorHelper;
import org.joml.Vector2i;
import com.minelittlepony.common.util.Color;
import java.util.Arrays;
import java.util.*;
/**
* Individual trigger pixels for a pony skin.
*
*/
@SuppressWarnings("unchecked")
public enum TriggerPixel {
RACE(Race.HUMAN, Channel.ALL, 0, 0),
TAIL(TailLength.FULL, Channel.ALL, 1, 0),
GENDER(Gender.MARE, Channel.ALL, 2, 0),
SIZE(Sizes.NORMAL, Channel.ALL, 3, 0),
GLOW(null, Channel.RAW, 0, 1),
WEARABLES(Wearable.NONE, Channel.RAW, 1, 1),
TAIL_SHAPE(TailShape.STRAIGHT, Channel.ALL, 2, 1);
public interface TriggerPixel<T> {
Vector2i MAX_COORDS = new Vector2i();
private final int x;
private final int y;
TriggerPixel<Race> RACE = ofOptions(0, 0, Race.HUMAN, Race.values());
TriggerPixel<TailLength> TAIL = ofOptions(1, 0, TailLength.FULL, TailLength.values());
TriggerPixel<Gender> GENDER = ofOptions(2, 0, Gender.MARE, Gender.values());
TriggerPixel<TailShape> TAIL_SHAPE = ofOptions(2, 1, TailShape.STRAIGHT, TailShape.values());
TriggerPixel<Size> SIZE = ofOptions(3, 0, SizePreset.NORMAL, SizePreset.values());
TriggerPixel<Integer> GLOW = ofColor(0, 1);
TriggerPixel<Flags<Wearable>> WEARABLES = ofFlags(1, 1, Wearable.EMPTY_FLAGS, Wearable.values());
private final Channel channel;
static <T extends TValue<T>> TriggerPixel<T> ofOptions(int x, int y, T def, T[] options) {
MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
Int2ObjectOpenHashMap<T> lookup = buildLookup(options);
return image -> {
int color = Color.abgrToArgb(image.getColor(x, y));
private final TriggerPixelType<?> def;
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_Y = Arrays.stream(VALUES).mapToInt(i -> i.y).max().getAsInt();
TriggerPixel(TriggerPixelType<?> def, Channel channel, int x, int y) {
this.def = def;
this.channel = channel;
this.x = x;
this.y = y;
if (ColorHelper.Argb.getAlpha(color) < 255) {
return (T)def;
}
return lookup.getOrDefault(color & 0x00FFFFFF, def);
};
}
/**
* Reads this trigger pixel's value and returns the raw colour.
*
* @param image Image to read
*/
public int readColor(NativeImage image) {
return channel.readValue(x, y, image);
static TriggerPixel<Integer> ofColor(int x, int y) {
MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
return image -> Color.abgrToArgb(image.getColor(x, y));
}
/**
* Reads this trigger pixel's value and parses it to an Enum instance.
*
* @param image Image to read
*/
public <T extends TriggerPixelType<T>> T readValue(NativeImage image) {
int color = readColor(image);
static <T extends Enum<T> & TValue<T>> TriggerPixel<Flags<T>> ofFlags(int x, int y, Flags<T> def, T[] options) {
MAX_COORDS.x = Math.max(MAX_COORDS.x, x);
MAX_COORDS.y = Math.max(MAX_COORDS.y, y);
Int2ObjectOpenHashMap<T> lookup = buildLookup(options);
var flagReader = new Object() {
boolean readFlag(int color, Set<T> values) {
T value = lookup.get(color);
return value != null && values.add(value);
}
};
return image -> {
int color = Color.abgrToArgb(image.getColor(x, y));
if (ColorHelper.Argb.getAlpha(color) < 255) {
return def;
}
@SuppressWarnings("unchecked")
Set<T> values = EnumSet.noneOf((Class<T>)def.def().getClass());
if (flagReader.readFlag(ColorHelper.Argb.getRed(color), values)
|| flagReader.readFlag(ColorHelper.Argb.getGreen(color), values)
|| flagReader.readFlag(ColorHelper.Argb.getBlue(color), values)) {
return new Flags<>(def.def(), values, color & 0x00FFFFFF);
}
return def;
};
}
if (Channel.ALPHA.readValue(x, y, image) < 255) {
return (T)def;
static <T extends TValue<T>> Int2ObjectOpenHashMap<T> buildLookup(T[] options) {
Int2ObjectOpenHashMap<T> lookup = new Int2ObjectOpenHashMap<>();
for (int i = 0; i < options.length; i++) {
lookup.put(options[i].colorCode(), options[i]);
}
return TriggerPixelType.getByTriggerPixel((T)def, color);
return lookup;
}
public <T extends Enum<T> & TriggerPixelType<T>> TriggerPixelType.Multiple<T> readFlags(NativeImage image) {
boolean[] out = new boolean[def.getClass().getEnumConstants().length];
readFlags(out, image);
return new TriggerPixelType.Multiple<>(readColor(image), (T)def, out);
T read(Mat image);
static boolean isTriggerPixelCoord(int x, int y) {
return x <= MAX_COORDS.x && y <= MAX_COORDS.y;
}
public <T extends Enum<T> & TriggerPixelType<T>> void readFlags(boolean[] out, NativeImage image) {
readFlag(out, Channel.RED, image);
readFlag(out, Channel.GREEN, image);
readFlag(out, Channel.BLUE, image);
interface Mat {
int getColor(int x, int y);
}
private <T extends Enum<T> & TriggerPixelType<T>> void readFlag(boolean[] out, Channel channel, NativeImage image) {
if (Channel.ALPHA.readValue(x, y, image) < 255) {
return;
}
T value = TriggerPixelType.getByTriggerPixel((T)def, channel.readValue(x, y, image));
out[value.ordinal()] |= value != def;
}
public static boolean isTriggerPixelCoord(int x, int y) {
return x <= MAX_READ_X && y <= MAX_READ_Y;
}
enum Channel {
RAW (0xFFFFFFFF, 0),
ALL (0x00FFFFFF, 0),
ALPHA(0x000000FF, 24),
RED (0x000000FF, 0),
GREEN(0x000000FF, 8),
BLUE (0x000000FF, 16);
private int mask;
private int offset;
Channel(int mask, int offset) {
this.mask = mask;
this.offset = offset;
}
public int readValue(int x, int y, NativeImage image) {
return (Color.abgrToArgb(image.getColor(x, y)) >> offset) & mask;
}
}
}

View file

@ -1,96 +0,0 @@
package com.minelittlepony.api.pony.meta;
import java.util.Arrays;
import java.util.List;
/**
* Interface for enums that can be parsed from an image trigger pixel value.
*/
public interface TriggerPixelType<T extends TriggerPixelType<T>> {
/**
* Gets the pixel colour matching this enum value.
*/
int colorCode();
/**
* Gets the pixel colour matching this enum value, adjusted to fill all three channels.
*/
default int getChannelAdjustedColorCode() {
return colorCode();
}
/**
* Gets a string representation of this value.
*/
default String name() {
return "[Numeric " + getHexValue() + "]";
}
default String getHexValue() {
return toHex(colorCode());
}
/**
* Returns a list of possible values this trigger pixel can accept.
*/
@SuppressWarnings("unchecked")
default List<TriggerPixelType<T>> getOptions() {
if (this instanceof Enum) {
// cast is required because gradle's compiler is more strict
return Arrays.asList(getClass().getEnumConstants());
}
return List.of();
}
default boolean matches(Object o) {
return equals(o);
}
/**
* Gets the enum value corresponding to the given enum type and pixel value.
* If none are found, the first parameter is returned as the default.
*
* @param type Return type and default value.
* @param pixelValue The pixel colour to search for.
*/
@SuppressWarnings("unchecked")
static <T extends TriggerPixelType<T>> T getByTriggerPixel(T type, int pixelValue) {
return (T)type.getOptions().stream()
.filter(i -> i.colorCode() == pixelValue)
.findFirst()
.orElse(type);
}
static <T extends TriggerPixelType<T>> TriggerPixelType<T> of(int color) {
return () -> color;
}
static String toHex(int color) {
String v = Integer.toHexString(color).toUpperCase();
while (v.length() < 6) {
v = "0" + v;
}
return "#" + v;
}
public record Multiple<T extends Enum<T> & TriggerPixelType<T>> (
int colorCode,
T def,
boolean[] value
) implements TriggerPixelType<T> {
@Override
public String name() {
return "[Flags " + Arrays.toString(value) + "]";
}
@Override
public List<TriggerPixelType<T>> getOptions() {
return def.getOptions();
}
@Override
public boolean matches(Object o) {
return o.getClass() == def.getClass() && value()[((Enum<?>)o).ordinal()];
}
}
}

View file

@ -1,14 +1,13 @@
package com.minelittlepony.api.pony.meta;
import net.minecraft.util.Identifier;
import com.minelittlepony.common.util.Color;
import net.minecraft.util.math.ColorHelper;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public enum Wearable implements TriggerPixelType<Wearable> {
public enum Wearable implements TValue<Wearable> {
NONE (0x00, null),
CROWN (0x16, new Identifier("minelittlepony", "textures/models/crown.png")),
MUFFIN (0x32, new Identifier("minelittlepony", "textures/models/muffin.png")),
@ -22,13 +21,11 @@ public enum Wearable implements TriggerPixelType<Wearable> {
private int triggerValue;
private final Identifier id;
private final Identifier texture;
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 = Arrays.stream(values()).collect(Collectors.toMap(Wearable::getId, Function.identity()));
public static final Flags<Wearable> EMPTY_FLAGS = Flags.of(Wearable.class);
public static final Flags<Wearable> EMPTY_FLAGS = Flags.of(NONE);
Wearable(int pixel, Identifier texture) {
triggerValue = pixel;
@ -55,6 +52,6 @@ public enum Wearable implements TriggerPixelType<Wearable> {
@Override
public int getChannelAdjustedColorCode() {
return triggerValue == 0 ? 0 : Color.argbToHex(255, triggerValue, triggerValue, triggerValue);
return triggerValue == 0 ? 0 : ColorHelper.Argb.getArgb(255, triggerValue, triggerValue, triggerValue);
}
}

View file

@ -1,38 +0,0 @@
package com.minelittlepony.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.client.model.armour.ArmourTextureResolver;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.util.settings.Setting;
import java.nio.file.Path;
class ClientPonyConfig extends PonyConfig {
/**
* Visibility mode for the horse button.
*/
public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO)
.addComment("Whether to show the mine little pony settings button on the main menu")
.addComment("AUTO (default) - only show when HDSkins is not installed")
.addComment("ON - always show")
.addComment("OFF - never show");
public ClientPonyConfig(Path path) {
super(path);
MobRenderers.REGISTRY.values().forEach(r -> value("entities", r.name, true));
disablePonifiedArmour.onChanged(t -> ArmourTextureResolver.INSTANCE.invalidate());
}
@Override
public void save() {
super.save();
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null) {
player.calculateDimensions();
}
}
}

View file

@ -1,8 +1,10 @@
package com.minelittlepony.client;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.events.Channel;
import com.minelittlepony.api.pony.PonyManager;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.armour.ArmourTextureResolver;
import com.minelittlepony.client.render.MobRenderers;
import com.minelittlepony.client.render.PonyRenderDispatcher;
import com.minelittlepony.common.client.gui.VisibilityMode;
import com.minelittlepony.common.client.gui.element.Button;
@ -12,6 +14,8 @@ import com.minelittlepony.common.event.ScreenInitCallback;
import com.minelittlepony.common.event.SkinFilterCallback;
import com.minelittlepony.common.util.GamePaths;
import java.nio.file.Path;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
@ -22,6 +26,7 @@ import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager;
@ -37,7 +42,6 @@ public class MineLittlePony implements ClientModInitializer {
public static final Logger logger = LogManager.getLogger("MineLittlePony");
private ClientPonyConfig config;
private PonyManagerImpl ponyManager;
private VariatedTextureSupplier variatedTextures;
@ -64,7 +68,7 @@ public class MineLittlePony implements ClientModInitializer {
hasHdSkins = FabricLoader.getInstance().isModLoaded("hdskins");
hasModMenu = FabricLoader.getInstance().isModLoaded("modmenu");
config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json"));
PonyConfig config = new ClientPonyConfig(GamePaths.getConfigDirectory().resolve("minelp.json"));
ponyManager = new PonyManagerImpl(config);
variatedTextures = new VariatedTextureSupplier();
@ -108,7 +112,7 @@ public class MineLittlePony implements ClientModInitializer {
private void onScreenInit(Screen screen, ScreenInitCallback.ButtonList buttons) {
if (screen instanceof TitleScreen) {
VisibilityMode mode = config.horseButton.get();
VisibilityMode mode = ClientPonyConfig.getInstance().horseButton.get();
boolean show = mode == VisibilityMode.ON || (mode == VisibilityMode.AUTO
&& !(hasHdSkins || hasModMenu
));
@ -129,7 +133,7 @@ public class MineLittlePony implements ClientModInitializer {
}
}
public PonyManager getManager() {
public PonyManagerImpl getManager() {
return ponyManager;
}
@ -143,5 +147,22 @@ public class MineLittlePony implements ClientModInitializer {
public PonyRenderDispatcher getRenderDispatcher() {
return renderDispatcher;
}
private static final class ClientPonyConfig extends PonyConfig {
public ClientPonyConfig(Path path) {
super(path);
MobRenderers.REGISTRY.values().forEach(r -> value("entities", r.name, true));
disablePonifiedArmour.onChanged(t -> ArmourTextureResolver.INSTANCE.invalidate());
}
@Override
public void save() {
super.save();
PlayerEntity player = MinecraftClient.getInstance().player;
if (player != null) {
player.calculateDimensions();
}
}
}
}

View file

@ -6,7 +6,6 @@ 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;
@ -53,16 +52,7 @@ class PonyDataLoader {
}).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
));
callback.accept(new PonyData(image, noSkin));
}, e -> {
MineLittlePony.logger.fatal("Unable to read {} metadata", identifier, e);
callback.accept(PonyData.NULL);

View file

@ -9,10 +9,10 @@ import com.minelittlepony.client.render.blockentity.skull.PonySkullRenderer;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.util.DefaultSkinHelper;
import net.minecraft.resource.ResourceManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
@ -22,25 +22,18 @@ import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* The PonyManager is responsible for reading and recoding all the pony data associated with an entity of skin.
*/
class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadListener {
public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadListener {
private static final Identifier ID = new Identifier("minelittlepony", "background_ponies");
private final PonyConfig config;
private final LoadingCache<Identifier, Pony> defaultedPoniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(resource -> {
return new Pony(resource, PonyDataLoader.parse(resource, true));
}));
.build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, true))));
private final LoadingCache<Identifier, Pony> poniesCache = CacheBuilder.newBuilder()
.expireAfterAccess(30, TimeUnit.SECONDS)
.build(CacheLoader.from(resource -> {
return new Pony(resource, PonyDataLoader.parse(resource, false));
}));
.build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, false))));
public PonyManagerImpl(PonyConfig config) {
this.config = config;
@ -56,78 +49,62 @@ class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceReloadLis
}
@Override
public Pony getPony(Identifier resource) {
return loadPony(resource, false);
public Pony getPony(PlayerEntity player) {
clearCache();
return getPony(getSkin(player), player instanceof ForcedPony ? null : player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId());
}
@Override
public Optional<Pony> getPony(@Nullable Entity entity) {
public Optional<Pony> getPony(LivingEntity entity) {
if (entity instanceof PlayerEntity player) {
return Optional.of(getPony(player));
}
if (entity instanceof LivingEntity living) {
return Optional.ofNullable(MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(living)).map(d -> d.getEntityPony(living));
}
return Optional.empty();
Identifier skin = getSkin(entity);
return skin == null ? Optional.empty() : Optional.of(getPony(skin, null));
}
@Override
public Pony getPony(PlayerEntity player) {
Identifier skin = getSkin(player);
UUID uuid = player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId();
if (skin != null) {
if (player instanceof PonyManager.ForcedPony) {
return getPony(skin);
}
return getPony(skin, uuid);
public Pony getPony(@Nullable Identifier resource, @Nullable UUID uuid) {
if (resource == null) {
return uuid == null ? loadPony(DefaultSkinHelper.getTexture(), true) : getBackgroundPony(uuid);
}
if (config.ponyLevel.get() == PonyLevel.PONIES) {
Pony pony = loadPony(resource, false);
if (uuid != null && PonyConfig.getInstance().ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) {
return getBackgroundPony(uuid);
}
return loadPony(DefaultSkinHelper.getTexture(uuid).texture(), true);
}
@Override
public Pony getPony(Identifier resource, UUID uuid) {
Pony pony = getPony(resource);
if (config.ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) {
return getBackgroundPony(uuid);
}
return pony;
}
@Override
public Pony getBackgroundPony(UUID uuid) {
return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getTexture(uuid).texture()), true);
public Pony getBackgroundPony(@Nullable UUID uuid) {
if (config.ponyLevel.get() == PonyLevel.PONIES) {
return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getTexture(uuid).texture()), true);
}
return loadPony(DefaultSkinHelper.getTexture(uuid).texture(), true);
}
@Nullable
private Identifier getSkin(PlayerEntity player) {
if (player.getGameProfile() == null) {
return null;
}
if (player instanceof AbstractClientPlayerEntity) {
return ((AbstractClientPlayerEntity)player).method_52814().texture();
private Identifier getSkin(LivingEntity entity) {
if (entity instanceof PlayerEntity player) {
if (player.getGameProfile() != null && player instanceof AbstractClientPlayerEntity clientPlayer) {
return clientPlayer.method_52814().texture();
}
} else {
if (MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(entity) != null) {
return MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity).getTexture(entity);
}
}
return null;
}
@Override
public void removePony(Identifier resource) {
poniesCache.invalidate(resource);
defaultedPoniesCache.invalidate(resource);
}
@Override
public void clearCache() {
MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size());
poniesCache.invalidateAll();

View file

@ -35,7 +35,7 @@ public class PonySettingsscreen extends GameGui {
public static final Text SCALE_SHOW = Text.translatable("minelp.debug.scale.sa");
public static final Text SCALE_MIN = Text.translatable("minelp.debug.scale.min");
private ClientPonyConfig config;
private final PonyConfig config = PonyConfig.getInstance();
private final ScrollContainer content = new ScrollContainer();
@ -43,9 +43,6 @@ public class PonySettingsscreen extends GameGui {
public PonySettingsscreen(@Nullable Screen parent) {
super(Text.literal(OPTIONS_PREFIX + "title"), parent);
config = (ClientPonyConfig)PonyConfig.getInstance();
content.margin.top = 30;
content.margin.bottom = 30;
content.getContentPadding().top = 10;

View file

@ -1,6 +1,5 @@
package com.minelittlepony.client.compat.hdskins;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.PonySettingsscreen;
import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.common.client.gui.dimension.Bounds;
@ -29,13 +28,13 @@ class GuiSkinsMineLP extends GuiSkins {
chooser.addSkinChangedEventListener(type -> {
MineLittlePony.logger.debug("Invalidating old local skin, checking updated local skin");
if (type == SkinType.SKIN) {
Pony.getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId());
MineLittlePony.getInstance().getManager().removePony(previewer.getLocal().getSkins().get(SkinType.SKIN).getId());
}
});
uploader.addSkinLoadedEventListener((type, location, profileTexture) -> {
MineLittlePony.logger.debug("Invalidating old remote skin, checking updated remote skin");
if (type == SkinType.SKIN) {
Pony.getManager().removePony(location);
MineLittlePony.getInstance().getManager().removePony(location);
}
});
}

View file

@ -4,7 +4,7 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.TriggerPixelType;
import com.minelittlepony.api.pony.meta.TValue;
import com.minelittlepony.common.client.gui.ITextContext;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.hdskins.client.gui.Carousel;
@ -37,7 +37,7 @@ class LegendOverlayWidget implements Carousel.Element, ITextContext {
});
}
private void drawLegendBlock(DrawContext context, int index, int x, int y, int mouseX, int mouseY, String key, TriggerPixelType<?> value) {
private void drawLegendBlock(DrawContext context, int index, int x, int y, int mouseX, int mouseY, String key, TValue<?> value) {
context.fill(0, 0, LEGEND_BLOCK_BOUNDS.width, LEGEND_BLOCK_BOUNDS.height, 0xFF003333);
context.fill(1, 1, LEGEND_BLOCK_BOUNDS.width - 1, LEGEND_BLOCK_BOUNDS.height - 1, value.colorCode() | 0xFF000000);

View file

@ -43,7 +43,7 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
SkinsProxy.instance = this;
seaponySkinType = SkinType.register(AquaticPlayerPonyRenderer.SKIN_TYPE_ID, Items.COD_BUCKET.getDefaultStack());
Wearable.VALUES.forEach(wearable -> {
Wearable.REGISTRY.values().forEach(wearable -> {
if (wearable != Wearable.NONE) {
wearableTypes.put(SkinType.register(wearable.getId(), Items.BUNDLE.getDefaultStack()), wearable);
}
@ -100,7 +100,7 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
PlayerSkin main = dummy.getTextures().get(SkinType.SKIN);
Wearable wearable = Wearable.REGISTRY.getOrDefault(type.getId(), Wearable.NONE);
PonyData metadata = Pony.getManager().getPony(main.getId()).metadata();
if (wearable != Wearable.NONE && metadata.isWearing(wearable)) {
if (wearable != Wearable.NONE && metadata.gear().matches(wearable)) {
if (wearable.isSaddlebags() && metadata.race().supportsLegacySaddlebags()) {
return Optional.of(main.getId());

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.model;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.events.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.client.util.render.RenderList;
import com.minelittlepony.util.MathUtil;
@ -450,10 +450,10 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
arm.pivotX -= 6 * sigma;
arm.pivotZ -= 2;
}
if (getSize() == Sizes.TALL) {
if (getSize() == SizePreset.TALL) {
arm.pivotY += 1;
}
if (getSize() == Sizes.FOAL) {
if (getSize() == SizePreset.FOAL) {
arm.pivotY -= 2;
}
@ -558,7 +558,7 @@ public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPo
@Override
public float getRiderYOffset() {
switch ((Sizes)getSize()) {
switch ((SizePreset)getSize()) {
case NORMAL: return 0.4F;
case FOAL:
case TALL:

View file

@ -13,7 +13,7 @@ import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyData;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.mson.api.model.biped.MsonPlayer;
/**
@ -79,7 +79,7 @@ public abstract class ClientPonyModel<T extends LivingEntity> extends MsonPlayer
@Override
public Size getSize() {
return child ? Sizes.FOAL : PonyModel.super.getSize();
return child ? SizePreset.FOAL : PonyModel.super.getSize();
}
@Override

View file

@ -3,7 +3,7 @@ package com.minelittlepony.client.model.entity.race;
import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.api.pony.meta.SizePreset;
import com.minelittlepony.client.model.part.UnicornHorn;
import com.minelittlepony.client.util.render.RenderList;
import com.minelittlepony.mson.api.ModelView;
@ -101,9 +101,9 @@ public class UnicornModel<T extends LivingEntity> extends EarthPonyModel<T> impl
float x = 0.3F;
float z = -0.4F;
if (size == Sizes.TALL || size == Sizes.YEARLING) {
if (size == SizePreset.TALL || size == SizePreset.YEARLING) {
z += 0.05F;
} else if (size == Sizes.FOAL) {
} else if (size == SizePreset.FOAL) {
x -= 0.1F;
z -= 0.1F;
}

View file

@ -59,7 +59,7 @@ public class SaddleBags extends WearableGear {
strap.visible = wearable == Wearable.SADDLE_BAGS_BOTH;
dropAmount = hangLow ? 0.15F : 0;
dropAmount = model.getAttributes().metadata.getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3);
dropAmount = model.getAttributes().getMainInterpolator().interpolate("dropAmount", dropAmount, 3);
}
@Override

View file

@ -26,7 +26,7 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
private ModelWrapper<T, M> playerModel;
private final IPonyRenderContext<T, M> renderer;
private final PonyRenderContext<T, M> renderer;
private final FrustrumCheck<T> frustrum = new FrustrumCheck<>(this);
@ -34,11 +34,11 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
RenderSystem.disableBlend();
}
public EquineRenderManager(IPonyRenderContext<T, M> renderer) {
public EquineRenderManager(PonyRenderContext<T, M> renderer) {
this.renderer = renderer;
}
public IPonyRenderContext<T, M> getContext() {
public PonyRenderContext<T, M> getContext() {
return renderer;
}
@ -95,7 +95,7 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
if (entity.hasVehicle() && entity.getVehicle() instanceof LivingEntity) {
LivingEntity ridingEntity = (LivingEntity) entity.getVehicle();
IPonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(ridingEntity);
PonyRenderContext<LivingEntity, ?> renderer = MineLittlePony.getInstance().getRenderDispatcher().getPonyRenderer(ridingEntity);
if (renderer != null) {
// negate vanilla translations so the rider begins at the ridees feet.
@ -141,6 +141,10 @@ public class EquineRenderManager<T extends LivingEntity, M extends EntityModel<T
return getModel().getSize().scaleFactor();
}
public float getShadowSize() {
return getModel().getSize().shadowSize();
}
public double getNamePlateYOffset(T entity) {
// We start by negating the height calculation done by mahjong.

View file

@ -10,7 +10,7 @@ import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
public interface IPonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
public interface PonyRenderContext<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends Gear.Context<T, M> {
Pony getEntityPony(T entity);

View file

@ -6,8 +6,8 @@ import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.mixin.MixinEntityRenderers;
import com.minelittlepony.client.render.entity.PlayerPonyRenderer;
import com.minelittlepony.client.render.entity.AquaticPlayerPonyRenderer;
import com.minelittlepony.client.render.entity.PlayerPonyRenderer;
import org.jetbrains.annotations.Nullable;
@ -83,15 +83,15 @@ public class PonyRenderDispatcher {
@SuppressWarnings("unchecked")
@Nullable
public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> IPonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) {
public <T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> PonyRenderContext<T, M> getPonyRenderer(@Nullable T entity) {
if (entity == null) {
return null;
}
EntityRenderer<?> renderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity);
if (renderer instanceof IPonyRenderContext) {
return (IPonyRenderContext<T, M>) renderer;
if (renderer instanceof PonyRenderContext) {
return (PonyRenderContext<T, M>) renderer;
}
return null;

View file

@ -5,7 +5,7 @@ import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.render.entity.npc.textures.TextureSupplier;
@ -27,7 +27,7 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements IPonyRenderContext<T, M> {
public abstract class AbstractPonyRenderer<T extends MobEntity, M extends EntityModel<T> & PonyModel<T> & ModelWithArms> extends MobEntityRenderer<T, M> implements PonyRenderContext<T, M> {
protected final EquineRenderManager<T, M> manager = new EquineRenderManager<>(this);
@ -91,7 +91,7 @@ public abstract class AbstractPonyRenderer<T extends MobEntity, M extends Entity
@Override
public void scale(T entity, MatrixStack stack, float tickDelta) {
shadowRadius = manager.getModel().getSize().shadowSize();
shadowRadius = manager.getShadowSize();
if (entity.isBaby()) {
shadowRadius *= 3; // undo vanilla shadow scaling

View file

@ -69,12 +69,11 @@ public class AquaticPlayerPonyRenderer extends PlayerPonyRenderer {
}
private void updateSeaponyState(AbstractClientPlayerEntity player) {
Pony pony = getEntityPony(player);
wet = PonyPosture.isSeaponyModifier(player);
if (!(player instanceof PreviewModel)) {
float state = wet ? 100 : 0;
float interpolated = pony.metadata().getInterpolator(player.getUuid()).interpolate("seapony_state", state, 5);
float interpolated = getInternalRenderer().getModel().getAttributes().getMainInterpolator().interpolate("seapony_state", state, 5);
if (!MathUtil.compareFloats(interpolated, state)) {
double x = player.getEntityWorld().getRandom().nextTriangular(player.getX(), 1);

View file

@ -8,7 +8,7 @@ import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.*;
import com.minelittlepony.client.render.DebugBoundingBoxRenderer;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.feature.*;
import com.minelittlepony.client.util.render.RenderLayerUtil;
@ -29,7 +29,7 @@ import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> {
public class PlayerPonyRenderer extends PlayerEntityRenderer implements PonyRenderContext<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> {
protected final EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager = new EquineRenderManager<>(this);
@ -81,7 +81,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
Pony pony = getEntityPony(entity);
model = manager.setModel(modelsCache.apply(getPlayerRace(entity, pony))).body();
// EntityModelFeatures: We have to force it to use our models otherwise EMF overrides it and breaks pony rendering
shadowRadius = manager.getModel().getSize().shadowSize();
shadowRadius = manager.getShadowSize();
super.render(entity, entityYaw, tickDelta, stack, renderContext, lightUv);
DebugBoundingBoxRenderer.render(pony, this, entity, stack, renderContext, tickDelta);
@ -89,7 +89,7 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
// (shadows are drawn after us)
if (!entity.hasVehicle() && !entity.isSleeping()) {
float yaw = MathHelper.lerpAngleDegrees(tickDelta, entity.prevBodyYaw, entity.bodyYaw);
float l = entity.getWidth() / 2 * pony.size().scaleFactor();
float l = entity.getWidth() / 2 * manager.getScaleFactor();
stack.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw));
stack.translate(0, 0, -l);

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRenderer;
@ -13,10 +13,10 @@ import net.minecraft.entity.LivingEntity;
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 PonyRenderContext<T, M> context;
@SuppressWarnings("unchecked")
public AbstractPonyFeature(IPonyRenderContext<T, M> context) {
public AbstractPonyFeature(PonyRenderContext<T, M> context) {
super((FeatureRendererContext<T, M>)context);
this.context = context;
}
@ -39,7 +39,7 @@ public abstract class AbstractPonyFeature<T extends LivingEntity, M extends Enti
public abstract void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch);
@SuppressWarnings("unchecked")
protected <C extends IPonyRenderContext<T, M> & FeatureRendererContext<T, M>> C getContext() {
protected <C extends PonyRenderContext<T, M> & FeatureRendererContext<T, M>> C getContext() {
return (C)context;
}

View file

@ -3,7 +3,7 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.ModelWrapper;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.common.util.Color;
import net.minecraft.client.MinecraftClient;
@ -22,7 +22,7 @@ import net.minecraft.util.Identifier;
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(PonyRenderContext<T, M> context, BakedModelManager bakery) {
super(context);
}

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture;
@ -17,7 +17,7 @@ import net.minecraft.entity.EquipmentSlot;
public class CapeFeature<M extends ClientPonyModel<AbstractClientPlayerEntity>> extends AbstractPonyFeature<AbstractClientPlayerEntity, M> {
public CapeFeature(IPonyRenderContext<AbstractClientPlayerEntity, M> context) {
public CapeFeature(PonyRenderContext<AbstractClientPlayerEntity, M> context) {
super(context);
}

View file

@ -11,13 +11,13 @@ import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.DJPon3EarsModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
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();
public DJPon3Feature(IPonyRenderContext<T, M> context) {
public DJPon3Feature(PonyRenderContext<T, M> context) {
super(context);
}

View file

@ -5,7 +5,7 @@ import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.PonyElytra;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture;
@ -29,7 +29,7 @@ public class ElytraFeature<T extends LivingEntity, M extends EntityModel<T> & Po
@SuppressWarnings("unchecked")
private final PonyElytra<T> modelElytra = (PonyElytra<T>)ModelType.ELYTRA.createModel();
public ElytraFeature(IPonyRenderContext<T, M> rp) {
public ElytraFeature(PonyRenderContext<T, M> rp) {
super(rp);
}

View file

@ -15,7 +15,7 @@ import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.model.gear.Gear;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import java.util.*;
import java.util.concurrent.TimeUnit;
@ -42,7 +42,7 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & Pony
return randomizedOrder;
}));
public GearFeature(IPonyRenderContext<T, M> renderer) {
public GearFeature(PonyRenderContext<T, M> renderer) {
super(renderer);
}

View file

@ -8,13 +8,13 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
public class GlowingEyesFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends EyesFeatureRenderer<T, M> {
private final RenderLayer layer;
public <V extends FeatureRendererContext<T, M> & IPonyRenderContext<T, M> & IGlowingRenderer> GlowingEyesFeature(V renderer) {
public <V extends FeatureRendererContext<T, M> & PonyRenderContext<T, M> & IGlowingRenderer> GlowingEyesFeature(V renderer) {
super(renderer);
layer = RenderLayer.getEyes(renderer.getEyeTexture());
}

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
@ -18,10 +18,10 @@ import net.minecraft.util.Arm;
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 PonyRenderContext<T, M> context;
@SuppressWarnings("unchecked")
public HeldItemFeature(IPonyRenderContext<T, M> context, HeldItemRenderer renderer) {
public HeldItemFeature(PonyRenderContext<T, M> context, HeldItemRenderer renderer) {
super((FeatureRendererContext<T, M>)context, renderer);
this.context = context;
}

View file

@ -6,11 +6,11 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.mob.IllagerEntity;
import com.minelittlepony.client.model.entity.race.AlicornModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
public class IllagerHeldItemFeature<T extends IllagerEntity, M extends AlicornModel<T>> extends HeldItemFeature<T, M> {
public IllagerHeldItemFeature(IPonyRenderContext<T,M> livingPony, HeldItemRenderer renderer) {
public IllagerHeldItemFeature(PonyRenderContext<T,M> livingPony, HeldItemRenderer renderer) {
super(livingPony, renderer);
}

View file

@ -17,7 +17,7 @@ import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import java.util.Optional;
@ -25,7 +25,7 @@ public class PassengerFeature<T extends PlayerEntity, M extends ClientPonyModel<
private final ParrotEntityModel model;
public PassengerFeature(IPonyRenderContext<T, M> renderer, EntityRendererFactory.Context context) {
public PassengerFeature(PonyRenderContext<T, M> renderer, EntityRendererFactory.Context context) {
super(renderer);
model = new ParrotEntityModel(context.getPart(EntityModelLayers.PARROT));
}

View file

@ -3,7 +3,7 @@ package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import com.mojang.authlib.GameProfile;
import java.util.Map;
@ -34,7 +34,7 @@ public class SkullFeature<T extends LivingEntity, M extends EntityModel<T> & Pon
private final Map<SkullBlock.SkullType, SkullBlockEntityModel> headModels;
public SkullFeature(IPonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader) {
public SkullFeature(PonyRenderContext<T, M> renderPony, EntityModelLoader entityModelLoader) {
super(renderPony);
headModels = SkullBlockEntityRenderer.getModels(entityModelLoader);
}

View file

@ -20,17 +20,12 @@ import com.minelittlepony.client.render.entity.npc.textures.*;
import java.util.*;
abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer> extends PonyRenderer<T, ClientPonyModel<T>> {
private final String entityType;
private final Map<Race, ModelWrapper<T, ClientPonyModel<T>>> models = new EnumMap<>(Race.class);
private final NpcClothingFeature<T, ClientPonyModel<T>, AbstractNpcRenderer<T>> clothing;
public AbstractNpcRenderer(EntityRendererFactory.Context context, String type, TextureSupplier<T> textureSupplier, TextureSupplier<String> formatter) {
super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), new SillyPonyTextureSupplier<>(textureSupplier, formatter));
entityType = type;
clothing = new NpcClothingFeature<>(this, entityType);
super(context, ModelType.getPlayerModel(Race.EARTH).getKey(false), SillyPonyTextureSupplier.create(textureSupplier, formatter));
clothing = new NpcClothingFeature<>(this, type);
addFeature(clothing);
}
@ -42,12 +37,9 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
@Override
public boolean shouldRender(ClientPonyModel<T> model, T entity, Wearable wearable, Gear gear) {
boolean special = SillyPonyTextureSupplier.isBestPony(entity);
if (wearable == Wearable.SADDLE_BAGS_BOTH) {
VillagerProfession profession = entity.getVillagerData().getProfession();
return !special && profession != VillagerProfession.NONE && (
return !SillyPonyTextureSupplier.isBestPony(entity) && profession != VillagerProfession.NONE && (
profession == VillagerProfession.CARTOGRAPHER
|| profession == VillagerProfession.FARMER
|| profession == VillagerProfession.FISHERMAN

View file

@ -17,7 +17,7 @@ import net.minecraft.village.VillagerProfession;
import net.minecraft.village.VillagerType;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.client.render.IPonyRenderContext;
import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.feature.AbstractPonyFeature;
import com.minelittlepony.client.util.render.TextureFlattener;
import com.minelittlepony.util.ResourceUtil;
@ -27,7 +27,7 @@ import java.util.*;
class NpcClothingFeature<
T extends LivingEntity & VillagerDataContainer,
M extends EntityModel<T> & PonyModel<T>,
C extends FeatureRendererContext<T, M> & IPonyRenderContext<T, M>> extends AbstractPonyFeature<T, M> {
C extends FeatureRendererContext<T, M> & PonyRenderContext<T, M>> extends AbstractPonyFeature<T, M> {
private static final Int2ObjectMap<Identifier> LEVEL_TO_ID = Util.make(new Int2ObjectOpenHashMap<>(), a -> {
a.put(1, new Identifier("stone"));

View file

@ -1,7 +1,6 @@
package com.minelittlepony.client.render.entity.npc;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.util.math.MathHelper;
@ -10,12 +9,10 @@ import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.*;
public class VillagerPonyRenderer extends AbstractNpcRenderer<VillagerEntity> {
private static final String TYPE = "villager";
private static final TextureSupplier<String> FORMATTER = TextureSupplier.formatted("minelittlepony", "textures/entity/villager/%s.png");
public VillagerPonyRenderer(EntityRendererFactory.Context context) {
super(context, TYPE,
super(context, "villager",
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER))), FORMATTER);
}
@ -25,9 +22,7 @@ public class VillagerPonyRenderer extends AbstractNpcRenderer<VillagerEntity> {
model.onSetModelAngles((m, move, swing, ticks, entity) -> {
m.getAttributes().visualHeight += SillyPonyTextureSupplier.isCrownPony(entity) ? 0.3F : -0.1F;
boolean isHeadRolling = entity instanceof MerchantEntity && ((MerchantEntity)entity).getHeadRollingTimeLeft() > 0;
if (isHeadRolling) {
if (entity.getHeadRollingTimeLeft() > 0) {
m.head.yaw = 0.3F * MathHelper.sin(0.45F * ticks);
}
});

View file

@ -11,12 +11,10 @@ import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.npc.textures.*;
public class ZomponyVillagerRenderer extends AbstractNpcRenderer<ZombieVillagerEntity> {
private static final String TYPE = "zombie_villager";
private static final TextureSupplier<String> FORMATTER = TextureSupplier.formatted("minelittlepony", "textures/entity/zombie_villager/zombie_%s.png");
public ZomponyVillagerRenderer(EntityRendererFactory.Context context) {
super(context, TYPE,
super(context, "zombie_villager",
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_ZOMPONIES_POOL,
TextureSupplier.ofPool(VariatedTextureSupplier.BACKGROUND_PONIES_POOL,
PlayerTextureSupplier.create(ProfessionTextureSupplier.create(FORMATTER)))),

View file

@ -5,8 +5,6 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.pony.Pony;
import com.minelittlepony.client.SkinsProxy;
@ -15,31 +13,20 @@ import java.util.function.Function;
public class PlayerTextureSupplier {
public static <T extends LivingEntity> TextureSupplier<T> create(TextureSupplier<T> fallback) {
Function<String, Entry> customNameCache = Util.memoize(Entry::new);
Function<String, CompletableFuture<Identifier>> customNameCache = Util.memoize(name -> {
return SkullBlockEntity.fetchProfile(name).thenApply(profile -> {
return profile
.map(p -> SkinsProxy.instance.getSkinTexture(p))
.filter(skin -> !Pony.getManager().getPony(skin).race().isHuman())
.orElse(null);
});
});
return entity -> {
Identifier override = entity.hasCustomName() ? customNameCache.apply(entity.getCustomName().getString()).getTexture() : null;
Identifier override = entity.hasCustomName() ? customNameCache.apply(entity.getCustomName().getString()).getNow(null) : null;
if (override != null) {
return override;
}
return fallback.apply(entity);
};
}
static final class Entry {
private final CompletableFuture<Identifier> profile;
Entry(String name) {
profile = SkullBlockEntity.fetchProfile(name).thenApply(profile -> {
return profile
.map(p -> SkinsProxy.instance.getSkinTexture(p))
.filter(skin -> !Pony.getManager().getPony(skin).race().isHuman())
.orElse(null);
});
}
@Nullable
public Identifier getTexture() {
return profile.getNow(null);
}
}
}

View file

@ -4,22 +4,11 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import net.minecraft.village.VillagerDataContainer;
public class SillyPonyTextureSupplier<T extends LivingEntity & VillagerDataContainer> implements TextureSupplier<T> {
private final TextureSupplier<T> fallback;
private final Identifier egg;
private final Identifier egg2;
public SillyPonyTextureSupplier(TextureSupplier<T> fallback, TextureSupplier<String> formatter) {
this.fallback = fallback;
this.egg = formatter.apply("silly_pony");
this.egg2 = formatter.apply("tiny_silly_pony");
}
@Override
public Identifier apply(T entity) {
return isBestPony(entity) ? (entity.isBaby() ? egg2 : egg) : fallback.apply(entity);
public class SillyPonyTextureSupplier {
public static <T extends LivingEntity & VillagerDataContainer> TextureSupplier<T> create(TextureSupplier<T> fallback, TextureSupplier<String> formatter) {
Identifier egg = formatter.apply("silly_pony");
Identifier egg2 = formatter.apply("tiny_silly_pony");
return entity -> isBestPony(entity) ? (entity.isBaby() ? egg2 : egg) : fallback.apply(entity);
}
public static boolean isBestPony(LivingEntity entity) {

View file

@ -6,7 +6,7 @@ import net.minecraft.util.math.Vec3d;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.PonyModel;
import com.minelittlepony.api.pony.meta.Size;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.api.pony.meta.SizePreset;
import java.util.Arrays;
import java.util.Map;
@ -15,7 +15,7 @@ import java.util.stream.Collectors;
public enum PonyTransformation {
NORMAL(Sizes.NORMAL, 0, 3F, 0.75F) {
NORMAL(SizePreset.NORMAL, 0, 3F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.3F, 0);
@ -37,7 +37,7 @@ public enum PonyTransformation {
}
}
},
LANKY(Sizes.LANKY, 0, 2.6F, 0.75F) {
LANKY(SizePreset.LANKY, 0, 2.6F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.2F, 0);
@ -73,7 +73,7 @@ public enum PonyTransformation {
}
}
},
BULKY(Sizes.BULKY, 0, 2.3F, 0.75F) {
BULKY(SizePreset.BULKY, 0, 2.3F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
@ -108,7 +108,7 @@ public enum PonyTransformation {
}
}
},
FOAL(Sizes.FOAL, 0, 3.8F, 0.75F) {
FOAL(SizePreset.FOAL, 0, 3.8F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.9F, 0);
@ -138,7 +138,7 @@ public enum PonyTransformation {
}
}
},
TALL(Sizes.TALL, 0, 2.2F, 0.75F) {
TALL(SizePreset.TALL, 0, 2.2F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isCrouching) stack.translate(0, -0.15F, 0);
@ -170,7 +170,7 @@ public enum PonyTransformation {
}
}
},
YEARLING(Sizes.YEARLING, 0, 3.8F, 0.75F) {
YEARLING(SizePreset.YEARLING, 0, 3.8F, 0.75F) {
@Override
public void transform(PonyModel<?> model, BodyPart part, MatrixStack stack) {
if (model.getAttributes().isSwimming) stack.translate(0, -0.6F, 0);
@ -205,12 +205,12 @@ public enum PonyTransformation {
}
};
private static final Map<Sizes, PonyTransformation> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(i -> i.size, Function.identity()));
private static final Map<Size, PonyTransformation> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(i -> i.size, Function.identity()));
private final Sizes size;
private final Size size;
private final Vec3d riderOffset;
PonyTransformation(Sizes size, float rX, float rY, float rZ) {
PonyTransformation(Size size, float rX, float rY, float rZ) {
this.size = size;
riderOffset = new Vec3d(rX, rY, rZ);
}

View file

@ -5,6 +5,7 @@ import net.minecraft.client.texture.*;
import net.minecraft.resource.Resource;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.TriggerPixel;
import com.mojang.blaze3d.systems.RenderSystem;
import java.io.InputStream;
@ -86,11 +87,11 @@ public class NativeUtil {
}
}
public static void parseImage(Identifier resource, Consumer<NativeImage> consumer, Consumer<Exception> fail) {
public static void parseImage(Identifier resource, Consumer<TriggerPixel.Mat> consumer, Consumer<Exception> fail) {
parseImage(resource, consumer, fail, 0);
}
private static void parseImage(Identifier resource, Consumer<NativeImage> consumer, Consumer<Exception> fail, int attempt) {
private static void parseImage(Identifier resource, Consumer<TriggerPixel.Mat> consumer, Consumer<Exception> fail, int attempt) {
try {
if (!RenderSystem.isOnRenderThread()) {
RenderSystem.recordRenderCall(() -> parseImage(resource, consumer, fail, attempt));
@ -105,7 +106,7 @@ public class NativeUtil {
if (loadedTexture instanceof NativeImageBackedTexture nibt) {
NativeImage image = nibt.getImage();
if (image != null) {
consumer.accept(image);
consumer.accept(image::getColor);
return;
}
}
@ -113,7 +114,7 @@ public class NativeUtil {
Resource res = mc.getResourceManager().getResource(resource).orElse(null);
if (res != null) {
try (InputStream inputStream = res.getInputStream()){
consumer.accept(NativeImage.read(inputStream));
consumer.accept(NativeImage.read(inputStream)::getColor);
return;
}
}
@ -124,7 +125,7 @@ public class NativeUtil {
}
}
private static void __reconstructNativeImage(Identifier resource, Consumer<NativeImage> consumer, Consumer<Exception> fail, int attempt) {
private static void __reconstructNativeImage(Identifier resource, Consumer<TriggerPixel.Mat> consumer, Consumer<Exception> fail, int attempt) {
MinecraftClient mc = MinecraftClient.getInstance();
TextureManager textures = mc.getTextureManager();
@ -156,7 +157,7 @@ public class NativeUtil {
// This allocates a new array to store the image every time.
// Don't do this every time. Keep a cache and store it so we don't destroy memory.
image.loadFromTextureImage(0, false);
consumer.accept(image);
consumer.accept(image::getColor);
}
}
}