diff --git a/fabric-renderer-registries-v1/build.gradle b/fabric-renderer-registries-v1/build.gradle
index b85d29f34..9aaf5bf19 100644
--- a/fabric-renderer-registries-v1/build.gradle
+++ b/fabric-renderer-registries-v1/build.gradle
@@ -1,6 +1,8 @@
archivesBaseName = "fabric-renderer-registries-v1"
-version = getSubprojectVersion(project, "2.0.1")
+version = getSubprojectVersion(project, "2.1.0")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
+
+ testmodCompile project(path: ':fabric-lifecycle-events-v1', configuration: 'dev')
}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/LivingEntityFeatureRendererRegistrationCallback.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/LivingEntityFeatureRendererRegistrationCallback.java
new file mode 100644
index 000000000..592971c0f
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/api/client/rendereregistry/v1/LivingEntityFeatureRendererRegistrationCallback.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.api.client.rendereregistry.v1;
+
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.feature.Deadmau5FeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.LivingEntity;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.api.event.Event;
+import net.fabricmc.fabric.api.event.EventFactory;
+
+/**
+ * Called when {@link FeatureRenderer feature renderers} for a {@link LivingEntityRenderer living entity renderer} are registered.
+ *
+ *
Feature renderers are typically used for rendering additional objects on an entity, such as armor, an elytra or {@link Deadmau5FeatureRenderer Deadmau5's ears}.
+ * This callback lets developers add additional feature renderers for use in entity rendering.
+ * Listeners should filter out the specific entity renderer they want to hook into, usually through {@code instanceof} checks or filtering by entity type.
+ * Once listeners find a suitable entity renderer, they should register their feature renderer via the registration helper.
+ *
+ *
For example, to register a feature renderer for a player model, the example below may used:
+ *
EVENT = EventFactory.createArrayBacked(LivingEntityFeatureRendererRegistrationCallback.class, callbacks -> (entityType, entityRenderer, registrationHelper) -> {
+ for (LivingEntityFeatureRendererRegistrationCallback callback : callbacks) {
+ callback.registerRenderers(entityType, entityRenderer, registrationHelper);
+ }
+ });
+
+ /**
+ * Called when feature renderers may be registered.
+ *
+ * @param entityType the entity type of the renderer
+ * @param entityRenderer the entity renderer
+ */
+ void registerRenderers(EntityType extends LivingEntity> entityType, LivingEntityRenderer, ?> entityRenderer, RegistrationHelper registrationHelper);
+
+ /**
+ * A delegate object used to help register feature renderers for an entity renderer.
+ *
+ * This is not meant for implementation by users of the API.
+ */
+ interface RegistrationHelper {
+ /**
+ * Adds a feature renderer to the entity renderer.
+ *
+ * @param featureRenderer the feature renderer
+ * @param the type of entity
+ */
+ void register(FeatureRenderer> featureRenderer);
+ }
+}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/RegistrationHelperImpl.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/RegistrationHelperImpl.java
new file mode 100644
index 000000000..c8f0b1c26
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/impl/client/renderer/registry/RegistrationHelperImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.Objects;
+import java.util.function.Function;
+
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.entity.LivingEntity;
+
+import net.fabricmc.fabric.api.client.rendereregistry.v1.LivingEntityFeatureRendererRegistrationCallback;
+
+public final class RegistrationHelperImpl implements LivingEntityFeatureRendererRegistrationCallback.RegistrationHelper {
+ private final Function, Boolean> delegate;
+
+ public RegistrationHelperImpl(Function, Boolean> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void register(FeatureRenderer> featureRenderer) {
+ Objects.requireNonNull(featureRenderer, "Feature renderer cannot be null");
+ this.delegate.apply(featureRenderer);
+ }
+}
+
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/LivingEntityRendererAccessor.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/LivingEntityRendererAccessor.java
new file mode 100644
index 000000000..1b76f1df0
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/LivingEntityRendererAccessor.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.entity.LivingEntity;
+
+@Mixin(LivingEntityRenderer.class)
+public interface LivingEntityRendererAccessor> {
+ @Invoker("addFeature")
+ boolean callAddFeature(FeatureRenderer featureRenderer);
+}
diff --git a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/MixinEntityRenderDispatcher.java b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/MixinEntityRenderDispatcher.java
index 780ac23d1..0b6b37d13 100644
--- a/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/MixinEntityRenderDispatcher.java
+++ b/fabric-renderer-registries-v1/src/main/java/net/fabricmc/fabric/mixin/client/renderer/registry/MixinEntityRenderDispatcher.java
@@ -18,6 +18,7 @@ package net.fabricmc.fabric.mixin.client.renderer.registry;
import java.util.Map;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -26,20 +27,51 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderer;
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.entity.EntityType;
+import net.minecraft.entity.LivingEntity;
import net.minecraft.resource.ReloadableResourceManager;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
+import net.fabricmc.fabric.api.client.rendereregistry.v1.LivingEntityFeatureRendererRegistrationCallback;
+import net.fabricmc.fabric.impl.client.renderer.registry.RegistrationHelperImpl;
@Mixin(EntityRenderDispatcher.class)
-public class MixinEntityRenderDispatcher {
+public abstract class MixinEntityRenderDispatcher {
@Shadow
- Map, EntityRenderer>> renderers;
+ @Final
+ private Map, EntityRenderer>> renderers;
- @Inject(method = "registerRenderers", at = @At(value = "RETURN"), require = 1)
- public void on_method_23167(ItemRenderer itemRenderer, ReloadableResourceManager manager, CallbackInfo info) {
+ @Shadow
+ @Final
+ private Map modelRenderers;
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Inject(method = "registerRenderers", at = @At(value = "TAIL"))
+ public void onRegisterRenderers(ItemRenderer itemRenderer, ReloadableResourceManager manager, CallbackInfo info) {
final EntityRenderDispatcher me = (EntityRenderDispatcher) (Object) this;
EntityRendererRegistry.INSTANCE.initialize(me, me.textureManager, manager, itemRenderer, renderers);
+
+ // Dispatch events to register feature renderers.
+ for (Map.Entry, EntityRenderer>> entry : this.renderers.entrySet()) {
+ if (entry.getValue() instanceof LivingEntityRenderer) { // Must be living for features
+ LivingEntityRendererAccessor accessor = (LivingEntityRendererAccessor) entry.getValue();
+
+ LivingEntityFeatureRendererRegistrationCallback.EVENT.invoker().registerRenderers((EntityType extends LivingEntity>) entry.getKey(), (LivingEntityRenderer) entry.getValue(), new RegistrationHelperImpl(accessor::callAddFeature));
+ }
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Inject(method = "", at = @At("TAIL"))
+ private void afterRegisterPlayerModels(CallbackInfo ci) {
+ // Players are a fun case, we need to do these separately and per model type
+ for (Map.Entry entry : this.modelRenderers.entrySet()) {
+ LivingEntityRendererAccessor accessor = (LivingEntityRendererAccessor) entry.getValue();
+
+ LivingEntityFeatureRendererRegistrationCallback.EVENT.invoker().registerRenderers(EntityType.PLAYER, entry.getValue(), new RegistrationHelperImpl(accessor::callAddFeature));
+ }
}
}
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 17edfeec3..2a029a6b2 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,7 @@
"package": "net.fabricmc.fabric.mixin.client.renderer.registry",
"compatibilityLevel": "JAVA_8",
"client": [
+ "LivingEntityRendererAccessor",
"MixinBlockEntityRenderDispatcher",
"MixinEntityRenderDispatcher"
],
diff --git a/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererGenericTests.java b/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererGenericTests.java
new file mode 100644
index 000000000..79466c21e
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererGenericTests.java
@@ -0,0 +1,121 @@
+/*
+ * 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.renderer.registry;
+
+import net.minecraft.client.network.AbstractClientPlayerEntity;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.ArmorStandEntityRenderer;
+import net.minecraft.client.render.entity.BipedEntityRenderer;
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.PlayerEntityRenderer;
+import net.minecraft.client.render.entity.feature.ElytraFeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRendererContext;
+import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer;
+import net.minecraft.client.render.entity.model.ArmorStandArmorEntityModel;
+import net.minecraft.client.render.entity.model.PlayerEntityModel;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.decoration.ArmorStandEntity;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.client.rendereregistry.v1.LivingEntityFeatureRendererRegistrationCallback;
+
+/**
+ * This test exists solely for testing generics.
+ * As such it is not in the mod json
+ */
+public class FeatureRendererGenericTests implements ClientModInitializer {
+ @Override
+ public void onInitializeClient() {
+ // These aren't tests in the normal sense. These exist to test that generics are sane.
+ LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, entityRenderer, registrationHelper) -> {
+ if (entityRenderer instanceof PlayerEntityRenderer) {
+ registrationHelper.register(new TestPlayerFeature((PlayerEntityRenderer) entityRenderer));
+
+ // This is T extends AbstractClientPlayerEntity
+ registrationHelper.register(new GenericTestPlayerFeature<>((PlayerEntityRenderer) entityRenderer));
+ }
+
+ if (entityRenderer instanceof ArmorStandEntityRenderer) {
+ registrationHelper.register(new TestArmorStandFeature((ArmorStandEntityRenderer) entityRenderer));
+ }
+
+ // Obviously not recommended, just used for testing generics
+ registrationHelper.register(new ElytraFeatureRenderer<>(entityRenderer));
+
+ if (entityRenderer instanceof BipedEntityRenderer) {
+ // It works, method ref is encouraged
+ registrationHelper.register(new HeldItemFeatureRenderer<>((BipedEntityRenderer, ?>) entityRenderer));
+ }
+ });
+
+ LivingEntityFeatureRendererRegistrationCallback.EVENT.register(this::registerFeatures);
+ }
+
+ private void registerFeatures(EntityType extends LivingEntity> entityType, LivingEntityRenderer, ?> entityRenderer, LivingEntityFeatureRendererRegistrationCallback.RegistrationHelper registrationHelper) {
+ if (entityRenderer instanceof PlayerEntityRenderer) {
+ registrationHelper.register(new TestPlayerFeature((PlayerEntityRenderer) entityRenderer));
+
+ // This is T extends AbstractClientPlayerEntity
+ registrationHelper.register(new GenericTestPlayerFeature<>((PlayerEntityRenderer) entityRenderer));
+ }
+
+ if (entityRenderer instanceof ArmorStandEntityRenderer) {
+ registrationHelper.register(new TestArmorStandFeature((ArmorStandEntityRenderer) entityRenderer));
+ }
+
+ // Obviously not recommended, just used for testing generics.
+ registrationHelper.register(new ElytraFeatureRenderer<>(entityRenderer));
+
+ if (entityRenderer instanceof BipedEntityRenderer) {
+ // It works, method ref is encouraged
+ registrationHelper.register(new HeldItemFeatureRenderer<>((BipedEntityRenderer, ?>) entityRenderer));
+ }
+ }
+
+ static class TestPlayerFeature extends FeatureRenderer> {
+ TestPlayerFeature(FeatureRendererContext> context) {
+ super(context);
+ }
+
+ @Override
+ public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, AbstractClientPlayerEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
+ }
+ }
+
+ static class GenericTestPlayerFeature> extends FeatureRenderer {
+ GenericTestPlayerFeature(FeatureRendererContext context) {
+ super(context);
+ }
+
+ @Override
+ public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
+ }
+ }
+
+ static class TestArmorStandFeature extends FeatureRenderer {
+ TestArmorStandFeature(FeatureRendererContext context) {
+ super(context);
+ }
+
+ @Override
+ public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, ArmorStandEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
+ }
+ }
+}
diff --git a/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererTest.java b/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererTest.java
new file mode 100644
index 000000000..3c32b664e
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/registry/FeatureRendererTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.renderer.registry;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import net.minecraft.block.Blocks;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.network.AbstractClientPlayerEntity;
+import net.minecraft.client.render.OverlayTexture;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.PlayerEntityRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRenderer;
+import net.minecraft.client.render.entity.feature.FeatureRendererContext;
+import net.minecraft.client.render.entity.model.PlayerEntityModel;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EntityType;
+import net.minecraft.util.registry.Registry;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
+import net.fabricmc.fabric.api.client.rendereregistry.v1.LivingEntityFeatureRendererRegistrationCallback;
+
+public final class FeatureRendererTest implements ClientModInitializer {
+ private static final Logger LOGGER = LogManager.getLogger(FeatureRendererTest.class);
+ private int playerRegistrations = 0;
+
+ @Override
+ public void onInitializeClient() {
+ LOGGER.info("Registering test feature renderer");
+ LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, entityRenderer, registrationHelper) -> {
+ // minecraft:player SHOULD be printed twice
+ LOGGER.info(String.format("Received registration for %s", Registry.ENTITY_TYPE.getId(entityType)));
+
+ if (entityType == EntityType.PLAYER) {
+ this.playerRegistrations++;
+ }
+
+ if (entityRenderer instanceof PlayerEntityRenderer) {
+ registrationHelper.register(new TestPlayerFeatureRenderer((PlayerEntityRenderer) entityRenderer));
+ }
+ });
+
+ ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
+ if (this.playerRegistrations != 2) {
+ throw new AssertionError(String.format("Expected 2 entity feature renderer registration events for \"minecraft:player\" but received %s registrations", this.playerRegistrations));
+ }
+
+ LOGGER.info("Successfully called feature renderer registration events");
+ });
+ }
+
+ private static class TestPlayerFeatureRenderer extends FeatureRenderer> {
+ TestPlayerFeatureRenderer(FeatureRendererContext> context) {
+ super(context);
+ }
+
+ @Override
+ public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, AbstractClientPlayerEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
+ matrices.push();
+
+ // Translate to center above the player's head
+ matrices.translate(-0.5F, -entity.getHeight() + 0.25F, -0.5F);
+ // Render a diamond block above the player's head
+ MinecraftClient.getInstance().getBlockRenderManager().renderBlockAsEntity(Blocks.DIAMOND_BLOCK.getDefaultState(), matrices, vertexConsumers, light, OverlayTexture.DEFAULT_UV);
+
+ matrices.pop();
+ }
+ }
+}
diff --git a/fabric-renderer-registries-v1/src/testmod/resources/fabric.mod.json b/fabric-renderer-registries-v1/src/testmod/resources/fabric.mod.json
new file mode 100644
index 000000000..a9bbee589
--- /dev/null
+++ b/fabric-renderer-registries-v1/src/testmod/resources/fabric.mod.json
@@ -0,0 +1,16 @@
+{
+ "schemaVersion": 1,
+ "id": "fabric-renderer-registries-v1-testmod",
+ "name": "Fabric Render Registries (v1) Test Mod",
+ "version": "1.0.0",
+ "environment": "*",
+ "license": "Apache-2.0",
+ "depends": {
+ "fabric-item-api-v1": "*"
+ },
+ "entrypoints": {
+ "client": [
+ "net.fabricmc.fabric.test.renderer.registry.FeatureRendererTest"
+ ]
+ }
+}