diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateDataExtractor.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateDataExtractor.java new file mode 100644 index 0000000000..757a12415c --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateDataExtractor.java @@ -0,0 +1,24 @@ +/* + * 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 net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.world.entity.Entity; + +public interface EntityRenderStateDataExtractor { + void extract(Entity entity, EntityRenderState state); +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractionCallback.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractionCallback.java new file mode 100644 index 0000000000..1591c2bd4b --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractionCallback.java @@ -0,0 +1,49 @@ +/* + * 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 org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.Nullable; + +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.world.entity.EntityType; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +public interface EntityRenderStateExtractionCallback { + Event EVENT = EventFactory.createArrayBacked( + EntityRenderStateExtractionCallback.class, listeners -> ctx -> { + for (EntityRenderStateExtractionCallback callback : listeners) { + callback.onRenderStateExtraction(ctx); + } + }); + + void onRenderStateExtraction(Context ctx); + + @ApiStatus.NonExtendable + interface Context { + @Nullable EntityType type(); + + EntityRenderer renderer(); + + EntityRendererProvider.Context rendererContext(); + + void add(EntityRenderStateDataExtractor extractor); + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractorHolder.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractorHolder.java new file mode 100644 index 0000000000..bf760d50bb --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/EntityRenderStateExtractorHolder.java @@ -0,0 +1,23 @@ +/* + * 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.List; + +public interface EntityRenderStateExtractorHolder { + void fabric_addExtractors(List extractors); +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/RenderStateExtractionCallbackContextImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/RenderStateExtractionCallbackContextImpl.java new file mode 100644 index 0000000000..380a3df1c2 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/RenderStateExtractionCallbackContextImpl.java @@ -0,0 +1,66 @@ +/* + * 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.ArrayList; +import java.util.List; + +import org.jspecify.annotations.Nullable; + +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.world.entity.EntityType; + +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateDataExtractor; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateExtractionCallback; + +public final class RenderStateExtractionCallbackContextImpl implements EntityRenderStateExtractionCallback.Context { + private final @Nullable EntityType type; + private final EntityRenderer renderer; + private final EntityRendererProvider.Context rendererContext; + private final List extractors = new ArrayList<>(); + + public RenderStateExtractionCallbackContextImpl(@Nullable EntityType type, EntityRenderer renderer, EntityRendererProvider.Context rendererContext) { + this.type = type; + this.renderer = renderer; + this.rendererContext = rendererContext; + } + + @Override + public void add(EntityRenderStateDataExtractor extractor) { + extractors.add(extractor); + } + + @Override + public @Nullable EntityType type() { + return type; + } + + @Override + public EntityRenderer renderer() { + return renderer; + } + + @Override + public EntityRendererProvider.Context rendererContext() { + return rendererContext; + } + + public List extractors() { + return extractors; + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRendererMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRendererMixin.java new file mode 100644 index 0000000000..ec43066f59 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRendererMixin.java @@ -0,0 +1,51 @@ +/* + * 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.ArrayList; +import java.util.List; + +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.callback.CallbackInfo; + +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.world.entity.Entity; + +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateDataExtractor; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateExtractorHolder; + +@Mixin(EntityRenderer.class) +public abstract class EntityRendererMixin implements EntityRenderStateExtractorHolder { + @Unique + private final List renderStateExtractors = new ArrayList<>(); + + @Inject(method = "extractRenderState", at = @At("TAIL")) + private void runRenderStateExtractors(T entity, S state, float partialTicks, CallbackInfo ci) { + for (EntityRenderStateDataExtractor extractor : renderStateExtractors) { + extractor.extract(entity, state); + } + } + + @Override + public void fabric_addExtractors(List extractors) { + this.renderStateExtractors.addAll(extractors); + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRenderersMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRenderersMixin.java index 15bc8618e7..492c3f1f25 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRenderersMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/EntityRenderersMixin.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -34,12 +35,16 @@ import net.minecraft.client.renderer.entity.EntityRenderers; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.client.renderer.entity.player.AvatarRenderer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateExtractionCallback; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRenderStateExtractorHolder; import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityRenderLayerRegistrationCallback; import net.fabricmc.fabric.impl.client.rendering.EntityRendererRegistryImpl; import net.fabricmc.fabric.impl.client.rendering.RegistrationHelperImpl; +import net.fabricmc.fabric.impl.client.rendering.RenderStateExtractionCallbackContextImpl; @Mixin(EntityRenderers.class) public abstract class EntityRenderersMixin { @@ -77,4 +82,22 @@ private static AvatarRenderer createAvatarRenderer(EntityRendererProvider.Contex return entityRenderer; } + + @WrapOperation(method = "lambda$createEntityRenderers$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRendererProvider;create(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;)Lnet/minecraft/client/renderer/entity/EntityRenderer;")) + private static EntityRenderer applyExtractorsToRenderer(EntityRendererProvider instance, EntityRendererProvider.Context context, Operation> original, @Local(argsOnly = true) EntityType entityType) { + EntityRenderer entityRenderer = original.call(instance, context); + RenderStateExtractionCallbackContextImpl ctx = new RenderStateExtractionCallbackContextImpl(entityType, entityRenderer, context); + EntityRenderStateExtractionCallback.EVENT.invoker().onRenderStateExtraction(ctx); + ((EntityRenderStateExtractorHolder) entityRenderer).fabric_addExtractors(ctx.extractors()); + return entityRenderer; + } + + @WrapOperation(method = "createAvatarRenderers", at = @At(value = "NEW", target = "(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;Z)Lnet/minecraft/client/renderer/entity/player/AvatarRenderer;")) + private static AvatarRenderer applyExtractorsToAvatarRenderer(EntityRendererProvider.Context context, boolean slimSteve, Operation> original) { + AvatarRenderer entityRenderer = original.call(context, slimSteve); + RenderStateExtractionCallbackContextImpl ctx = new RenderStateExtractionCallbackContextImpl(null, entityRenderer, context); + EntityRenderStateExtractionCallback.EVENT.invoker().onRenderStateExtraction(ctx); + ((EntityRenderStateExtractorHolder) entityRenderer).fabric_addExtractors(ctx.extractors()); + return entityRenderer; + } } diff --git a/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json b/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json index 2839e47fb3..6349386b7a 100644 --- a/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json +++ b/fabric-rendering-v1/src/client/resources/fabric-rendering-v1.mixins.json @@ -54,5 +54,8 @@ }, "overwrites": { "requireAnnotations": true - } + }, + "mixins": [ + "EntityRendererMixin" + ] }