)model).render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, red, green, blue, 1.0F);
- }
-
- @Inject(method = "renderArmor", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;hasGlint()Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
- private void onRenderArmor(MatrixStack matrices, VertexConsumerProvider vertexConsumers, T entity, EquipmentSlot armorSlot, int light, A model, CallbackInfo info, ItemStack itemStack, ArmorItem armorItem, boolean bl) {
- boolean bl2 = itemStack.hasGlint();
- boolean check = true;
-
- for(var function : ArmorModelPredicateProviderRegistry.providers()) {
- if(function.invert((predicate, provider) -> {
- if(predicate.test(itemStack, entity)) {
- provider.invert(itemStack, entity, bl).accept((texture, color) -> {
- float r = (float)(color >> 16 & 0xFF) / 255.0F;
- float g = (float)(color >> 8 & 0xFF) / 255.0F;
- float b = (float)(color & 0xFF) / 255.0F;
- this.amp_renderArmorParts(matrices, vertexConsumers, light, texture, bl2, model, r, g, b);
- });
-
- return true;
- } else {
- return false;
- }
- })) {
- check = false;
- }
- }
-
- if(check) {
- this.amp_renderArmorParts(matrices, vertexConsumers, light, new Identifier("minecraft:textures/models/armor/" + armorItem.getMaterial().getName() + "_layer_" + (bl ? 2 : 1) + ".png"), bl2, model, 1.0F, 1.0F, 1.0F);
- }
-
- info.cancel();
- }
-}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderData.java b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderData.java
new file mode 100644
index 0000000..61942a7
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderData.java
@@ -0,0 +1,13 @@
+package com.github.clevernucleus.armorrenderlib.api;
+
+@FunctionalInterface
+public interface ArmorRenderData {
+
+ /**
+ *
+ * @param texturePath
+ * @param color
+ * @param hasGlint
+ */
+ void accept(final String texturePath, final int color, final boolean hasGlint);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLayer.java b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLayer.java
new file mode 100644
index 0000000..9e0e9a5
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLayer.java
@@ -0,0 +1,18 @@
+package com.github.clevernucleus.armorrenderlib.api;
+
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ItemStack;
+
+@FunctionalInterface
+public interface ArmorRenderLayer {
+
+ /**
+ *
+ * @param itemStack
+ * @param livingEntity
+ * @param slot
+ * @return
+ */
+ ArmorRenderProvider render(final ItemStack itemStack, final LivingEntity livingEntity, final EquipmentSlot slot);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLib.java b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLib.java
new file mode 100644
index 0000000..a19092b
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderLib.java
@@ -0,0 +1,26 @@
+package com.github.clevernucleus.armorrenderlib.api;
+
+import net.minecraft.item.ItemConvertible;
+
+/**
+ * Use this to register armor render layers!
+ *
+ * @author CleverNucleus
+ *
+ */
+public interface ArmorRenderLib {
+ /**
+ *
+ * Registers an armor render layer for the input item(s). The same armor render layer can be registered for multiple items. The same item(s) can have multiple armor render layers. The armor render layer specifies what armor texture should be used, what color should be applied (if any) and whether it has a glint.
+ *
+ *
+ * This is an extension of {@link net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderer#render(net.minecraft.client.util.math.MatrixStack, net.minecraft.client.render.VertexConsumerProvider, net.minecraft.item.ItemStack, net.minecraft.entity.LivingEntity, net.minecraft.entity.EquipmentSlot, int, net.minecraft.client.render.entity.model.BipedEntityModel)}.
+ *
+ *
+ * @param layer
+ * @param items
+ */
+ static void register(ArmorRenderLayer layer, ItemConvertible ... items) {
+ com.github.clevernucleus.armorrenderlib.impl.ArmorRenderLibImpl.register(layer, items);
+ }
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderProvider.java b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderProvider.java
new file mode 100644
index 0000000..9e07beb
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/api/ArmorRenderProvider.java
@@ -0,0 +1,11 @@
+package com.github.clevernucleus.armorrenderlib.api;
+
+@FunctionalInterface
+public interface ArmorRenderProvider {
+
+ /**
+ *
+ * @param data
+ */
+ void from(final ArmorRenderData data);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorRenderLibImpl.java b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorRenderLibImpl.java
new file mode 100644
index 0000000..6b5d860
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorRenderLibImpl.java
@@ -0,0 +1,64 @@
+package com.github.clevernucleus.armorrenderlib.impl;
+
+import com.github.clevernucleus.armorrenderlib.api.ArmorRenderLayer;
+import com.github.clevernucleus.armorrenderlib.mixin.ArmorFeatureRendererInvoker;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderer;
+import net.fabricmc.fabric.impl.client.rendering.ArmorRendererRegistryImpl;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.OverlayTexture;
+import net.minecraft.client.render.RenderLayer;
+import net.minecraft.client.render.VertexConsumer;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.client.render.item.ItemRenderer;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ArmorItem;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemConvertible;
+import net.minecraft.item.ItemStack;
+
+public final class ArmorRenderLibImpl {
+ private static final Multimap- RENDERERS = ArrayListMultimap.create();
+
+ @SuppressWarnings("unchecked")
+ private static , A extends BipedEntityModel> void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, ItemStack stack, LivingEntity entity, EquipmentSlot slot, int light, BipedEntityModel contextModel) {
+ if(!(stack.getItem() instanceof ArmorItem)) return;
+ ArmorItem item = (ArmorItem)stack.getItem();
+
+ if(item.getSlotType() != slot) return;
+ var entityRenderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity);
+ ArmorFeatureRenderer armorFeatureRenderer = (ArmorFeatureRenderer)((FeatureRendererAccessor)entityRenderer).getFeatureRenderer(ArmorFeatureRenderer.class);
+ A model = ((ArmorFeatureRendererInvoker)armorFeatureRenderer).invokeGetArmor(slot);
+ contextModel.setAttributes((BipedEntityModel)model);
+ ((ArmorFeatureRendererInvoker)armorFeatureRenderer).invokeSetVisible(model, slot);
+
+ for(ArmorRenderLayer layer : RENDERERS.get(item)) {
+ layer.render(stack, entity, slot).from((path, color, glint) -> {
+ float red = (float)(color >> 16 & 0xFF) / 255.0F;
+ float green = (float)(color >> 8 & 0xFF) / 255.0F;
+ float blue = (float)(color & 0xFF) / 255.0F;
+
+ VertexConsumer vertexConsumer = ItemRenderer.getArmorGlintConsumer(vertexConsumers, RenderLayer.getArmorCutoutNoCull(((ArmorTextureCache)armorFeatureRenderer).getOrCache(path)), false, glint);
+ model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, red, green, blue, 1.0F);
+ });
+ }
+ }
+
+ public static void register(ArmorRenderLayer layer, ItemConvertible ... items) {
+ if(items == null || items.length == 0) return;
+
+ for(ItemConvertible item : items) {
+ if(ArmorRendererRegistryImpl.get(item.asItem()) == null) {
+ ArmorRenderer.register(ArmorRenderLibImpl::render, item);
+ }
+
+ RENDERERS.put(item.asItem(), layer);
+ }
+ }
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorTextureCache.java b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorTextureCache.java
new file mode 100644
index 0000000..492415a
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/ArmorTextureCache.java
@@ -0,0 +1,7 @@
+package com.github.clevernucleus.armorrenderlib.impl;
+
+import net.minecraft.util.Identifier;
+
+public interface ArmorTextureCache {
+ Identifier getOrCache(final String path);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/impl/FeatureRendererAccessor.java b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/FeatureRendererAccessor.java
new file mode 100644
index 0000000..a6330f7
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/impl/FeatureRendererAccessor.java
@@ -0,0 +1,9 @@
+package com.github.clevernucleus.armorrenderlib.impl;
+
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.entity.LivingEntity;
+
+public interface FeatureRendererAccessor> {
+ ArmorFeatureRenderer, ?, ?> getFeatureRenderer(Object key);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererInvoker.java b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererInvoker.java
new file mode 100644
index 0000000..541d6e5
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererInvoker.java
@@ -0,0 +1,18 @@
+package com.github.clevernucleus.armorrenderlib.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+
+@Mixin(ArmorFeatureRenderer.class)
+public interface ArmorFeatureRendererInvoker, A extends BipedEntityModel> {
+ @Invoker("getArmor")
+ public A invokeGetArmor(EquipmentSlot slot);
+
+ @Invoker("setVisible")
+ public void invokeSetVisible(A bipedModel, EquipmentSlot slot);
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererMixin.java b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererMixin.java
new file mode 100644
index 0000000..bf0e49e
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/ArmorFeatureRendererMixin.java
@@ -0,0 +1,25 @@
+package com.github.clevernucleus.armorrenderlib.mixin;
+
+import java.util.Map;
+
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import com.github.clevernucleus.armorrenderlib.impl.ArmorTextureCache;
+
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.util.Identifier;
+
+@Mixin(value = ArmorFeatureRenderer.class, priority = 900)
+abstract class ArmorFeatureRendererMixin implements ArmorTextureCache {
+
+ @Shadow
+ @Final
+ private static Map ARMOR_TEXTURE_CACHE;
+
+ @Override
+ public Identifier getOrCache(final String path) {
+ return ARMOR_TEXTURE_CACHE.computeIfAbsent(path, Identifier::new);
+ }
+}
diff --git a/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/LivingEntityRendererMixin.java b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/LivingEntityRendererMixin.java
new file mode 100644
index 0000000..4ebb4d8
--- /dev/null
+++ b/src/main/java/com/github/clevernucleus/armorrenderlib/mixin/LivingEntityRendererMixin.java
@@ -0,0 +1,45 @@
+package com.github.clevernucleus.armorrenderlib.mixin;
+
+import java.util.List;
+import java.util.Map;
+
+import org.objectweb.asm.Opcodes;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import com.github.clevernucleus.armorrenderlib.impl.FeatureRendererAccessor;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.entity.LivingEntity;
+
+@Mixin(LivingEntityRenderer.class)
+abstract class LivingEntityRendererMixin> implements FeatureRendererAccessor {
+
+ @Unique
+ private final Map>, FeatureRenderer> arl_features = new Object2ObjectArrayMap<>();
+
+ @SuppressWarnings("unchecked")
+ @Inject(method = "addFeature", at = @At("HEAD"), cancellable = true)
+ private void arl_addFeature(FeatureRenderer feature, CallbackInfoReturnable info) {
+ this.arl_features.put((Class extends FeatureRenderer>)feature.getClass(), feature);
+ info.setReturnValue(true);
+ }
+
+ @Redirect(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/entity/LivingEntityRenderer;features:Ljava/util/List;", opcode = Opcodes.GETFIELD))
+ private List> arl_get(LivingEntityRenderer renderer) {
+ return this.arl_features.values().stream().toList();
+ }
+
+ @Override
+ public ArmorFeatureRenderer, ?, ?> getFeatureRenderer(Object key) {
+ return (ArmorFeatureRenderer, ?, ?>)this.arl_features.get(key);
+ }
+}
diff --git a/src/main/resources/armor-model-predicate.mixins.json b/src/main/resources/armorrenderlib.mixins.json
similarity index 52%
rename from src/main/resources/armor-model-predicate.mixins.json
rename to src/main/resources/armorrenderlib.mixins.json
index 0c77989..0c96be4 100644
--- a/src/main/resources/armor-model-predicate.mixins.json
+++ b/src/main/resources/armorrenderlib.mixins.json
@@ -1,13 +1,15 @@
{
"required": true,
"minVersion": "0.8",
- "package": "com.github.clevernucleus.armormodelpredicate.mixin",
+ "package": "com.github.clevernucleus.armorrenderlib.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
- "ArmorFeatureRendererMixin"
+ "LivingEntityRendererMixin",
+ "ArmorFeatureRendererMixin",
+ "ArmorFeatureRendererInvoker"
],
"injectors": {
"defaultRequire": 1
diff --git a/src/main/resources/assets/armor-model-predicate/icon.png b/src/main/resources/assets/armorrenderlib/icon.png
similarity index 100%
rename from src/main/resources/assets/armor-model-predicate/icon.png
rename to src/main/resources/assets/armorrenderlib/icon.png
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index 287f516..ae5c2a6 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -1,19 +1,19 @@
{
"schemaVersion": 1,
- "id": "armor-model-predicate",
+ "id": "armorrenderlib",
"version": "${version}",
- "name": "Armor Model Predicate",
- "description": "Adds armor model predicates to Minecraft using Fabric Mixins.",
+ "name": "Armor Render Lib",
+ "description": "Extends Fabric API's armor renderer registry to enable a more specific implementation.",
"authors": [
"CleverNucleus"
],
"contact": {
- "homepage": "https://github.com/CleverNucleus/ArmorModelPredicate",
- "sources": "https://github.com/CleverNucleus/ArmorModelPredicate"
+ "homepage": "https://github.com/CleverNucleus/ArmorRenderLib",
+ "sources": "https://github.com/CleverNucleus/ArmorRenderLib"
},
"license": "MIT",
- "icon": "assets/armor-model-predicate/icon.png",
+ "icon": "assets/armorrenderlib/icon.png",
"environment": "*",
"entrypoints": {
@@ -22,11 +22,12 @@
]
},
"mixins": [
- "armor-model-predicate.mixins.json"
+ "armorrenderlib.mixins.json"
],
"depends": {
- "fabricloader": ">=0.12.12",
- "minecraft": "1.18.x",
+ "fabricloader": ">=0.14.6",
+ "fabric": ">=0.55.1",
+ "minecraft": "1.18.2",
"java": ">=17"
}
}
\ No newline at end of file