diff --git a/fabric-rendering-v1/build.gradle b/fabric-rendering-v1/build.gradle
index ef0e58c3d6..ac1ae68672 100644
--- a/fabric-rendering-v1/build.gradle
+++ b/fabric-rendering-v1/build.gradle
@@ -1,5 +1,5 @@
archivesBaseName = "fabric-rendering-v1"
-version = getSubprojectVersion(project, "1.3.1")
+version = getSubprojectVersion(project, "1.4.0")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
diff --git a/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/api/client/rendering/v1/ArmorRenderingRegistry.java b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/api/client/rendering/v1/ArmorRenderingRegistry.java
new file mode 100644
index 0000000000..82719276f8
--- /dev/null
+++ b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/api/client/rendering/v1/ArmorRenderingRegistry.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.client.rendering.v1;
+
+import java.util.Arrays;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.util.Identifier;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.impl.client.rendering.ArmorRenderingRegistryImpl;
+
+/**
+ * A class for registering custom armor models and textures for {@link Item}, to be provided by a {@link ModelProvider} or {@link TextureProvider}.
+ *
+ *
This can be used to replace existing vanilla armor models and textures conditionally, however each {@link Item}
+ * instance can only allow one {@link ModelProvider} or {@link TextureProvider} respectively, causing potential conflicts
+ * with other mods if you replace the model or texture for vanilla items. Consider using a separate item instead.
+ *
+ * A custom model would probably also require a custom texture to go along it, the model will use the vanilla texture if it is undefined.
+ *
+ * Since armor textures identifier in vanilla is hardcoded to be in the {@code minecraft} namespace, this registry can also be
+ * used to use a custom namespace if desired.
+ */
+@Environment(EnvType.CLIENT)
+public final class ArmorRenderingRegistry {
+ private ArmorRenderingRegistry() {
+ }
+
+ /**
+ * Registers a provider for custom armor models for an item.
+ *
+ * @param provider the provider for the model
+ * @param items the items to be registered for
+ */
+ public static void registerModel(@Nullable ModelProvider provider, Item... items) {
+ registerModel(provider, Arrays.asList(items));
+ }
+
+ /**
+ * Registers a provider for custom armor models for an item.
+ *
+ * @param provider the provider for the model
+ * @param items the items to be registered for
+ */
+ public static void registerModel(@Nullable ModelProvider provider, Iterable- items) {
+ ArmorRenderingRegistryImpl.registerModel(provider, items);
+ }
+
+ /**
+ * Registers a provider for custom texture models for an item.
+ *
+ * @param provider the provider for the texture
+ * @param items the items to be registered for
+ */
+ public static void registerTexture(@Nullable TextureProvider provider, Item... items) {
+ registerTexture(provider, Arrays.asList(items));
+ }
+
+ /**
+ * Registers a provider for custom texture models for an item.
+ *
+ * @param provider the provider for the texture
+ * @param items the items to be registered for
+ */
+ public static void registerTexture(@Nullable TextureProvider provider, Iterable
- items) {
+ ArmorRenderingRegistryImpl.registerTexture(provider, items);
+ }
+
+ /**
+ * Register simple armor items to use the vanilla armor file name under the mods namespace.
+ *
+ * @param identifier The namespace + path to use for the armor texture location.
+ * @param items the items to be registered
+ */
+ public static void registerSimpleTexture(Identifier identifier, Item... items) {
+ registerTexture((entity, stack, slot, secondLayer, suffix, defaultTexture) -> {
+ return new Identifier(identifier.getNamespace(), "textures/models/armor/" + identifier.getPath() + "_layer_" + (secondLayer ? 2 : 1) + (suffix == null ? "" : "_" + suffix) + ".png");
+ }, items);
+ }
+
+ /**
+ * Gets the model of the armor piece.
+ *
+ * @param entity The entity equipping the armor
+ * @param stack The item stack of the armor
+ * @param slot The slot which the armor is in
+ * @param defaultModel The default model that vanilla provides
+ * @return The model of the armor piece.
+ */
+ @NotNull
+ public static BipedEntityModel getArmorModel(LivingEntity entity, ItemStack stack, EquipmentSlot slot, BipedEntityModel defaultModel) {
+ return ArmorRenderingRegistryImpl.getArmorModel(entity, stack, slot, defaultModel);
+ }
+
+ /**
+ * Gets the armor texture {@link net.minecraft.util.Identifier}.
+ *
+ * @param entity The entity equipping the armor
+ * @param stack The item stack of the armor
+ * @param slot The slot which the armor is in
+ * @param secondLayer True if using the second texture layer
+ * @param suffix The texture suffix, used in vanilla by {@link net.minecraft.item.DyeableArmorItem}
+ * @param defaultTexture The default vanilla texture identifier
+ * @return the custom armor texture identifier, return null to use the vanilla ones. Defaulted to the item's registry id.
+ */
+ @NotNull
+ public static Identifier getArmorTexture(LivingEntity entity, ItemStack stack, EquipmentSlot slot, boolean secondLayer, @Nullable String suffix, Identifier defaultTexture) {
+ return ArmorRenderingRegistryImpl.getArmorTexture(entity, stack, slot, secondLayer, suffix, defaultTexture);
+ }
+
+ @FunctionalInterface
+ @Environment(EnvType.CLIENT)
+ public interface ModelProvider {
+ /**
+ * Gets the model of the armor piece.
+ *
+ * @param entity The entity equipping the armor
+ * @param stack The item stack of the armor
+ * @param slot The slot which the armor is in
+ * @param defaultModel The default vanilla armor model
+ * @return The model of the armor piece. Should never be null.
+ */
+ @NotNull
+ BipedEntityModel getArmorModel(LivingEntity entity, ItemStack stack, EquipmentSlot slot, BipedEntityModel defaultModel);
+ }
+
+ @FunctionalInterface
+ @Environment(EnvType.CLIENT)
+ public interface TextureProvider {
+ /**
+ * Gets the armor texture {@link net.minecraft.util.Identifier}.
+ *
+ * @param entity The entity equipping the armor
+ * @param stack The item stack of the armor
+ * @param slot The slot which the armor is in
+ * @param defaultTexture The default vanilla texture identifier
+ * @return the custom armor texture identifier. Should never be null.
+ */
+ @NotNull
+ Identifier getArmorTexture(LivingEntity entity, ItemStack stack, EquipmentSlot slot, boolean secondLayer, @Nullable String suffix, Identifier defaultTexture);
+ }
+}
diff --git a/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorProviderExtensions.java b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorProviderExtensions.java
new file mode 100644
index 0000000000..13166aa39f
--- /dev/null
+++ b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorProviderExtensions.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.client.rendering;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderingRegistry;
+
+public interface ArmorProviderExtensions {
+ @Nullable
+ ArmorRenderingRegistry.ModelProvider fabric_getArmorModelProvider();
+
+ @Nullable
+ ArmorRenderingRegistry.TextureProvider fabric_getArmorTextureProvider();
+
+ void fabric_setArmorModelProvider(@Nullable ArmorRenderingRegistry.ModelProvider provider);
+
+ void fabric_setArmorTextureProvider(@Nullable ArmorRenderingRegistry.TextureProvider provider);
+}
diff --git a/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorRenderingRegistryImpl.java b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorRenderingRegistryImpl.java
new file mode 100644
index 0000000000..4bd3a91e61
--- /dev/null
+++ b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/impl/client/rendering/ArmorRenderingRegistryImpl.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.client.rendering;
+
+import java.util.Objects;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.Identifier;
+
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderingRegistry;
+
+public final class ArmorRenderingRegistryImpl {
+ private ArmorRenderingRegistryImpl() {
+ }
+
+ public static void registerModel(ArmorRenderingRegistry.ModelProvider provider, Iterable
- items) {
+ Objects.requireNonNull(items);
+
+ for (Item item : items) {
+ Objects.requireNonNull(item);
+
+ ((ArmorProviderExtensions) item).fabric_setArmorModelProvider(provider);
+ }
+ }
+
+ public static void registerTexture(ArmorRenderingRegistry.TextureProvider provider, Iterable
- items) {
+ Objects.requireNonNull(items);
+
+ for (Item item : items) {
+ Objects.requireNonNull(item);
+
+ ((ArmorProviderExtensions) item).fabric_setArmorTextureProvider(provider);
+ }
+ }
+
+ public static BipedEntityModel getArmorModel(LivingEntity entity, ItemStack stack, EquipmentSlot slot, BipedEntityModel defaultModel) {
+ if (!stack.isEmpty()) {
+ ArmorRenderingRegistry.ModelProvider provider = ((ArmorProviderExtensions) stack.getItem()).fabric_getArmorModelProvider();
+
+ if (provider != null) {
+ return provider.getArmorModel(entity, stack, slot, defaultModel);
+ }
+ }
+
+ return defaultModel;
+ }
+
+ public static Identifier getArmorTexture(LivingEntity entity, ItemStack stack, EquipmentSlot slot, boolean secondLayer, @Nullable String suffix, Identifier defaultTexture) {
+ if (!stack.isEmpty()) {
+ ArmorRenderingRegistry.TextureProvider provider = ((ArmorProviderExtensions) stack.getItem()).fabric_getArmorTextureProvider();
+
+ if (provider != null) {
+ return provider.getArmorTexture(entity, stack, slot, secondLayer, suffix, defaultTexture);
+ }
+ }
+
+ return defaultTexture;
+ }
+}
diff --git a/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinArmorFeatureRenderer.java b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinArmorFeatureRenderer.java
new file mode 100644
index 0000000000..55d646657e
--- /dev/null
+++ b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinArmorFeatureRenderer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering;
+
+import java.util.Map;
+import java.util.Objects;
+
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+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.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRendererContext;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+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.ItemStack;
+import net.minecraft.util.Identifier;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderingRegistry;
+
+@Mixin(ArmorFeatureRenderer.class)
+@Environment(EnvType.CLIENT)
+public abstract class MixinArmorFeatureRenderer extends FeatureRenderer {
+ @Shadow
+ @Final
+ private static Map ARMOR_TEXTURE_CACHE;
+
+ public MixinArmorFeatureRenderer(FeatureRendererContext context) {
+ super(context);
+ }
+
+ @Unique
+ private LivingEntity storedEntity;
+ @Unique
+ private EquipmentSlot storedSlot;
+
+ @Inject(method = "render", at = @At("HEAD"))
+ private void storeEntity(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntity livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
+ // We store the living entity wearing the armor before we render
+ this.storedEntity = livingEntity;
+ }
+
+ @Inject(method = "renderArmor", at = @At("HEAD"))
+ private void storeSlot(MatrixStack matrices, VertexConsumerProvider vertexConsumers, LivingEntity livingEntity, EquipmentSlot slot, int i, BipedEntityModel bipedEntityModel, CallbackInfo ci) {
+ // We store the current armor slot that is rendering before we render each armor piece
+ this.storedSlot = slot;
+ }
+
+ @Inject(method = "render", at = @At("RETURN"))
+ private void removeStored(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntity livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
+ // We remove the stored data after we render
+ this.storedEntity = null;
+ this.storedSlot = null;
+ }
+
+ @Inject(method = "getArmor", at = @At("RETURN"), cancellable = true)
+ private void selectArmorModel(EquipmentSlot slot, CallbackInfoReturnable> cir) {
+ ItemStack stack = storedEntity.getEquippedStack(slot);
+
+ BipedEntityModel defaultModel = cir.getReturnValue();
+ BipedEntityModel model = ArmorRenderingRegistry.getArmorModel(storedEntity, stack, slot, defaultModel);
+
+ if (model != defaultModel) {
+ cir.setReturnValue(model);
+ }
+ }
+
+ @Inject(method = "getArmorTexture", at = @At(value = "INVOKE", target = "Ljava/util/Map;computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
+ private void getArmorTexture(ArmorItem armorItem, boolean secondLayer, /* @Nullable */ String suffix, CallbackInfoReturnable cir, String vanillaIdentifier) {
+ String texture = ArmorRenderingRegistry.getArmorTexture(storedEntity, storedEntity.getEquippedStack(storedSlot), storedSlot, secondLayer, suffix, new Identifier(vanillaIdentifier)).toString();
+
+ if (!Objects.equals(texture, vanillaIdentifier)) {
+ cir.setReturnValue(ARMOR_TEXTURE_CACHE.computeIfAbsent(texture, Identifier::new));
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinItem.java b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinItem.java
new file mode 100644
index 0000000000..7d3fc300b8
--- /dev/null
+++ b/fabric-rendering-v1/src/main/java/net/fabricmc/fabric/mixin/client/rendering/MixinItem.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.client.rendering;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+
+import net.minecraft.item.Item;
+
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderingRegistry;
+import net.fabricmc.fabric.impl.client.rendering.ArmorProviderExtensions;
+
+@Mixin(Item.class)
+public class MixinItem implements ArmorProviderExtensions {
+ @Unique
+ private ArmorRenderingRegistry.ModelProvider armorModelProvider;
+ @Unique
+ private ArmorRenderingRegistry.TextureProvider armorTextureProvider;
+
+ @Override
+ public ArmorRenderingRegistry.ModelProvider fabric_getArmorModelProvider() {
+ return armorModelProvider;
+ }
+
+ @Override
+ public ArmorRenderingRegistry.TextureProvider fabric_getArmorTextureProvider() {
+ return armorTextureProvider;
+ }
+
+ @Override
+ public void fabric_setArmorModelProvider(ArmorRenderingRegistry.ModelProvider provider) {
+ armorModelProvider = provider;
+ }
+
+ @Override
+ public void fabric_setArmorTextureProvider(ArmorRenderingRegistry.TextureProvider provider) {
+ armorTextureProvider = provider;
+ }
+}
diff --git a/fabric-rendering-v1/src/main/resources/fabric-rendering-v1.mixins.json b/fabric-rendering-v1/src/main/resources/fabric-rendering-v1.mixins.json
index aad088181d..3f55d6a8ac 100644
--- a/fabric-rendering-v1/src/main/resources/fabric-rendering-v1.mixins.json
+++ b/fabric-rendering-v1/src/main/resources/fabric-rendering-v1.mixins.json
@@ -3,9 +3,11 @@
"package": "net.fabricmc.fabric.mixin.client.rendering",
"compatibilityLevel": "JAVA_8",
"client": [
+ "MixinArmorFeatureRenderer",
"MixinBlockColorMap",
"MixinBuiltinModelItemRenderer",
"MixinInGameHud",
+ "MixinItem",
"MixinItemColorMap",
"MixinWorldRenderer"
],
diff --git a/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/CustomArmorTests.java b/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/CustomArmorTests.java
new file mode 100644
index 0000000000..b2311eac97
--- /dev/null
+++ b/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/CustomArmorTests.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.rendering;
+
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.item.ArmorItem;
+import net.minecraft.item.ArmorMaterials;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemGroup;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+
+import net.fabricmc.api.ModInitializer;
+
+public class CustomArmorTests implements ModInitializer {
+ public static Item customModeledArmor;
+ public static Item customTexturedArmor;
+ public static Item simpleTexturedArmor;
+
+ @Override
+ public void onInitialize() {
+ Registry.register(Registry.ITEM, new Identifier("fabric-rendering-v1-testmod:custom_modeled_armor"),
+ customModeledArmor = new ArmorItem(ArmorMaterials.DIAMOND, EquipmentSlot.CHEST, new Item.Settings().group(ItemGroup.COMBAT)));
+
+ Registry.register(Registry.ITEM, new Identifier("fabric-rendering-v1-testmod:custom_textured_armor"),
+ customTexturedArmor = new ArmorItem(ArmorMaterials.DIAMOND, EquipmentSlot.CHEST, new Item.Settings().group(ItemGroup.COMBAT)));
+
+ Registry.register(Registry.ITEM, new Identifier("fabric-rendering-v1-testmod:simple_textured_armor"),
+ simpleTexturedArmor = new ArmorItem(ArmorMaterials.DIAMOND, EquipmentSlot.CHEST, new Item.Settings().group(ItemGroup.COMBAT)));
+ }
+}
diff --git a/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/client/CustomArmorTestsClient.java b/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/client/CustomArmorTestsClient.java
new file mode 100644
index 0000000000..db22faad67
--- /dev/null
+++ b/fabric-rendering-v1/src/testmod/java/net/fabricmc/fabric/test/rendering/client/CustomArmorTestsClient.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.rendering.client;
+
+import java.util.Collections;
+
+import net.minecraft.client.model.ModelPart;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.util.Identifier;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderingRegistry;
+import net.fabricmc.fabric.test.rendering.CustomArmorTests;
+
+@Environment(EnvType.CLIENT)
+public class CustomArmorTestsClient implements ClientModInitializer {
+ @Override
+ public void onInitializeClient() {
+ CustomArmorModel model = new CustomArmorModel(1.0F);
+ ArmorRenderingRegistry.registerModel((entity, stack, slot, defaultModel) -> model, CustomArmorTests.customModeledArmor);
+ ArmorRenderingRegistry.registerTexture((entity, stack, slot, secondLayer, suffix, defaultTexture) ->
+ new Identifier("fabric-rendering-v1-testmod", "textures/cube.png"), CustomArmorTests.customModeledArmor);
+
+ ArmorRenderingRegistry.registerTexture((entity, stack, slot, secondLayer, suffix, defaultTexture) ->
+ new Identifier("fabric-rendering-v1-testmod", "textures/custom_texture.png"), CustomArmorTests.customTexturedArmor);
+
+ ArmorRenderingRegistry.registerSimpleTexture(new Identifier("fabric-rendering-v1-testmod", "simple_textured_armor"), CustomArmorTests.simpleTexturedArmor);
+ }
+
+ private static class CustomArmorModel extends BipedEntityModel {
+ private final ModelPart part;
+
+ CustomArmorModel(float scale) {
+ super(scale, 0, 1, 1);
+ part = new ModelPart(this, 0, 0);
+ part.addCuboid(-5F, 0F, 2F, 10, 10, 10);
+ part.setPivot(0F, 0F, 0F);
+ part.mirror = true;
+ }
+
+ @Override
+ protected Iterable getBodyParts() {
+ return Collections.singleton(part);
+ }
+
+ @Override
+ protected Iterable getHeadParts() {
+ return Collections::emptyIterator;
+ }
+ }
+}
diff --git a/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/cube.png b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/cube.png
new file mode 100644
index 0000000000..6ae593cc53
Binary files /dev/null and b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/cube.png differ
diff --git a/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/custom_texture.png b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/custom_texture.png
new file mode 100644
index 0000000000..d4bcbb9d68
Binary files /dev/null and b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/custom_texture.png differ
diff --git a/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/models/armor/simple_textured_armor_layer_1.png b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/models/armor/simple_textured_armor_layer_1.png
new file mode 100644
index 0000000000..e29f81a2a3
Binary files /dev/null and b/fabric-rendering-v1/src/testmod/resources/assets/fabric-rendering-v1-testmod/textures/models/armor/simple_textured_armor_layer_1.png differ
diff --git a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json
new file mode 100644
index 0000000000..342edb10e6
--- /dev/null
+++ b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json
@@ -0,0 +1,19 @@
+{
+ "schemaVersion": 1,
+ "id": "fabric-rendering-v1-testmod",
+ "name": "Fabric Rendering (v1) Test Mod",
+ "version": "1.0.0",
+ "environment": "*",
+ "license": "Apache-2.0",
+ "depends": {
+ "fabric-rendering-v1": "*"
+ },
+ "entrypoints": {
+ "main": [
+ "net.fabricmc.fabric.test.rendering.CustomArmorTests"
+ ],
+ "client": [
+ "net.fabricmc.fabric.test.rendering.client.CustomArmorTestsClient"
+ ]
+ }
+}