Players can now upload a texture to use for each type of wearable

This commit is contained in:
Sollace 2022-12-10 19:36:55 +00:00
parent 2cbdc7477c
commit e54b29146a
22 changed files with 219 additions and 192 deletions

View file

@ -84,6 +84,14 @@ public interface IModel {
* Tests if this model is wearing the given piece of gear. * Tests if this model is wearing the given piece of gear.
*/ */
default boolean isWearing(Wearable wearable) { default boolean isWearing(Wearable wearable) {
return isEmbedded(wearable) || getAttributes().featureSkins.contains(wearable.getId());
}
/**
* Tests if the chosen piece of gear is sourcing its texture from the main skin.
* i.e. Used to change wing rendering when using saddlebags.
*/
default boolean isEmbedded(Wearable wearable) {
return getMetadata().isWearing(wearable); return getMetadata().isWearing(wearable);
} }
} }

View file

@ -2,16 +2,18 @@ package com.minelittlepony.api.model;
import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.PonyPosture; import com.minelittlepony.api.pony.PonyPosture;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.util.MathUtil; import com.minelittlepony.util.MathUtil;
import java.util.*;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import java.util.UUID;
import static com.minelittlepony.api.model.PonyModelConstants.ROTATE_270; import static com.minelittlepony.api.model.PonyModelConstants.ROTATE_270;
import static com.minelittlepony.api.model.PonyModelConstants.WING_ROT_Z_SNEAK; import static com.minelittlepony.api.model.PonyModelConstants.WING_ROT_Z_SNEAK;
import static com.minelittlepony.api.model.PonyModelConstants.WING_ROT_Z_FLYING; import static com.minelittlepony.api.model.PonyModelConstants.WING_ROT_Z_FLYING;
@ -95,6 +97,11 @@ public class ModelAttributes {
*/ */
public float wingAngle; public float wingAngle;
/**
* Contains a list of additional skins available for rendering.
*/
public Set<Identifier> featureSkins = new HashSet<>();
/** /**
* 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.
*/ */
@ -135,6 +142,7 @@ public class ModelAttributes {
isRidingInteractive = PonyPosture.isRidingAPony(entity); isRidingInteractive = PonyPosture.isRidingAPony(entity);
interpolatorId = entity.getUuid(); interpolatorId = entity.getUuid();
isLeftHanded = entity.getMainArm() == Arm.LEFT; isLeftHanded = entity.getMainArm() == Arm.LEFT;
featureSkins = SkinsProxy.instance.getAvailableSkins(entity);
} }
public enum Mode { public enum Mode {

View file

@ -105,7 +105,7 @@ public interface IGear {
/** /**
* The empty context. * The empty context.
*/ */
Context<?, ?> NULL = (e, g) -> null; Context<?, ?> NULL = (e, g) -> g.getDefaultTexture();
/** /**
* 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.

View file

@ -1,26 +1,44 @@
package com.minelittlepony.api.pony.meta; package com.minelittlepony.api.pony.meta;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.TriggerPixelType; import com.minelittlepony.api.pony.TriggerPixelType;
import com.minelittlepony.client.model.gear.SaddleBags;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public enum Wearable implements TriggerPixelType<Wearable> { public enum Wearable implements TriggerPixelType<Wearable> {
NONE (0x00), NONE (0x00, null),
CROWN (0x16), CROWN (0x16, new Identifier("minelittlepony", "textures/models/crown.png")),
MUFFIN (0x32), MUFFIN (0x32, new Identifier("minelittlepony", "textures/models/muffin.png")),
HAT (0x64), HAT (0x64, new Identifier("textures/entity/witch.png")),
ANTLERS (0x96), ANTLERS (0x96, new Identifier("minelittlepony", "textures/models/antlers.png")),
SADDLE_BAGS_LEFT (0xC6), SADDLE_BAGS_LEFT (0xC6, SaddleBags.TEXTURE),
SADDLE_BAGS_RIGHT (0xC7), SADDLE_BAGS_RIGHT (0xC7, SaddleBags.TEXTURE),
SADDLE_BAGS_BOTH (0xC8), SADDLE_BAGS_BOTH (0xC8, SaddleBags.TEXTURE),
STETSON (0xFA); STETSON (0xFA, new Identifier("minelittlepony", "textures/models/stetson.png"));
private int triggerValue; private int triggerValue;
Wearable(int pixel) { private final Identifier id;
private final Identifier texture;
public static final List<Wearable> VALUES = Arrays.stream(values()).toList();
Wearable(int pixel, Identifier texture) {
triggerValue = pixel; triggerValue = pixel;
id = new Identifier("minelittlepony", name().toLowerCase(Locale.ROOT));
this.texture = texture;
}
public Identifier getId() {
return id;
}
public Identifier getDefaultTexture() {
return texture;
} }
@Override @Override
@ -38,7 +56,7 @@ public enum Wearable implements TriggerPixelType<Wearable> {
} }
public static boolean[] flags(Wearable[] wears) { public static boolean[] flags(Wearable[] wears) {
boolean[] flags = new boolean[values().length]; boolean[] flags = new boolean[VALUES.size()];
for (int i = 0; i < wears.length; i++) { for (int i = 0; i < wears.length; i++) {
flags[wears[i].ordinal()] = true; flags[wears[i].ordinal()] = true;
} }
@ -47,9 +65,8 @@ public enum Wearable implements TriggerPixelType<Wearable> {
public static Wearable[] flags(boolean[] flags) { public static Wearable[] flags(boolean[] flags) {
List<Wearable> wears = new ArrayList<>(); List<Wearable> wears = new ArrayList<>();
Wearable[] values = values(); for (int i = 0; i < VALUES.size(); i++) {
for (int i = 0; i < values.length; i++) { if (flags[i]) wears.add(VALUES.get(i));
if (flags[i]) wears.add(values[i]);
} }
return wears.toArray(new Wearable[0]); return wears.toArray(new Wearable[0]);
} }

View file

@ -1,16 +1,19 @@
package com.minelittlepony.client; package com.minelittlepony.client;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.EquineRenderManager;
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;
import com.minelittlepony.common.client.gui.element.Button; import com.minelittlepony.common.client.gui.element.Button;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import java.util.Optional;
import java.util.Set;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.texture.PlayerSkinProvider; import net.minecraft.client.texture.PlayerSkinProvider;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -41,8 +44,12 @@ public class SkinsProxy {
.setText("minelp.options.skins.hdskins.open"); .setText("minelp.options.skins.hdskins.open");
} }
public Identifier getSeaponySkin(EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager, AbstractClientPlayerEntity player) { public Optional<Identifier> getSkin(Identifier skinTypeId, AbstractClientPlayerEntity player) {
return manager.getTexture(player); return Optional.empty();
}
public Set<Identifier> getAvailableSkins(Entity entity) {
return Set.of();
} }
} }

View file

@ -1,32 +1,36 @@
package com.minelittlepony.client.hdskins; package com.minelittlepony.client.hdskins;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.SkinsProxy; import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.ClientPonyModel;
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;
import com.minelittlepony.hdskins.client.SkinCacheClearCallback; import com.minelittlepony.hdskins.client.*;
import com.minelittlepony.hdskins.client.ducks.ClientPlayerInfo; import com.minelittlepony.hdskins.client.ducks.ClientPlayerInfo;
import com.minelittlepony.hdskins.client.dummy.DummyPlayer; import com.minelittlepony.hdskins.client.dummy.DummyPlayer;
import com.minelittlepony.hdskins.client.gui.GuiSkins; import com.minelittlepony.hdskins.client.gui.GuiSkins;
import com.minelittlepony.hdskins.client.resources.LocalPlayerSkins;
import com.minelittlepony.hdskins.mixin.client.MixinClientPlayer; import com.minelittlepony.hdskins.mixin.client.MixinClientPlayer;
import com.minelittlepony.hdskins.profile.SkinType; import com.minelittlepony.hdskins.profile.SkinType;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import java.util.*;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
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.pony.PonyManager;
import com.minelittlepony.client.render.EquineRenderManager; import com.minelittlepony.client.render.entity.PlayerSeaponyRenderer;
import com.minelittlepony.hdskins.client.HDSkins;
/** /**
* All the interactions with HD Skins. * All the interactions with HD Skins.
@ -35,11 +39,18 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
static SkinType seaponySkinType; static SkinType seaponySkinType;
static final Map<SkinType, Wearable> wearableTypes = new HashMap<>();
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
SkinsProxy.instance = this; SkinsProxy.instance = this;
seaponySkinType = SkinType.register(new Identifier("minelp", "seapony"), Items.COD_BUCKET.getDefaultStack()); seaponySkinType = SkinType.register(PlayerSeaponyRenderer.SKIN_TYPE_ID, Items.COD_BUCKET.getDefaultStack());
Wearable.VALUES.forEach(wearable -> {
if (wearable != Wearable.NONE) {
wearableTypes.put(SkinType.register(wearable.getId(), Items.BUNDLE.getDefaultStack()), wearable);
}
});
ClientReadyCallback.EVENT.register(client -> { ClientReadyCallback.EVENT.register(client -> {
// Clear ponies when skins are cleared // Clear ponies when skins are cleared
@ -62,18 +73,39 @@ public class MineLPHDSkins extends SkinsProxy implements ClientModInitializer {
} }
@Override @Override
public Identifier getSeaponySkin(EquineRenderManager<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> manager, AbstractClientPlayerEntity player) { public Optional<Identifier> getSkin(Identifier skinTypeId, AbstractClientPlayerEntity player) {
if (player instanceof DummyPlayer) { return SkinType.REGISTRY.getOrEmpty(skinTypeId).flatMap(type -> getSkin(type, player));
return ((DummyPlayer)player).getTextures().get(seaponySkinType).getId(); }
} else {
ClientPlayerInfo info = (ClientPlayerInfo)((MixinClientPlayer)player).getBackingClientData(); public Set<Identifier> getAvailableSkins(Entity entity) {
Identifier tex = info.getSkins().getSkin(seaponySkinType);
if (tex != null) { if (entity instanceof DummyPlayer dummy) {
return tex; return SkinType.REGISTRY.stream()
} .filter(type -> {
return dummy.getTextures().get(type).isReady()
|| (dummy.getTextures().getPosture().getActiveSkinType() == type && dummy.getTextures() instanceof LocalPlayerSkins);
})
.map(SkinType::getId)
.collect(Collectors.toSet());
} }
return super.getSeaponySkin(manager, player); if (entity instanceof AbstractClientPlayerEntity player) {
PlayerSkins skins = ((ClientPlayerInfo)((MixinClientPlayer)player).getBackingClientData()).getSkins();
return SkinType.REGISTRY.stream()
.filter(type -> skins.getSkin(type) != null)
.map(SkinType::getId)
.collect(Collectors.toSet());
}
return Set.of();
}
private Optional<Identifier> getSkin(SkinType type, AbstractClientPlayerEntity player) {
if (player instanceof DummyPlayer dummy) {
return Optional.of(dummy.getTextures().get(type).getId());
}
return Optional.ofNullable(((ClientPlayerInfo)((MixinClientPlayer)player).getBackingClientData()).getSkins().getSkin(type));
} }
@Override @Override

View file

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.api.pony.*; import com.minelittlepony.api.pony.*;
import com.minelittlepony.api.pony.meta.TriggerPixel; import com.minelittlepony.api.pony.meta.TriggerPixel;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.render.entity.SeaponyRenderer; import com.minelittlepony.client.render.entity.SeaponyRenderer;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
@ -34,6 +35,12 @@ class PonyPreview extends PlayerPreview {
return DefaultSkinGenerator.generateGreyScale(SeaponyRenderer.TEXTURE, SeaponyRenderer.TEXTURE, getExclusion()); return DefaultSkinGenerator.generateGreyScale(SeaponyRenderer.TEXTURE, SeaponyRenderer.TEXTURE, getExclusion());
} }
Wearable wearable = MineLPHDSkins.wearableTypes.getOrDefault(type, Wearable.NONE);
if (wearable != Wearable.NONE) {
return DefaultSkinGenerator.generateGreyScale(wearable.getDefaultTexture(), wearable.getDefaultTexture(), getExclusion());
}
return super.getDefaultSkin(type, slim); return super.getDefaultSkin(type, slim);
} }

View file

@ -29,9 +29,8 @@ import java.util.function.BiFunction;
import java.util.stream.Stream; 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, ModelKey<? extends IGear>> GEAR_MODELS = new HashMap<>(); private static final Map<Wearable, GearModelKey<? extends IGear>> 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,12 +54,14 @@ public final class ModelType {
public static final ModelKey<PonyArmourModel<?>> ARMOUR_INNER = register("armour_inner", PonyArmourModel::new); public static final ModelKey<PonyArmourModel<?>> ARMOUR_INNER = register("armour_inner", PonyArmourModel::new);
public static final ModelKey<PonyArmourModel<?>> ARMOUR_OUTER = register("armour_outer", PonyArmourModel::new); public static final ModelKey<PonyArmourModel<?>> ARMOUR_OUTER = register("armour_outer", PonyArmourModel::new);
public static final ModelKey<Stetson> STETSON = registerGear("stetson", Wearable.STETSON, Stetson::new); public static final GearModelKey<Stetson> STETSON = registerGear("stetson", Wearable.STETSON, Stetson::new);
public static final ModelKey<SaddleBags> SADDLEBAGS = registerGear("saddlebags", Wearable.SADDLE_BAGS_BOTH, SaddleBags::new); public static final GearModelKey<SaddleBags> SADDLEBAGS_BOTH = registerGear("saddlebags", Wearable.SADDLE_BAGS_BOTH, t -> new SaddleBags(t, Wearable.SADDLE_BAGS_BOTH));
public static final ModelKey<Crown> CROWN = registerGear("crown", Wearable.CROWN, Crown::new); 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 ModelKey<Muffin> MUFFIN = registerGear("muffin", Wearable.MUFFIN, Muffin::new); 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 ModelKey<WitchHat> WITCH_HAT = registerGear("witch_hat", Wearable.HAT, WitchHat::new); public static final GearModelKey<Crown> CROWN = registerGear("crown", Wearable.CROWN, Crown::new);
public static final ModelKey<ChristmasHat> ANTLERS = registerGear("antlers", Wearable.ANTLERS, ChristmasHat::new); public static final GearModelKey<Muffin> MUFFIN = registerGear("muffin", Wearable.MUFFIN, Muffin::new);
public static final GearModelKey<WitchHat> WITCH_HAT = registerGear("witch_hat", Wearable.HAT, WitchHat::new);
public static final GearModelKey<ChristmasHat> ANTLERS = registerGear("antlers", Wearable.ANTLERS, ChristmasHat::new);
public static final PlayerModelKey<?, AlicornModel<?>> ALICORN = registerPlayer("alicorn", Race.ALICORN, AlicornModel::new); public static final PlayerModelKey<?, AlicornModel<?>> ALICORN = registerPlayer("alicorn", Race.ALICORN, AlicornModel::new);
public static final PlayerModelKey<?, UnicornModel<?>> UNICORN = registerPlayer("unicorn", Race.UNICORN, UnicornModel::new); public static final PlayerModelKey<?, UnicornModel<?>> UNICORN = registerPlayer("unicorn", Race.UNICORN, UnicornModel::new);
@ -87,12 +88,17 @@ public final class ModelType {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends AbstractGear> ModelKey<T> registerGear(String name, Wearable wearable, MsonModel.Factory<T> constructor) { static <T extends AbstractGear> GearModelKey<T> registerGear(String name, Wearable wearable, MsonModel.Factory<T> constructor) {
return (ModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> { return (GearModelKey<T>)GEAR_MODELS.computeIfAbsent(wearable, w -> {
return Mson.getInstance().registerModel(new Identifier("minelittlepony", "gear/" + name), constructor); return new GearModelKey<T>(Mson.getInstance().registerModel(new Identifier("minelittlepony", "gear/" + name), constructor), constructor);
}); });
} }
@SuppressWarnings("unchecked")
static <T extends AbstractGear> 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));
}
static <T extends Model> ModelKey<T> register(String name, MsonModel.Factory<T> constructor) { static <T extends Model> ModelKey<T> register(String name, MsonModel.Factory<T> constructor) {
return Mson.getInstance().registerModel(new Identifier("minelittlepony", name), constructor); return Mson.getInstance().registerModel(new Identifier("minelittlepony", name), constructor);
} }
@ -103,9 +109,15 @@ public final class ModelType {
return (PlayerModelKey<E, T>)PLAYER_MODELS.get(race); return (PlayerModelKey<E, T>)PLAYER_MODELS.get(race);
} }
public static Stream<Map.Entry<Wearable, ModelKey<? extends IGear>>> getWearables() { public static Stream<Map.Entry<Wearable, GearModelKey<? extends IGear>>> 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 T createModel() {
return key.createModel(constructor);
}
}
} }

View file

@ -15,18 +15,17 @@ import com.minelittlepony.mson.api.MsonModel;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
public class PlayerModelKey<T extends LivingEntity, M extends Model & MsonModel> { public record PlayerModelKey<T extends LivingEntity, M extends Model & MsonModel> (
ModelKey<M> steveKey,
private final ModelKey<M> steveKey; ModelKey<M> alexKey,
private final ModelKey<M> alexKey; RendererFactory factory
) {
private final RendererFactory rendererFactory;
PlayerModelKey(String name, BiFunction<ModelPart, Boolean, M> modelFactory, RendererFactory rendererFactory) { PlayerModelKey(String name, BiFunction<ModelPart, Boolean, M> modelFactory, RendererFactory rendererFactory) {
this.rendererFactory = rendererFactory; this(
Mson.getInstance().registerModel(new Identifier("minelittlepony", "races/steve/" + name), tree -> modelFactory.apply(tree, false)),
steveKey = Mson.getInstance().registerModel(new Identifier("minelittlepony", "races/steve/" + name), tree -> modelFactory.apply(tree, false)); Mson.getInstance().registerModel(new Identifier("minelittlepony", "races/alex/" + name), tree -> modelFactory.apply(tree, true)),
alexKey = Mson.getInstance().registerModel(new Identifier("minelittlepony", "races/alex/" + name), tree -> modelFactory.apply(tree, true)); rendererFactory
);
} }
public ModelKey<M> getKey(boolean slimArms) { public ModelKey<M> getKey(boolean slimArms) {
@ -34,8 +33,8 @@ public class PlayerModelKey<T extends LivingEntity, M extends Model & MsonModel>
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Function<EntityRendererFactory.Context, PlayerEntityRenderer> getRendererFactory(boolean slimArms) { public Function<EntityRendererFactory.Context, PlayerEntityRenderer> getFactory(boolean slimArms) {
return d -> rendererFactory.create(d, slimArms, (ModelKey<? extends ClientPonyModel<AbstractClientPlayerEntity>>)getKey(slimArms)); return d -> factory.create(d, slimArms, (ModelKey<? extends ClientPonyModel<AbstractClientPlayerEntity>>)getKey(slimArms));
} }
public interface RendererFactory { public interface RendererFactory {

View file

@ -0,0 +1,34 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.model.BodyPart;
import com.minelittlepony.api.model.IModel;
import com.minelittlepony.api.pony.meta.Wearable;
public abstract class AbstractWearableGear extends AbstractGear {
protected final Wearable wearable;
protected final BodyPart location;
protected AbstractWearableGear(Wearable wearable, BodyPart location) {
this.wearable = wearable;
this.location = location;
}
@Override
public BodyPart getGearLocation() {
return location;
}
@Override
public boolean canRender(IModel model, Entity entity) {
return model.isWearing(wearable);
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return context.getDefaultTexture(entity, wearable);
}
}

View file

@ -4,7 +4,6 @@ import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import com.minelittlepony.api.model.BodyPart; import com.minelittlepony.api.model.BodyPart;
@ -16,7 +15,7 @@ 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 AbstractGear implements PonyModelConstants { public class ChristmasHat extends AbstractWearableGear implements PonyModelConstants {
private static boolean dayChecked = false; private static boolean dayChecked = false;
private static boolean dayResult = false; private static boolean dayResult = false;
@ -32,21 +31,20 @@ public class ChristmasHat extends AbstractGear implements PonyModelConstants {
return dayResult; return dayResult;
} }
private static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/antlers.png");
private final ModelPart left; private final ModelPart left;
private final ModelPart right; private final ModelPart right;
private int tint; private int tint;
public ChristmasHat(ModelPart tree) { public ChristmasHat(ModelPart tree) {
super(Wearable.ANTLERS, BodyPart.HEAD);
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(IModel model, Entity entity) {
return isChristmasDay() || model.isWearing(Wearable.ANTLERS); return isChristmasDay() || super.canRender(model, entity);
} }
@Override @Override
@ -65,16 +63,6 @@ public class ChristmasHat extends AbstractGear implements PonyModelConstants {
right.roll = -bodySwing; right.roll = -bodySwing;
} }
@Override
public BodyPart getGearLocation() {
return BodyPart.HEAD;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return TEXTURE;
}
@Override @Override
public void render(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) { public void render(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
if (tint != 0) { if (tint != 0) {

View file

@ -5,23 +5,22 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.AbstractPiglinEntity; import net.minecraft.entity.mob.AbstractPiglinEntity;
import net.minecraft.entity.mob.ZombifiedPiglinEntity; import net.minecraft.entity.mob.ZombifiedPiglinEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
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.IModel;
import com.minelittlepony.api.model.gear.IStackable; import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class Crown extends AbstractGear implements IStackable { public class Crown extends AbstractWearableGear implements IStackable {
public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/crown.png");
public Crown(ModelPart tree) { public Crown(ModelPart tree) {
super(Wearable.CROWN, BodyPart.HEAD);
addPart(tree.getChild("crown")); addPart(tree.getChild("crown"));
} }
@Override @Override
public boolean canRender(IModel model, Entity entity) { public boolean canRender(IModel model, Entity entity) {
return model.isWearing(Wearable.CROWN) return super.canRender(model, entity)
|| (( || ((
entity instanceof AbstractPiglinEntity entity instanceof AbstractPiglinEntity
|| entity instanceof PlayerEntity || entity instanceof PlayerEntity
@ -30,16 +29,6 @@ public class Crown extends AbstractGear implements IStackable {
); );
} }
@Override
public BodyPart getGearLocation() {
return BodyPart.HEAD;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return TEXTURE;
}
@Override @Override
public float getStackingHeight() { public float getStackingHeight() {
return 0.1F; return 0.1F;

View file

@ -1,37 +1,17 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity;
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.gear.IStackable; import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class Muffin extends AbstractGear implements IStackable { public class Muffin extends AbstractWearableGear implements IStackable {
private static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/muffin.png");
public Muffin(ModelPart tree) { public Muffin(ModelPart tree) {
super(Wearable.MUFFIN, BodyPart.HEAD);
addPart(tree.getChild("crown")); addPart(tree.getChild("crown"));
} }
@Override
public boolean canRender(IModel model, Entity entity) {
return model.isWearing(Wearable.MUFFIN);
}
@Override
public BodyPart getGearLocation() {
return BodyPart.HEAD;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return TEXTURE;
}
@Override @Override
public float getStackingHeight() { public float getStackingHeight() {
return 0.45F; return 0.45F;

View file

@ -15,7 +15,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 AbstractGear implements PonyModelConstants { public class SaddleBags extends AbstractWearableGear implements PonyModelConstants {
public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png"); public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png");
@ -26,9 +26,10 @@ public class SaddleBags extends AbstractGear implements PonyModelConstants {
private boolean hangLow = false; private boolean hangLow = false;
float dropAmount = 0; private float dropAmount = 0;
public SaddleBags(ModelPart tree) { public SaddleBags(ModelPart tree, Wearable wearable) {
super(wearable, BodyPart.BODY);
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");
@ -60,17 +61,13 @@ public class SaddleBags extends AbstractGear implements PonyModelConstants {
leftBag.roll = bodySwing; leftBag.roll = bodySwing;
rightBag.roll = -bodySwing; rightBag.roll = -bodySwing;
leftBag.visible = model.isWearing(Wearable.SADDLE_BAGS_BOTH) || model.isWearing(Wearable.SADDLE_BAGS_LEFT); leftBag.visible = wearable == Wearable.SADDLE_BAGS_BOTH || wearable == Wearable.SADDLE_BAGS_LEFT;
rightBag.visible = model.isWearing(Wearable.SADDLE_BAGS_BOTH) || model.isWearing(Wearable.SADDLE_BAGS_RIGHT); rightBag.visible = wearable == Wearable.SADDLE_BAGS_BOTH || wearable == Wearable.SADDLE_BAGS_RIGHT;
dropAmount = hangLow ? 0.15F : 0; dropAmount = hangLow ? 0.15F : 0;
dropAmount = model.getMetadata().getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3); dropAmount = model.getMetadata().getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3);
} }
public void sethangingLow(boolean veryLow) {
hangLow = veryLow;
}
@Override @Override
public void render(MatrixStack stack, VertexConsumer renderContext, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) { public void render(MatrixStack stack, VertexConsumer renderContext, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
stack.push(); stack.push();
@ -88,19 +85,4 @@ public class SaddleBags extends AbstractGear implements PonyModelConstants {
strap.render(stack, renderContext, overlayUv, lightUv, red, green, blue, alpha); strap.render(stack, renderContext, overlayUv, lightUv, red, green, blue, alpha);
} }
} }
@Override
public boolean canRender(IModel model, Entity entity) {
return model.isWearing(Wearable.SADDLE_BAGS_BOTH) || model.isWearing(Wearable.SADDLE_BAGS_LEFT) || model.isWearing(Wearable.SADDLE_BAGS_RIGHT);
}
@Override
public BodyPart getGearLocation() {
return BodyPart.BODY;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return context.getDefaultTexture(entity, Wearable.SADDLE_BAGS_BOTH);
}
} }

View file

@ -1,36 +1,17 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity;
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.gear.IStackable; import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class Stetson extends AbstractGear implements IStackable { public class Stetson extends AbstractWearableGear implements IStackable {
private static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/stetson.png");
public Stetson(ModelPart tree) { public Stetson(ModelPart tree) {
super(Wearable.STETSON, BodyPart.HEAD);
addPart(tree.getChild("rim")); addPart(tree.getChild("rim"));
} }
@Override
public BodyPart getGearLocation() {
return BodyPart.HEAD;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return TEXTURE;
}
@Override
public boolean canRender(IModel model, Entity entity) {
return model.isWearing(Wearable.STETSON);
}
@Override @Override
public float getStackingHeight() { public float getStackingHeight() {
return 0.15F; return 0.15F;

View file

@ -1,37 +1,17 @@
package com.minelittlepony.client.model.gear; package com.minelittlepony.client.model.gear;
import net.minecraft.client.model.ModelPart; import net.minecraft.client.model.ModelPart;
import net.minecraft.entity.Entity;
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.gear.IStackable; import com.minelittlepony.api.model.gear.IStackable;
import com.minelittlepony.api.pony.meta.Wearable; import com.minelittlepony.api.pony.meta.Wearable;
public class WitchHat extends AbstractGear implements IStackable { public class WitchHat extends AbstractWearableGear implements IStackable {
private static final Identifier WITCH_TEXTURES = new Identifier("textures/entity/witch.png");
public WitchHat(ModelPart tree) { public WitchHat(ModelPart tree) {
super(Wearable.HAT, BodyPart.HEAD);
addPart(tree.getChild("hat")); addPart(tree.getChild("hat"));
} }
@Override
public boolean canRender(IModel model, Entity entity) {
return model.isWearing(Wearable.HAT);
}
@Override
public BodyPart getGearLocation() {
return BodyPart.HEAD;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return WITCH_TEXTURES;
}
@Override @Override
public float getStackingHeight() { public float getStackingHeight() {
return 0.7F; return 0.7F;

View file

@ -40,7 +40,7 @@ public class PegasusWings<T extends Model & IPegasus> implements IPart, MsonMode
} }
public Wing getRight() { public Wing getRight() {
return pegasus.isBurdened() ? 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

View file

@ -57,7 +57,7 @@ public class PonyRenderDispatcher {
private void addPlayerSkin(EntityRenderDispatcher manager, boolean slimArms, Race race) { private void addPlayerSkin(EntityRenderDispatcher manager, boolean slimArms, Race race) {
Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer( Mson.getInstance().getEntityRendererRegistry().registerPlayerRenderer(
race.getModelId(slimArms), race.getModelId(slimArms),
ModelType.getPlayerModel(race).getRendererFactory(slimArms) ModelType.getPlayerModel(race).getFactory(slimArms)
); );
} }

View file

@ -5,6 +5,7 @@ import com.minelittlepony.api.pony.IPony;
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.MineLittlePony; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.client.SkinsProxy;
import com.minelittlepony.client.model.ClientPonyModel; import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.model.ModelWrapper; import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.model.gear.SaddleBags; import com.minelittlepony.client.model.gear.SaddleBags;
@ -198,12 +199,12 @@ public class PlayerPonyRenderer extends PlayerEntityRenderer implements IPonyRen
@Override @Override
public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) { public Identifier getDefaultTexture(AbstractClientPlayerEntity entity, Wearable wearable) {
if (wearable.isSaddlebags()) { return SkinsProxy.instance.getSkin(wearable.getId(), entity).orElseGet(() -> {
if (getInternalRenderer().getModel().getMetadata().getRace() == Race.BATPONY) { if (wearable.isSaddlebags() && getInternalRenderer().getModel().getMetadata().getRace() == Race.BATPONY) {
return SaddleBags.TEXTURE; return SaddleBags.TEXTURE;
} }
}
return getTexture(entity); return wearable.getDefaultTexture();
});
} }
} }

View file

@ -16,6 +16,7 @@ import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class PlayerSeaponyRenderer extends PlayerPonyRenderer { public class PlayerSeaponyRenderer extends PlayerPonyRenderer {
public static final Identifier SKIN_TYPE_ID = new Identifier("minelp", "seapony");
private final ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> seapony; private final ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> seapony;
private final ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> normalPony; private final ModelWrapper<AbstractClientPlayerEntity, ClientPonyModel<AbstractClientPlayerEntity>> normalPony;
@ -29,7 +30,7 @@ public class PlayerSeaponyRenderer extends PlayerPonyRenderer {
@Override @Override
public Identifier getTexture(AbstractClientPlayerEntity player) { public Identifier getTexture(AbstractClientPlayerEntity player) {
return SkinsProxy.instance.getSeaponySkin(manager, player); return SkinsProxy.instance.getSkin(SKIN_TYPE_ID, player).orElseGet(() -> super.getTexture(player));
} }
@Override @Override

View file

@ -8,7 +8,8 @@ import net.minecraft.client.render.entity.feature.*;
import net.minecraft.client.render.entity.model.*; import net.minecraft.client.render.entity.model.*;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.passive.PigEntity; import net.minecraft.entity.passive.PigEntity;
import com.minelittlepony.client.model.gear.Crown;
import com.minelittlepony.api.pony.meta.Wearable;
public class PonyPigRenderer extends PigEntityRenderer { public class PonyPigRenderer extends PigEntityRenderer {
@ -34,7 +35,7 @@ public class PonyPigRenderer extends PigEntityRenderer {
getContextModel().copyStateTo(model); getContextModel().copyStateTo(model);
model.animateModel(entity, limbAngle, limbDistance, tickDelta); model.animateModel(entity, limbAngle, limbDistance, tickDelta);
model.setAngles(entity, limbAngle, limbDistance, animationProgress, headYaw, headPitch); model.setAngles(entity, limbAngle, limbDistance, animationProgress, headYaw, headPitch);
VertexConsumer vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(Crown.TEXTURE)); VertexConsumer vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(Wearable.CROWN.getDefaultTexture()));
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
} }
} }

View file

@ -78,7 +78,7 @@ abstract class AbstractNpcRenderer<T extends MobEntity & VillagerDataContainer>
if (wearable.isSaddlebags()) { if (wearable.isSaddlebags()) {
return clothing.createTexture(villager, "accessory"); return clothing.createTexture(villager, "accessory");
} }
return getTexture(villager); return wearable.getDefaultTexture();
} }
@Override @Override