mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-26 17:46:25 -05:00
Add callback to allow registration of feature renderers. (#873)
* Add callback to allow registration of feature renderers. * Laymans terms for those who don't map yarn for a living. * Be a little less generic * Dispatch events in a better spot, play with generics again, move to renderer-registries. Also move this to render registries * Handle players as well * Tweak generics * Hide acceptor impl * Add actual testmod, fix where player events are fired, Simplify to returning a list. * the old style worked fine * registerRenderers * Rename the event interface * Javadoc fixes
This commit is contained in:
parent
02fb8fda0e
commit
e2862de602
9 changed files with 413 additions and 5 deletions
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>For example, to register a feature renderer for a player model, the example below may used:
|
||||
* <blockquote><pre>
|
||||
* LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, entityRenderer, registrationHelper) -> {
|
||||
* if (entityRenderer instanceof PlayerEntityModel) {
|
||||
* registrationHelper.register(new MyFeatureRenderer((PlayerEntityModel) entityRenderer));
|
||||
* }
|
||||
* });
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface LivingEntityFeatureRendererRegistrationCallback {
|
||||
Event<LivingEntityFeatureRendererRegistrationCallback> 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.
|
||||
*
|
||||
* <p>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 <T> the type of entity
|
||||
*/
|
||||
<T extends LivingEntity> void register(FeatureRenderer<T, ? extends EntityModel<T>> featureRenderer);
|
||||
}
|
||||
}
|
|
@ -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<FeatureRenderer<?, ?>, Boolean> delegate;
|
||||
|
||||
public RegistrationHelperImpl(Function<FeatureRenderer<?, ?>, Boolean> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends LivingEntity> void register(FeatureRenderer<T, ? extends EntityModel<T>> featureRenderer) {
|
||||
Objects.requireNonNull(featureRenderer, "Feature renderer cannot be null");
|
||||
this.delegate.apply(featureRenderer);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<T extends LivingEntity, M extends EntityModel<T>> {
|
||||
@Invoker("addFeature")
|
||||
boolean callAddFeature(FeatureRenderer<T, M> featureRenderer);
|
||||
}
|
|
@ -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<EntityType<?>, EntityRenderer<?>> renderers;
|
||||
@Final
|
||||
private Map<EntityType<?>, 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<String, PlayerEntityRenderer> 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<EntityType<?>, 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 = "<init>", 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<String, PlayerEntityRenderer> entry : this.modelRenderers.entrySet()) {
|
||||
LivingEntityRendererAccessor accessor = (LivingEntityRendererAccessor) entry.getValue();
|
||||
|
||||
LivingEntityFeatureRendererRegistrationCallback.EVENT.invoker().registerRenderers(EntityType.PLAYER, entry.getValue(), new RegistrationHelperImpl(accessor::callAddFeature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"package": "net.fabricmc.fabric.mixin.client.renderer.registry",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"client": [
|
||||
"LivingEntityRendererAccessor",
|
||||
"MixinBlockEntityRenderDispatcher",
|
||||
"MixinEntityRenderDispatcher"
|
||||
],
|
||||
|
|
|
@ -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<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
|
||||
TestPlayerFeature(FeatureRendererContext<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> 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<T extends AbstractClientPlayerEntity, M extends PlayerEntityModel<T>> extends FeatureRenderer<T, M> {
|
||||
GenericTestPlayerFeature(FeatureRendererContext<T, M> 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<ArmorStandEntity, ArmorStandArmorEntityModel> {
|
||||
TestArmorStandFeature(FeatureRendererContext<ArmorStandEntity, ArmorStandArmorEntityModel> 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) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
|
||||
TestPlayerFeatureRenderer(FeatureRendererContext<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue