mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-11-22 04:27:59 +01:00
Implement a armour renderplugin api
This commit is contained in:
parent
85726e8c8d
commit
ced4a2d980
6 changed files with 189 additions and 111 deletions
|
@ -0,0 +1,65 @@
|
|||
package com.minelittlepony.client.model.armour;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.component.type.DyedColorComponent;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ArmorMaterial;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.trim.ArmorTrim;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.registry.tag.ItemTags;
|
||||
import net.minecraft.util.Colors;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public interface ArmourRendererPlugin {
|
||||
AtomicReference<ArmourRendererPlugin> INSTANCE = new AtomicReference<>(new ArmourRendererPlugin() {});
|
||||
|
||||
static void register(ArmourRendererPlugin plugin) {
|
||||
INSTANCE.set(plugin);
|
||||
}
|
||||
|
||||
default ArmourTextureLookup getTextureLookup() {
|
||||
return ArmourTextureResolver.INSTANCE;
|
||||
}
|
||||
|
||||
default ItemStack[] getArmorStacks(LivingEntity entity, EquipmentSlot armorSlot, ArmourLayer layer) {
|
||||
return new ItemStack[] { entity.getEquippedStack(armorSlot) };
|
||||
}
|
||||
|
||||
default boolean shouldRenderGlint(EquipmentSlot slot, ItemStack stack) {
|
||||
return stack.hasGlint();
|
||||
}
|
||||
|
||||
default int getDyeColor(EquipmentSlot slot, ItemStack stack) {
|
||||
return stack.isIn(ItemTags.DYEABLE) ? DyedColorComponent.getColor(stack, -6265536) : Colors.WHITE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default VertexConsumer getTrimConsumer(EquipmentSlot slot, VertexConsumerProvider provider, RegistryEntry<ArmorMaterial> material, ArmorTrim trim, ArmourLayer layer) {
|
||||
SpriteAtlasTexture armorTrimsAtlas = MinecraftClient.getInstance().getBakedModelManager().getAtlas(TexturedRenderLayers.ARMOR_TRIMS_ATLAS_TEXTURE);
|
||||
Sprite sprite = armorTrimsAtlas.getSprite(
|
||||
layer == ArmourLayer.INNER ? trim.getLeggingsModelId(material) : trim.getGenericModelId(material)
|
||||
);
|
||||
return sprite.getTextureSpecificVertexConsumer(
|
||||
provider.getBuffer(TexturedRenderLayers.getArmorTrims(trim.getPattern().value().decal()))
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default VertexConsumer getArmourConsumer(EquipmentSlot slot, VertexConsumerProvider provider, Identifier texture, ArmourLayer layer) {
|
||||
return provider.getBuffer(RenderLayer.getArmorCutoutNoCull(texture));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default VertexConsumer getGlintConsumer(EquipmentSlot slot, VertexConsumerProvider provider, ArmourLayer layer) {
|
||||
return provider.getBuffer(RenderLayer.getArmorEntityGlint());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.minelittlepony.client.model.armour;
|
||||
|
||||
import net.minecraft.client.texture.TextureManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import com.minelittlepony.api.config.PonyConfig;
|
||||
import com.minelittlepony.util.ResourceUtil;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public record ArmourTexture(Identifier texture, ArmourVariant variant) {
|
||||
private static final Interner<ArmourTexture> INTERNER = Interners.newWeakInterner();
|
||||
public static final ArmourTexture UNKNOWN = legacy(TextureManager.MISSING_IDENTIFIER);
|
||||
|
||||
public boolean validate() {
|
||||
return texture != TextureManager.MISSING_IDENTIFIER && ResourceUtil.textureExists(texture);
|
||||
}
|
||||
|
||||
public static ArmourTexture legacy(Identifier texture) {
|
||||
return INTERNER.intern(new ArmourTexture(texture, ArmourVariant.LEGACY));
|
||||
}
|
||||
|
||||
public static ArmourTexture modern(Identifier texture) {
|
||||
return INTERNER.intern(new ArmourTexture(texture, ArmourVariant.NORMAL));
|
||||
}
|
||||
|
||||
public Stream<ArmourTexture> named() {
|
||||
return Stream.of(legacy(texture().withPath(p -> p.replace("1", "inner").replace("2", "outer"))), this);
|
||||
}
|
||||
|
||||
public Stream<ArmourTexture> ponify() {
|
||||
if (!PonyConfig.getInstance().disablePonifiedArmour.get()) {
|
||||
return Stream.of(this, modern(ResourceUtil.ponify(texture())));
|
||||
}
|
||||
return Stream.of(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.minelittlepony.client.model.armour;
|
||||
|
||||
import net.minecraft.item.ArmorMaterial;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ArmourTextureLookup {
|
||||
ArmourTexture getTexture(ItemStack stack, ArmourLayer layer, ArmorMaterial.Layer armorLayer);
|
||||
|
||||
List<ArmorMaterial.Layer> getArmorLayers(ItemStack stack, int dyeColor);
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package com.minelittlepony.client.model.armour;
|
||||
|
||||
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
|
||||
import net.minecraft.client.texture.TextureManager;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.component.type.CustomModelDataComponent;
|
||||
import net.minecraft.item.*;
|
||||
|
@ -14,9 +13,7 @@ import net.minecraft.util.profiler.Profiler;
|
|||
import com.google.common.cache.*;
|
||||
import com.google.common.collect.Interner;
|
||||
import com.google.common.collect.Interners;
|
||||
import com.minelittlepony.api.config.PonyConfig;
|
||||
import com.minelittlepony.client.MineLittlePony;
|
||||
import com.minelittlepony.util.ResourceUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
@ -38,7 +35,7 @@ import java.util.stream.Stream;
|
|||
* - the "minecraft" namespace is always replaced with "minelittlepony"
|
||||
* <p>
|
||||
*/
|
||||
public class ArmourTextureResolver implements IdentifiableResourceReloadListener {
|
||||
public class ArmourTextureResolver implements ArmourTextureLookup, IdentifiableResourceReloadListener {
|
||||
public static final Identifier ID = MineLittlePony.id("armor_textures");
|
||||
public static final ArmourTextureResolver INSTANCE = new ArmourTextureResolver();
|
||||
|
||||
|
@ -102,10 +99,12 @@ public class ArmourTextureResolver implements IdentifiableResourceReloadListener
|
|||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArmourTexture getTexture(ItemStack stack, ArmourLayer layer, ArmorMaterial.Layer armorLayer) {
|
||||
return layerCache.getUnchecked(new ArmourParameters(layer, armorLayer, getCustom(stack)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArmorMaterial.Layer> getArmorLayers(ItemStack stack, int dyeColor) {
|
||||
if (stack.getItem() instanceof ArmorItem armor) {
|
||||
return armor.getMaterial().value().layers();
|
||||
|
@ -121,32 +120,4 @@ public class ArmourTextureResolver implements IdentifiableResourceReloadListener
|
|||
private record ArmourParameters(ArmourLayer layer, ArmorMaterial.Layer material, int customModelId) {
|
||||
|
||||
}
|
||||
|
||||
public record ArmourTexture(Identifier texture, ArmourVariant variant) {
|
||||
private static final Interner<ArmourTexture> INTERNER = Interners.newWeakInterner();
|
||||
public static final ArmourTexture UNKNOWN = legacy(TextureManager.MISSING_IDENTIFIER);
|
||||
|
||||
public boolean validate() {
|
||||
return texture != TextureManager.MISSING_IDENTIFIER && ResourceUtil.textureExists(texture);
|
||||
}
|
||||
|
||||
public static ArmourTexture legacy(Identifier texture) {
|
||||
return INTERNER.intern(new ArmourTexture(texture, ArmourVariant.LEGACY));
|
||||
}
|
||||
|
||||
public static ArmourTexture modern(Identifier texture) {
|
||||
return INTERNER.intern(new ArmourTexture(texture, ArmourVariant.NORMAL));
|
||||
}
|
||||
|
||||
public Stream<ArmourTexture> named() {
|
||||
return Stream.of(legacy(texture().withPath(p -> p.replace("1", "inner").replace("2", "outer"))), this);
|
||||
}
|
||||
|
||||
public Stream<ArmourTexture> ponify() {
|
||||
if (!PonyConfig.getInstance().disablePonifiedArmour.get()) {
|
||||
return Stream.of(this, modern(ResourceUtil.ponify(texture())));
|
||||
}
|
||||
return Stream.of(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import net.minecraft.client.render.entity.feature.*;
|
|||
import net.minecraft.client.render.entity.model.ArmorStandArmorEntityModel;
|
||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.decoration.ArmorStandEntity;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
|
@ -15,7 +14,6 @@ import com.minelittlepony.api.model.Models;
|
|||
import com.minelittlepony.api.pony.PonyData;
|
||||
import com.minelittlepony.api.pony.meta.Race;
|
||||
import com.minelittlepony.client.model.ModelType;
|
||||
import com.minelittlepony.client.model.armour.ArmourLayer;
|
||||
import com.minelittlepony.client.model.entity.PonyArmourStandModel;
|
||||
import com.minelittlepony.client.model.entity.race.EarthPonyModel;
|
||||
import com.minelittlepony.client.render.entity.feature.ArmourFeature;
|
||||
|
@ -82,13 +80,7 @@ public class PonyStandRenderer extends ArmorStandEntityRenderer {
|
|||
pony.body().animateModel(entity, limbDistance, limbAngle, tickDelta);
|
||||
pony.body().setAngles(entity, limbDistance, limbAngle, age, headYaw, headPitch);
|
||||
PonyStandRenderer.this.pony.applyAnglesTo(pony.body());
|
||||
|
||||
for (EquipmentSlot i : EquipmentSlot.values()) {
|
||||
if (i.getType() == EquipmentSlot.Type.ARMOR) {
|
||||
ArmourFeature.renderArmor(pony, stack, renderContext, lightUv, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.INNER);
|
||||
ArmourFeature.renderArmor(pony, stack, renderContext, lightUv, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.OUTER);
|
||||
}
|
||||
}
|
||||
ArmourFeature.renderArmor(pony, stack, renderContext, lightUv, entity, limbDistance, limbAngle, age, headYaw, headPitch);
|
||||
} else {
|
||||
super.render(stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch);
|
||||
}
|
||||
|
|
|
@ -3,114 +3,113 @@ package com.minelittlepony.client.render.entity.feature;
|
|||
import com.minelittlepony.api.model.Models;
|
||||
import com.minelittlepony.api.model.PonyModel;
|
||||
import com.minelittlepony.client.model.armour.*;
|
||||
import com.minelittlepony.client.model.armour.ArmourTextureResolver.ArmourTexture;
|
||||
import com.minelittlepony.client.render.PonyRenderContext;
|
||||
import com.minelittlepony.common.util.Color;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.render.entity.model.*;
|
||||
import net.minecraft.client.render.model.BakedModelManager;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.component.type.DyedColorComponent;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.item.trim.ArmorTrim;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.registry.tag.ItemTags;
|
||||
import net.minecraft.util.Colors;
|
||||
|
||||
public class ArmourFeature<T extends LivingEntity, M extends EntityModel<T> & PonyModel<T>> extends AbstractPonyFeature<T, M> {
|
||||
|
||||
public ArmourFeature(PonyRenderContext<T, M> context, BakedModelManager bakery) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
|
||||
Models<T, M> pony = getModelWrapper();
|
||||
|
||||
for (EquipmentSlot i : EquipmentSlot.values()) {
|
||||
if (i.getType() == EquipmentSlot.Type.ARMOR) {
|
||||
renderArmor(pony, stack, renderContext, lightUv, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.INNER);
|
||||
renderArmor(pony, stack, renderContext, lightUv, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.OUTER);
|
||||
}
|
||||
}
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider provider, int light, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
|
||||
renderArmor(getModelWrapper(), matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch);
|
||||
}
|
||||
|
||||
public static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor(
|
||||
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
|
||||
VertexConsumerProvider provider, int light, T entity,
|
||||
float limbDistance, float limbAngle,
|
||||
float age, float headYaw, float headPitch,
|
||||
EquipmentSlot armorSlot, ArmourLayer layer) {
|
||||
float age, float headYaw, float headPitch) {
|
||||
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
|
||||
|
||||
ItemStack stack = entity.getEquippedStack(armorSlot);
|
||||
|
||||
if (stack.isEmpty()) {
|
||||
return;
|
||||
for (EquipmentSlot i : EquipmentSlot.values()) {
|
||||
if (i.getType() == EquipmentSlot.Type.ARMOR) {
|
||||
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.INNER, plugin);
|
||||
renderArmor(pony, matrices, provider, light, entity, limbDistance, limbAngle, age, headYaw, headPitch, i, ArmourLayer.OUTER, plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean glint = stack.hasGlint();
|
||||
private static <T extends LivingEntity, V extends PonyArmourModel<T>> void renderArmor(
|
||||
Models<T, ? extends PonyModel<T>> pony, MatrixStack matrices,
|
||||
VertexConsumerProvider provider, int light, T entity,
|
||||
float limbDistance, float limbAngle,
|
||||
float age, float headYaw, float headPitch,
|
||||
EquipmentSlot armorSlot, ArmourLayer layer, ArmourRendererPlugin plugin) {
|
||||
|
||||
int color = stack.isIn(ItemTags.DYEABLE) ? DyedColorComponent.getColor(stack, -6265536) : Colors.WHITE;
|
||||
|
||||
Set<PonyArmourModel<?>> models = glint ? new HashSet<>() : null;
|
||||
|
||||
for (ArmorMaterial.Layer armorLayer : ArmourTextureResolver.INSTANCE.getArmorLayers(stack, color)) {
|
||||
ArmourTexture layerTexture = ArmourTextureResolver.INSTANCE.getTexture(stack, layer, armorLayer);
|
||||
|
||||
if (layerTexture == ArmourTexture.UNKNOWN) {
|
||||
for (ItemStack stack : plugin.getArmorStacks(entity, armorSlot, layer)) {
|
||||
if (stack.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var m = pony.getArmourModel(stack, layer, layerTexture.variant()).orElse(null);
|
||||
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
|
||||
float red = 1;
|
||||
float green = 1;
|
||||
float blue = 1;
|
||||
if (armorLayer.isDyeable() && color != Colors.WHITE) {
|
||||
red = Color.r(color);
|
||||
green = Color.g(color);
|
||||
blue = Color.b(color);
|
||||
boolean glint = plugin.shouldRenderGlint(armorSlot, stack);
|
||||
int color = plugin.getDyeColor(armorSlot, stack);
|
||||
|
||||
Set<PonyArmourModel<?>> models = glint ? new HashSet<>() : null;
|
||||
|
||||
ArmourTextureLookup textureLookup = plugin.getTextureLookup();
|
||||
|
||||
for (ArmorMaterial.Layer armorLayer : textureLookup.getArmorLayers(stack, color)) {
|
||||
ArmourTexture layerTexture = textureLookup.getTexture(stack, layer, armorLayer);
|
||||
|
||||
if (layerTexture == ArmourTexture.UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
m.render(matrices, provider.getBuffer(RenderLayer.getArmorCutoutNoCull(layerTexture.texture())), light, OverlayTexture.DEFAULT_UV, red, green, blue, 1);
|
||||
if (glint) {
|
||||
models.add(m);
|
||||
|
||||
var m = pony.getArmourModel(stack, layer, layerTexture.variant()).orElse(null);
|
||||
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
|
||||
VertexConsumer armorConsumer = plugin.getArmourConsumer(armorSlot, provider, layerTexture.texture(), layer);
|
||||
if (armorConsumer != null) {
|
||||
float red = 1;
|
||||
float green = 1;
|
||||
float blue = 1;
|
||||
if (armorLayer.isDyeable() && color != Colors.WHITE) {
|
||||
red = Color.r(color);
|
||||
green = Color.g(color);
|
||||
blue = Color.b(color);
|
||||
}
|
||||
m.render(matrices, armorConsumer, light, OverlayTexture.DEFAULT_UV, red, green, blue, 1);
|
||||
}
|
||||
if (glint) {
|
||||
models.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArmorTrim trim = stack.get(DataComponentTypes.TRIM);
|
||||
|
||||
if (trim != null && stack.getItem() instanceof ArmorItem armor) {
|
||||
var m = pony.getArmourModel(stack, layer, ArmourVariant.TRIM).orElse(null);
|
||||
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
|
||||
VertexConsumer trimConsumer = plugin.getTrimConsumer(armorSlot, provider, armor.getMaterial(), trim, layer);
|
||||
if (trimConsumer != null) {
|
||||
m.render(matrices, trimConsumer, light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (glint) {
|
||||
VertexConsumer glintConsumer = plugin.getGlintConsumer(armorSlot, provider, layer);
|
||||
if (glintConsumer != null) {
|
||||
for (var m : models) {
|
||||
m.render(matrices, glintConsumer, light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArmorTrim trim = stack.get(DataComponentTypes.TRIM);
|
||||
|
||||
if (trim != null && stack.getItem() instanceof ArmorItem armor) {
|
||||
var m = pony.getArmourModel(stack, layer, ArmourVariant.TRIM).orElse(null);
|
||||
if (m != null && m.poseModel(entity, limbAngle, limbDistance, age, headYaw, headPitch, armorSlot, layer, pony.body())) {
|
||||
m.render(matrices, getTrimConsumer(provider, armor.getMaterial(), trim, layer), light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (glint) {
|
||||
VertexConsumer glintConsumer = provider.getBuffer(RenderLayer.getArmorEntityGlint());
|
||||
for (var m : models) {
|
||||
m.render(matrices, glintConsumer, light, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static VertexConsumer getTrimConsumer(VertexConsumerProvider provider, RegistryEntry<ArmorMaterial> material, ArmorTrim trim, ArmourLayer layer) {
|
||||
SpriteAtlasTexture armorTrimsAtlas = MinecraftClient.getInstance().getBakedModelManager().getAtlas(TexturedRenderLayers.ARMOR_TRIMS_ATLAS_TEXTURE);
|
||||
Sprite sprite = armorTrimsAtlas.getSprite(
|
||||
layer == ArmourLayer.INNER ? trim.getLeggingsModelId(material) : trim.getGenericModelId(material)
|
||||
);
|
||||
return sprite.getTextureSpecificVertexConsumer(
|
||||
provider.getBuffer(TexturedRenderLayers.getArmorTrims(trim.getPattern().value().decal()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue