From f1b599275a68ca0d4ec8f6b366edcef9668efd3f Mon Sep 17 00:00:00 2001
From: i509VCB <git@i509.me>
Date: Sun, 14 Feb 2021 12:58:41 -0600
Subject: [PATCH] Add registry for creating entity model layers and texture
 data (#1197)

* Add registry for creating entity model layers and texture data

* Add ApiStatus annotations and document factory method

* Helper -> Registry
---
 .../v1/EntityModelLayerRegistry.java          | 71 +++++++++++++++++++
 .../v1/EntityRendererRegistry.java            |  2 +
 .../registry/EntityModelLayerImpl.java        | 34 +++++++++
 .../registry/EntityModelLayersAccessor.java   | 33 +++++++++
 .../renderer/registry/EntityModelsMixin.java  | 43 +++++++++++
 .../fabric-renderer-registries-v1.mixins.json |  2 +
 6 files changed, 185 insertions(+)
 create mode 100644 fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityModelLayerRegistry.java
 create mode 100644 fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/EntityModelLayerImpl.java
 create mode 100644 fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelLayersAccessor.java
 create mode 100644 fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelsMixin.java

diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityModelLayerRegistry.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityModelLayerRegistry.java
new file mode 100644
index 000000000..c4553f54c
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityModelLayerRegistry.java
@@ -0,0 +1,71 @@
+/*
+ * 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.rendereregistry.v1;
+
+import java.util.Objects;
+
+import org.jetbrains.annotations.ApiStatus;
+
+import net.minecraft.client.model.TexturedModelData;
+import net.minecraft.client.render.entity.model.EntityModelLayer;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.impl.client.renderer.registry.EntityModelLayerImpl;
+import net.fabricmc.fabric.mixin.client.renderer.registry.EntityModelLayersAccessor;
+
+/**
+ * A helpers for registering entity model layers and providers for the layer's textured model data.
+ *
+ * @deprecated Experimental feature, may be removed or changed without further notice: Snapshot feature.
+ */
+@Deprecated
+@ApiStatus.Experimental
+@Environment(EnvType.CLIENT)
+public final class EntityModelLayerRegistry {
+	/**
+	 * Registers an entity model layer and registers a provider for a {@linkplain TexturedModelData}.
+	 *
+	 * @param modelLayer the entity model layer
+	 * @param provider the provider for the textured model data
+	 */
+	public static void registerModelLayer(EntityModelLayer modelLayer, TexturedModelDataProvider provider) {
+		Objects.requireNonNull(modelLayer, "EntityModelLayer cannot be null");
+		Objects.requireNonNull(provider, "TexturedModelDataProvider cannot be null");
+
+		if (EntityModelLayerImpl.PROVIDERS.putIfAbsent(modelLayer, provider) != null) {
+			throw new IllegalArgumentException(String.format("Cannot replace registration for entity model layer \"%s\"", modelLayer));
+		}
+
+		EntityModelLayersAccessor.getLayers().add(modelLayer);
+	}
+
+	private EntityModelLayerRegistry() {
+	}
+
+	@FunctionalInterface
+	@ApiStatus.Experimental
+	@Environment(EnvType.CLIENT)
+	public interface TexturedModelDataProvider {
+		/**
+		 * Creates the textured model data for use in a {@link EntityModelLayer}.
+		 *
+		 * @return the textured model data for the entity model layer.
+		 */
+		TexturedModelData createModelData();
+	}
+}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityRendererRegistry.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityRendererRegistry.java
index 867bea85d..bedff324a 100644
--- a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityRendererRegistry.java
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/EntityRendererRegistry.java
@@ -16,6 +16,8 @@
 
 package net.fabricmc.fabric.api.client.rendereregistry.v1;
 
+import net.minecraft.client.render.entity.EntityRenderDispatcher;
+import net.minecraft.client.render.entity.EntityRenderer;
 import net.minecraft.client.render.entity.EntityRendererFactory;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityType;
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/EntityModelLayerImpl.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/EntityModelLayerImpl.java
new file mode 100644
index 000000000..c2bc300b1
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/EntityModelLayerImpl.java
@@ -0,0 +1,34 @@
+/*
+ * 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.renderer.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.minecraft.client.render.entity.model.EntityModelLayer;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityModelLayerRegistry;
+
+@Environment(EnvType.CLIENT)
+public final class EntityModelLayerImpl {
+	public static final Map<EntityModelLayer, EntityModelLayerRegistry.TexturedModelDataProvider> PROVIDERS = new HashMap<>();
+
+	private EntityModelLayerImpl() {
+	}
+}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelLayersAccessor.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelLayersAccessor.java
new file mode 100644
index 000000000..a0bea64d2
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelLayersAccessor.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.mixin.client.renderer.registry;
+
+import java.util.Set;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import net.minecraft.client.render.entity.model.EntityModelLayer;
+import net.minecraft.client.render.entity.model.EntityModelLayers;
+
+@Mixin(EntityModelLayers.class)
+public interface EntityModelLayersAccessor {
+	@Accessor("LAYERS")
+	static Set<EntityModelLayer> getLayers() {
+		throw new AssertionError("This should not occur!");
+	}
+}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelsMixin.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelsMixin.java
new file mode 100644
index 000000000..9d1627f12
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/EntityModelsMixin.java
@@ -0,0 +1,43 @@
+/*
+ * 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.renderer.registry;
+
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+import net.minecraft.client.model.TexturedModelData;
+import net.minecraft.client.render.entity.model.EntityModelLayer;
+import net.minecraft.client.render.entity.model.EntityModels;
+
+import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityModelLayerRegistry;
+import net.fabricmc.fabric.impl.client.renderer.registry.EntityModelLayerImpl;
+
+@Mixin(EntityModels.class)
+abstract class EntityModelsMixin {
+	@Inject(method = "getModels", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
+	private static void registerExtraModelData(CallbackInfoReturnable<Map<EntityModelLayer, TexturedModelData>> info, ImmutableMap.Builder<EntityModelLayer, TexturedModelData> builder) {
+		for (Map.Entry<EntityModelLayer, EntityModelLayerRegistry.TexturedModelDataProvider> entry : EntityModelLayerImpl.PROVIDERS.entrySet()) {
+			builder.put(entry.getKey(), entry.getValue().createModelData());
+		}
+	}
+}
diff --git a/fabric-renderer-registries-v1/src/main/resources/fabric-renderer-registries-v1.mixins.json b/fabric-renderer-registries-v1/src/main/resources/fabric-renderer-registries-v1.mixins.json
index c6ca53822..b60c3ac34 100644
--- a/fabric-renderer-registries-v1/src/main/resources/fabric-renderer-registries-v1.mixins.json
+++ b/fabric-renderer-registries-v1/src/main/resources/fabric-renderer-registries-v1.mixins.json
@@ -3,6 +3,8 @@
   "package": "net.fabricmc.fabric.mixin.client.renderer.registry",
   "compatibilityLevel": "JAVA_8",
   "client": [
+    "EntityModelLayersAccessor",
+    "EntityModelsMixin",
     "LivingEntityRendererAccessor",
     "MixinBlockEntityRenderers",
     "MixinEntityRenderers"