From 9724bae3894dd04552877e8fb26581d802fac834 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:37:42 -0400 Subject: [PATCH 01/11] Add HudRenderEvents --- .../client/rendering/v1/HudRenderEvents.java | 74 +++++++++++++++++++ .../client/rendering/InGameHudMixin.java | 37 ++++++++++ 2 files changed, 111 insertions(+) create mode 100644 fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java new file mode 100644 index 0000000000..dd7b38f6b4 --- /dev/null +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -0,0 +1,74 @@ +/* + * 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.gui.DrawContext; +import net.minecraft.client.render.RenderTickCounter; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Events for rendering elements on the HUD. + *

+ * These events will not be called if the HUD is hidden with F1. + */ +public class HudRenderEvents { + /** + * Called at the start of HUD rendering, right before anything is rendered. + */ + public static final Event START = createEventForStage(); + + /** + * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. + */ + public static final Event AFTER_MISC_OVERLAYS = createEventForStage(); + + /** + * Called after the hotbar, status bars, and experience bar have been rendered, and before the status effects overlays are rendered. + */ + public static final Event AFTER_MAIN_HUD = createEventForStage(); + + /** + * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. + */ + public static final Event BEFORE_CHAT = createEventForStage(); + + /** + * Called after the entire HUD is rendered. + */ + public static final Event LAST = createEventForStage(); + + private static Event createEventForStage() { + return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (context, tickDelta) -> { + for (HudRenderStage listener : listeners) { + listener.onRender(context, tickDelta); + } + }); + } + + @FunctionalInterface + public interface HudRenderStage { + /** + * Called sometime during a specific HUD render stage. + * + * @param context The {@link DrawContext} instance + * @param tickCounter The {@link RenderTickCounter} instance + */ + void onRender(DrawContext context, RenderTickCounter tickCounter); + } +} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index 61f48b3ca2..a21427554b 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -19,16 +19,53 @@ 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.ModifyArg; +import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.LayeredDrawer; import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.render.RenderTickCounter; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderEvents; @Mixin(InGameHud.class) public class InGameHudMixin { + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) + private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { + return (context, tickCounter) -> { + HudRenderEvents.START.invoker().onRender(context, tickCounter); + miscOverlaysLayer.render(context, tickCounter); + HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onRender(context, tickCounter); + }; + } + + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 3)) + private LayeredDrawer.Layer fabric$afterMainHud(LayeredDrawer.Layer mainHudLayer) { + return (context, tickCounter) -> { + mainHudLayer.render(context, tickCounter); + HudRenderEvents.AFTER_MAIN_HUD.invoker().onRender(context, tickCounter); + }; + } + + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) + private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { + return (context, tickCounter) -> { + HudRenderEvents.BEFORE_CHAT.invoker().onRender(context, tickCounter); + beforeChatLayer.render(context, tickCounter); + }; + } + + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 7)) + private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { + return (context, tickCounter) -> { + subtitlesHudLayer.render(context, tickCounter); + HudRenderEvents.LAST.invoker().onRender(context, tickCounter); + }; + } + @Inject(method = "render", at = @At(value = "TAIL")) public void render(DrawContext drawContext, RenderTickCounter tickCounter, CallbackInfo callbackInfo) { HudRenderCallback.EVENT.invoker().onHudRender(drawContext, tickCounter); From 584d9e862563ef1bbc0c6aa022a99ecce91b0328 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 24 Sep 2024 23:33:01 -0400 Subject: [PATCH 02/11] Add HudRenderEventsTests and deprecate HudRenderCallback --- .../rendering/v1/HudRenderCallback.java | 8 +++-- .../client/rendering/v1/HudRenderEvents.java | 4 +-- .../client/rendering/InGameHudMixin.java | 5 +-- .../src/testmod/resources/fabric.mod.json | 1 + .../client/HudRenderEventsTests.java | 35 +++++++++++++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java index 4890d53ed6..f73909b6e4 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderCallback.java @@ -22,10 +22,14 @@ import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; +/** + * @deprecated Use {@link HudRenderEvents} instead. For the closest equivalent, use {@link HudRenderEvents#LAST}. + */ +@Deprecated public interface HudRenderCallback { - Event EVENT = EventFactory.createArrayBacked(HudRenderCallback.class, (listeners) -> (matrixStack, delta) -> { + Event EVENT = EventFactory.createArrayBacked(HudRenderCallback.class, (listeners) -> (context, tickCounter) -> { for (HudRenderCallback event : listeners) { - event.onHudRender(matrixStack, delta); + event.onHudRender(context, tickCounter); } }); diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index dd7b38f6b4..c742d1c150 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -24,8 +24,8 @@ /** * Events for rendering elements on the HUD. - *

- * These events will not be called if the HUD is hidden with F1. + * + *

These events will not be called if the HUD is hidden with F1. */ public class HudRenderEvents { /** diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index a21427554b..f4e134e33c 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -43,9 +43,9 @@ public class InGameHudMixin { } @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 3)) - private LayeredDrawer.Layer fabric$afterMainHud(LayeredDrawer.Layer mainHudLayer) { + private LayeredDrawer.Layer fabric$afterMainHudAndExperienceLevel(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { - mainHudLayer.render(context, tickCounter); + experienceLevelLayer.render(context, tickCounter); HudRenderEvents.AFTER_MAIN_HUD.invoker().onRender(context, tickCounter); }; } @@ -66,6 +66,7 @@ public class InGameHudMixin { }; } + @Deprecated @Inject(method = "render", at = @At(value = "TAIL")) public void render(DrawContext drawContext, RenderTickCounter tickCounter, CallbackInfo callbackInfo) { HudRenderCallback.EVENT.invoker().onHudRender(drawContext, tickCounter); diff --git a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json index 57107b39f9..a24fc8630b 100644 --- a/fabric-rendering-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-rendering-v1/src/testmod/resources/fabric.mod.json @@ -18,6 +18,7 @@ "net.fabricmc.fabric.test.rendering.client.DimensionalRenderingTest", "net.fabricmc.fabric.test.rendering.client.FeatureRendererTest", "net.fabricmc.fabric.test.rendering.client.HudAndShaderTest", + "net.fabricmc.fabric.test.rendering.client.HudRenderEventsTests", "net.fabricmc.fabric.test.rendering.client.TooltipComponentTests", "net.fabricmc.fabric.test.rendering.client.WorldRenderEventsTests" ] diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java new file mode 100644 index 0000000000..0305befa24 --- /dev/null +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -0,0 +1,35 @@ +/* + * 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 net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderEvents; + +public class HudRenderEventsTests implements ClientModInitializer { + @Override + public void onInitializeClient() { + HudRenderEvents.START.register((context, tickCounter) -> { }); + // Render a red square in the center of the screen underneath the crosshair + HudRenderEvents.AFTER_MISC_OVERLAYS.register((context, tickCounter) -> context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, 0xFFFF0000)); + // Render a green rectangle at the bottom of the screen, and it should block the hotbar and status bars + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() - 50, context.getScaledWindowHeight() - 10, 0xFF00FF00)); + // Render a blue rectangle at the bottom left of the screen, and it should be blocked by the chat + HudRenderEvents.BEFORE_CHAT.register((context, tickCounter) -> context.fill(0, context.getScaledWindowHeight() / 2, 100, context.getScaledWindowHeight() - 10, 0xFF0000FF)); + // Render a yellow rectangle at the top of the screen, and it should block the player list + HudRenderEvents.LAST.register((context, tickCounter) -> context.fill(0, 0, context.getScaledWindowWidth(), 100, 0xFFFFFF00)); + } +} From a7ac0f110ea478aa25f8f1f3bdec12b48bb05ce1 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 25 Sep 2024 00:37:36 -0400 Subject: [PATCH 03/11] Update tests --- .../client/HudRenderEventsTests.java | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java index 0305befa24..3ba1c8604c 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -16,20 +16,39 @@ package net.fabricmc.fabric.test.rendering.client; +import net.minecraft.client.MinecraftClient; + import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderEvents; public class HudRenderEventsTests implements ClientModInitializer { @Override public void onInitializeClient() { - HudRenderEvents.START.register((context, tickCounter) -> { }); + // Render a blue rectangle at the top right of the screen, and it should be blocked by misc overlays such as vignette, spyglass, and powder snow + HudRenderEvents.START.register((context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() - 200, 0, context.getScaledWindowWidth(), 30, 0xFF0000FF); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "1. Blue rectangle blocked by overlays", context.getScaledWindowWidth() - 196, 10, 0xFFFFFFFF); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "such as powder snow", context.getScaledWindowWidth() - 111, 20, 0xFFFFFFFF); + }); // Render a red square in the center of the screen underneath the crosshair - HudRenderEvents.AFTER_MISC_OVERLAYS.register((context, tickCounter) -> context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, 0xFFFF0000)); + HudRenderEvents.AFTER_MISC_OVERLAYS.register((context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, 0xFFFF0000); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "2. Red square underneath crosshair", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() / 2 + 10, 0xFFFFFFFF); + }); // Render a green rectangle at the bottom of the screen, and it should block the hotbar and status bars - HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() - 50, context.getScaledWindowHeight() - 10, 0xFF00FF00)); + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() / 2 - 50, context.getScaledWindowHeight() - 50, context.getScaledWindowWidth() / 2 + 50, context.getScaledWindowHeight() - 10, 0xFF00FF00); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "3. This green rectangle should block the hotbar and status bars.", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() - 40, 0xFFFFFFFF); + }); // Render a blue rectangle at the bottom left of the screen, and it should be blocked by the chat - HudRenderEvents.BEFORE_CHAT.register((context, tickCounter) -> context.fill(0, context.getScaledWindowHeight() / 2, 100, context.getScaledWindowHeight() - 10, 0xFF0000FF)); + HudRenderEvents.BEFORE_CHAT.register((context, tickCounter) -> { + context.fill(0, context.getScaledWindowHeight() - 40, 300, context.getScaledWindowHeight() - 50, 0xFF0000FF); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, 0xFFFFFFFF); + }); // Render a yellow rectangle at the top of the screen, and it should block the player list - HudRenderEvents.LAST.register((context, tickCounter) -> context.fill(0, 0, context.getScaledWindowWidth(), 100, 0xFFFFFF00)); + HudRenderEvents.LAST.register((context, tickCounter) -> { + context.fill(0, 0, context.getScaledWindowWidth(), 10, 0xFFFFFF00); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, 0xFFFFFFFF); + }); } } From 668c53313d780e9084c65e4205b4dcdb930e498a Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:49:54 -0400 Subject: [PATCH 04/11] Add client parameter and apply suggestions --- .../client/rendering/v1/HudRenderEvents.java | 12 ++++--- .../client/rendering/InGameHudMixin.java | 17 +++++++--- .../client/HudRenderEventsTests.java | 33 ++++++++++--------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index c742d1c150..49eb56c25a 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.api.client.rendering.v1; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.RenderTickCounter; @@ -27,7 +28,7 @@ * *

These events will not be called if the HUD is hidden with F1. */ -public class HudRenderEvents { +public final class HudRenderEvents { /** * Called at the start of HUD rendering, right before anything is rendered. */ @@ -53,10 +54,12 @@ public class HudRenderEvents { */ public static final Event LAST = createEventForStage(); + private HudRenderEvents() { } + private static Event createEventForStage() { - return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (context, tickDelta) -> { + return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (client, context, tickCounter) -> { for (HudRenderStage listener : listeners) { - listener.onRender(context, tickDelta); + listener.onHudRender(client, context, tickCounter); } }); } @@ -66,9 +69,10 @@ public interface HudRenderStage { /** * Called sometime during a specific HUD render stage. * + * @param client The {@link MinecraftClient} instance * @param context The {@link DrawContext} instance * @param tickCounter The {@link RenderTickCounter} instance */ - void onRender(DrawContext context, RenderTickCounter tickCounter); + void onHudRender(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); } } diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index f4e134e33c..48acba80d6 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -16,13 +16,16 @@ package net.fabricmc.fabric.mixin.client.rendering; +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; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.LayeredDrawer; import net.minecraft.client.gui.hud.InGameHud; @@ -33,12 +36,16 @@ @Mixin(InGameHud.class) public class InGameHudMixin { + @Shadow + @Final + private MinecraftClient client; + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { return (context, tickCounter) -> { - HudRenderEvents.START.invoker().onRender(context, tickCounter); + HudRenderEvents.START.invoker().onHudRender(client, context, tickCounter); miscOverlaysLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onRender(context, tickCounter); + HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onHudRender(client, context, tickCounter); }; } @@ -46,14 +53,14 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$afterMainHudAndExperienceLevel(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { experienceLevelLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MAIN_HUD.invoker().onRender(context, tickCounter); + HudRenderEvents.AFTER_MAIN_HUD.invoker().onHudRender(client, context, tickCounter); }; } @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { - HudRenderEvents.BEFORE_CHAT.invoker().onRender(context, tickCounter); + HudRenderEvents.BEFORE_CHAT.invoker().onHudRender(client, context, tickCounter); beforeChatLayer.render(context, tickCounter); }; } @@ -62,7 +69,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); - HudRenderEvents.LAST.invoker().onRender(context, tickCounter); + HudRenderEvents.LAST.invoker().onHudRender(client, context, tickCounter); }; } diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java index 3ba1c8604c..bf66a45cda 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.test.rendering.client; import net.minecraft.client.MinecraftClient; +import net.minecraft.util.Colors; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderEvents; @@ -25,30 +26,30 @@ public class HudRenderEventsTests implements ClientModInitializer { @Override public void onInitializeClient() { // Render a blue rectangle at the top right of the screen, and it should be blocked by misc overlays such as vignette, spyglass, and powder snow - HudRenderEvents.START.register((context, tickCounter) -> { - context.fill(context.getScaledWindowWidth() - 200, 0, context.getScaledWindowWidth(), 30, 0xFF0000FF); - context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "1. Blue rectangle blocked by overlays", context.getScaledWindowWidth() - 196, 10, 0xFFFFFFFF); - context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "such as powder snow", context.getScaledWindowWidth() - 111, 20, 0xFFFFFFFF); + HudRenderEvents.START.register((client, context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() - 200, 0, context.getScaledWindowWidth(), 30, Colors.BLUE); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "1. Blue rectangle blocked by overlays", context.getScaledWindowWidth() - 196, 10, Colors.WHITE); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "such as powder snow", context.getScaledWindowWidth() - 111, 20, Colors.WHITE); }); // Render a red square in the center of the screen underneath the crosshair - HudRenderEvents.AFTER_MISC_OVERLAYS.register((context, tickCounter) -> { - context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, 0xFFFF0000); - context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "2. Red square underneath crosshair", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() / 2 + 10, 0xFFFFFFFF); + HudRenderEvents.AFTER_MISC_OVERLAYS.register((client, context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, Colors.RED); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "2. Red square underneath crosshair", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() / 2 + 10, Colors.WHITE); }); // Render a green rectangle at the bottom of the screen, and it should block the hotbar and status bars - HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> { - context.fill(context.getScaledWindowWidth() / 2 - 50, context.getScaledWindowHeight() - 50, context.getScaledWindowWidth() / 2 + 50, context.getScaledWindowHeight() - 10, 0xFF00FF00); - context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "3. This green rectangle should block the hotbar and status bars.", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() - 40, 0xFFFFFFFF); + HudRenderEvents.AFTER_MAIN_HUD.register((client, context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() / 2 - 50, context.getScaledWindowHeight() - 50, context.getScaledWindowWidth() / 2 + 50, context.getScaledWindowHeight() - 10, Colors.GREEN); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "3. This green rectangle should block the hotbar and status bars.", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() - 40, Colors.WHITE); }); // Render a blue rectangle at the bottom left of the screen, and it should be blocked by the chat - HudRenderEvents.BEFORE_CHAT.register((context, tickCounter) -> { - context.fill(0, context.getScaledWindowHeight() - 40, 300, context.getScaledWindowHeight() - 50, 0xFF0000FF); - context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, 0xFFFFFFFF); + HudRenderEvents.BEFORE_CHAT.register((client, context, tickCounter) -> { + context.fill(0, context.getScaledWindowHeight() - 40, 300, context.getScaledWindowHeight() - 50, Colors.BLUE); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, Colors.WHITE); }); // Render a yellow rectangle at the top of the screen, and it should block the player list - HudRenderEvents.LAST.register((context, tickCounter) -> { - context.fill(0, 0, context.getScaledWindowWidth(), 10, 0xFFFFFF00); - context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, 0xFFFFFFFF); + HudRenderEvents.LAST.register((client, context, tickCounter) -> { + context.fill(0, 0, context.getScaledWindowWidth(), 10, Colors.YELLOW); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, Colors.WHITE); }); } } From f781eb7e48257b553235014e7ef364597b720c26 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 2 Oct 2024 23:49:32 -0400 Subject: [PATCH 05/11] Split HudRenderEvents into separate interfaces --- .../client/rendering/v1/HudRenderEvents.java | 94 +++++++++++++++---- .../client/rendering/InGameHudMixin.java | 10 +- 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index 49eb56c25a..ec71344205 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -32,47 +32,107 @@ public final class HudRenderEvents { /** * Called at the start of HUD rendering, right before anything is rendered. */ - public static final Event START = createEventForStage(); + public static final Event START = EventFactory.createArrayBacked(Start.class, listeners -> (client, context, tickCounter) -> { + for (Start listener : listeners) { + listener.onHudStart(client, context, tickCounter); + } + }); /** * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. */ - public static final Event AFTER_MISC_OVERLAYS = createEventForStage(); + public static final Event AFTER_MISC_OVERLAYS = EventFactory.createArrayBacked(AfterMiscOverlays.class, listeners -> (client, context, tickCounter) -> { + for (AfterMiscOverlays listener : listeners) { + listener.afterMiscOverlays(client, context, tickCounter); + } + }); /** * Called after the hotbar, status bars, and experience bar have been rendered, and before the status effects overlays are rendered. */ - public static final Event AFTER_MAIN_HUD = createEventForStage(); + public static final Event AFTER_MAIN_HUD = EventFactory.createArrayBacked(AfterMainHud.class, listeners -> (client, context, tickCounter) -> { + for (AfterMainHud listener : listeners) { + listener.afterMainHud(client, context, tickCounter); + } + }); /** * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. */ - public static final Event BEFORE_CHAT = createEventForStage(); + public static final Event BEFORE_CHAT = EventFactory.createArrayBacked(BeforeChat.class, listeners -> (client, context, tickCounter) -> { + for (BeforeChat listener : listeners) { + listener.beforeChat(client, context, tickCounter); + } + }); /** * Called after the entire HUD is rendered. */ - public static final Event LAST = createEventForStage(); + public static final Event LAST = EventFactory.createArrayBacked(Last.class, listeners -> (client, context, tickCounter) -> { + for (Last listener : listeners) { + listener.onHudLast(client, context, tickCounter); + } + }); private HudRenderEvents() { } - private static Event createEventForStage() { - return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (client, context, tickCounter) -> { - for (HudRenderStage listener : listeners) { - listener.onHudRender(client, context, tickCounter); - } - }); + @FunctionalInterface + public interface Start { + /** + * Called at the start of HUD rendering, right before anything is rendered. + * + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta + */ + void onHudStart(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + } + + @FunctionalInterface + public interface AfterMiscOverlays { + /** + * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. + * + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta + */ + void afterMiscOverlays(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + } + + @FunctionalInterface + public interface AfterMainHud { + /** + * Called after the hotbar, status bars, and experience bar have been rendered, and before the status effects overlays are rendered. + * + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta + */ + void afterMainHud(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + } + + @FunctionalInterface + public interface BeforeChat { + /** + * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. + * + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta + */ + void beforeChat(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); } @FunctionalInterface - public interface HudRenderStage { + public interface Last { /** - * Called sometime during a specific HUD render stage. + * Called after the entire HUD is rendered. * - * @param client The {@link MinecraftClient} instance - * @param context The {@link DrawContext} instance - * @param tickCounter The {@link RenderTickCounter} instance + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta */ - void onHudRender(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + void onHudLast(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); } } diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index 48acba80d6..f639a78c5c 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -43,9 +43,9 @@ public class InGameHudMixin { @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { return (context, tickCounter) -> { - HudRenderEvents.START.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.START.invoker().onHudStart(client, context, tickCounter); miscOverlaysLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().afterMiscOverlays(client, context, tickCounter); }; } @@ -53,14 +53,14 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$afterMainHudAndExperienceLevel(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { experienceLevelLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MAIN_HUD.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.AFTER_MAIN_HUD.invoker().afterMainHud(client, context, tickCounter); }; } @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { - HudRenderEvents.BEFORE_CHAT.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.BEFORE_CHAT.invoker().beforeChat(client, context, tickCounter); beforeChatLayer.render(context, tickCounter); }; } @@ -69,7 +69,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); - HudRenderEvents.LAST.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.LAST.invoker().onHudLast(client, context, tickCounter); }; } From f13daa52e3b5c6294da65f2c50bacf5a31834b4d Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 3 Oct 2024 00:29:57 -0400 Subject: [PATCH 06/11] Fix before chat and last --- .../fabric/mixin/client/rendering/InGameHudMixin.java | 4 ++-- .../fabric/test/rendering/client/HudRenderEventsTests.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index f639a78c5c..be2d917b22 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -57,7 +57,7 @@ public class InGameHudMixin { }; } - @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { HudRenderEvents.BEFORE_CHAT.invoker().beforeChat(client, context, tickCounter); @@ -65,7 +65,7 @@ public class InGameHudMixin { }; } - @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 1)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 7)) + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 7)) private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java index bf66a45cda..923f0f986e 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -48,7 +48,7 @@ public void onInitializeClient() { }); // Render a yellow rectangle at the top of the screen, and it should block the player list HudRenderEvents.LAST.register((client, context, tickCounter) -> { - context.fill(0, 0, context.getScaledWindowWidth(), 10, Colors.YELLOW); + context.fill(context.getScaledWindowWidth() / 2 - 150, 0, context.getScaledWindowWidth() / 2 + 150, 15, Colors.YELLOW); context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, Colors.WHITE); }); } From ce182edcb7e193b81bbb0a4195f498a4a89a3771 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:17:20 -0400 Subject: [PATCH 07/11] Add after sleep overlay event and update after main hud injection point --- .../client/rendering/v1/HudRenderEvents.java | 25 +++++++++++++++++-- .../client/rendering/InGameHudMixin.java | 12 +++++++-- .../client/HudRenderEventsTests.java | 10 ++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index ec71344205..4f5326df86 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -48,7 +48,7 @@ public final class HudRenderEvents { }); /** - * Called after the hotbar, status bars, and experience bar have been rendered, and before the status effects overlays are rendered. + * Called after the hotbar, status bars, experience bar, status effects overlays, and boss bar have been rendered, and before the sleep overlay is rendered. */ public static final Event AFTER_MAIN_HUD = EventFactory.createArrayBacked(AfterMainHud.class, listeners -> (client, context, tickCounter) -> { for (AfterMainHud listener : listeners) { @@ -56,6 +56,15 @@ public final class HudRenderEvents { } }); + /** + * Called after the sleep overlay has been rendered, and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle are rendered. + */ + public static final Event AFTER_SLEEP_OVERLAY = EventFactory.createArrayBacked(AfterSleepOverlay.class, listeners -> (client, context, tickCounter) -> { + for (AfterSleepOverlay listener : listeners) { + listener.afterSleepOverlay(client, context, tickCounter); + } + }); + /** * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. */ @@ -103,7 +112,7 @@ public interface AfterMiscOverlays { @FunctionalInterface public interface AfterMainHud { /** - * Called after the hotbar, status bars, and experience bar have been rendered, and before the status effects overlays are rendered. + * Called after the hotbar, status bars, experience bar, status effects overlays, and boss bar have been rendered, and before the sleep overlay is rendered. * * @param client the {@link MinecraftClient} instance * @param context the {@link DrawContext} instance @@ -112,6 +121,18 @@ public interface AfterMainHud { void afterMainHud(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); } + @FunctionalInterface + public interface AfterSleepOverlay { + /** + * Called after the sleep overlay has been rendered, and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle are rendered. + * + * @param client the {@link MinecraftClient} instance + * @param context the {@link DrawContext} instance + * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta + */ + void afterSleepOverlay(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + } + @FunctionalInterface public interface BeforeChat { /** diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index be2d917b22..d70118d067 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -49,14 +49,22 @@ public class InGameHudMixin { }; } - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 3)) - private LayeredDrawer.Layer fabric$afterMainHudAndExperienceLevel(LayeredDrawer.Layer experienceLevelLayer) { + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) + private LayeredDrawer.Layer fabric$afterMainHudExperienceLevelStatusEffectOverlayAndBossBar(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { experienceLevelLayer.render(context, tickCounter); HudRenderEvents.AFTER_MAIN_HUD.invoker().afterMainHud(client, context, tickCounter); }; } + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) + private LayeredDrawer.Layer fabric$afterSleepOverlay(LayeredDrawer.Layer demoTimerLayer) { + return (context, tickCounter) -> { + HudRenderEvents.AFTER_SLEEP_OVERLAY.invoker().afterSleepOverlay(client, context, tickCounter); + demoTimerLayer.render(context, tickCounter); + }; + } + @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java index 923f0f986e..48e98c7c08 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -41,15 +41,21 @@ public void onInitializeClient() { context.fill(context.getScaledWindowWidth() / 2 - 50, context.getScaledWindowHeight() - 50, context.getScaledWindowWidth() / 2 + 50, context.getScaledWindowHeight() - 10, Colors.GREEN); context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "3. This green rectangle should block the hotbar and status bars.", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() - 40, Colors.WHITE); }); + // Render a yellow rectangle at the right of the screen, and it should be above the sleep overlay but below the scoreboard + HudRenderEvents.AFTER_SLEEP_OVERLAY.register((client, context, tickCounter) -> { + context.fill(context.getScaledWindowWidth() - 240, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth(), context.getScaledWindowHeight() / 2 + 10, Colors.YELLOW); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This yellow rectangle should be above", context.getScaledWindowWidth() - 236, context.getScaledWindowHeight() / 2 - 10, Colors.WHITE); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "the sleep overlay but below the scoreboard.", context.getScaledWindowWidth() - 236, context.getScaledWindowHeight() / 2, Colors.WHITE); + }); // Render a blue rectangle at the bottom left of the screen, and it should be blocked by the chat HudRenderEvents.BEFORE_CHAT.register((client, context, tickCounter) -> { context.fill(0, context.getScaledWindowHeight() - 40, 300, context.getScaledWindowHeight() - 50, Colors.BLUE); - context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, Colors.WHITE); + context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, Colors.WHITE); }); // Render a yellow rectangle at the top of the screen, and it should block the player list HudRenderEvents.LAST.register((client, context, tickCounter) -> { context.fill(context.getScaledWindowWidth() / 2 - 150, 0, context.getScaledWindowWidth() / 2 + 150, 15, Colors.YELLOW); - context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, Colors.WHITE); + context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "6. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, Colors.WHITE); }); } } From 6362810c66b490875a1b162a9f8023c95ea151ed Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:30:38 -0400 Subject: [PATCH 08/11] Add comments for injection points --- .../fabric/mixin/client/rendering/InGameHudMixin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index d70118d067..5aa9e12ad8 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -40,6 +40,7 @@ public class InGameHudMixin { @Final private MinecraftClient client; + // Targeting the first addLayer call of the first layered drawer, currently the misc overlays layer (renderMiscOverlays) as of 1.21. @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { return (context, tickCounter) -> { @@ -49,6 +50,7 @@ public class InGameHudMixin { }; } + // Targeting the last addLayer call of the first layered drawer, which is after the main hud, currently the boss bar layer (bossBarHud.render) as of 1.21. @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$afterMainHudExperienceLevelStatusEffectOverlayAndBossBar(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { @@ -57,6 +59,7 @@ public class InGameHudMixin { }; } + // Targeting the first addLayer call of the second layered drawer, currently the demo timer layer (renderDemoTimer) as of 1.21. @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$afterSleepOverlay(LayeredDrawer.Layer demoTimerLayer) { return (context, tickCounter) -> { @@ -65,6 +68,7 @@ public class InGameHudMixin { }; } + // Targeting the chat layer (renderChat), currently the sixth addLayer call of the second layered drawer as of 1.21. @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { @@ -73,6 +77,7 @@ public class InGameHudMixin { }; } + // Targeting the last addLayer call of the second layered drawer, currently the subtitles hud layer (subtitlesHud.render) as of 1.21. @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 7)) private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { @@ -81,6 +86,7 @@ public class InGameHudMixin { }; } + // Inject after the HUD is rendered. Deprecated in favor of HudRenderEvents. @Deprecated @Inject(method = "render", at = @At(value = "TAIL")) public void render(DrawContext drawContext, RenderTickCounter tickCounter, CallbackInfo callbackInfo) { From 28557b12b3aaf90526698ffa0df246d8acea5e52 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:08:28 -0400 Subject: [PATCH 09/11] Revert splitting HudRenderEvents into separate interfaces --- .../client/rendering/v1/HudRenderEvents.java | 106 +++--------------- .../client/rendering/InGameHudMixin.java | 12 +- 2 files changed, 21 insertions(+), 97 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index 4f5326df86..5c83b2620b 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -32,128 +32,52 @@ public final class HudRenderEvents { /** * Called at the start of HUD rendering, right before anything is rendered. */ - public static final Event START = EventFactory.createArrayBacked(Start.class, listeners -> (client, context, tickCounter) -> { - for (Start listener : listeners) { - listener.onHudStart(client, context, tickCounter); - } - }); + public static final Event START = createEventForStage(); /** * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. */ - public static final Event AFTER_MISC_OVERLAYS = EventFactory.createArrayBacked(AfterMiscOverlays.class, listeners -> (client, context, tickCounter) -> { - for (AfterMiscOverlays listener : listeners) { - listener.afterMiscOverlays(client, context, tickCounter); - } - }); + public static final Event AFTER_MISC_OVERLAYS = createEventForStage(); /** * Called after the hotbar, status bars, experience bar, status effects overlays, and boss bar have been rendered, and before the sleep overlay is rendered. */ - public static final Event AFTER_MAIN_HUD = EventFactory.createArrayBacked(AfterMainHud.class, listeners -> (client, context, tickCounter) -> { - for (AfterMainHud listener : listeners) { - listener.afterMainHud(client, context, tickCounter); - } - }); + public static final Event AFTER_MAIN_HUD = createEventForStage(); /** * Called after the sleep overlay has been rendered, and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle are rendered. */ - public static final Event AFTER_SLEEP_OVERLAY = EventFactory.createArrayBacked(AfterSleepOverlay.class, listeners -> (client, context, tickCounter) -> { - for (AfterSleepOverlay listener : listeners) { - listener.afterSleepOverlay(client, context, tickCounter); - } - }); + public static final Event AFTER_SLEEP_OVERLAY = createEventForStage(); /** * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. */ - public static final Event BEFORE_CHAT = EventFactory.createArrayBacked(BeforeChat.class, listeners -> (client, context, tickCounter) -> { - for (BeforeChat listener : listeners) { - listener.beforeChat(client, context, tickCounter); - } - }); + public static final Event BEFORE_CHAT = createEventForStage(); /** * Called after the entire HUD is rendered. */ - public static final Event LAST = EventFactory.createArrayBacked(Last.class, listeners -> (client, context, tickCounter) -> { - for (Last listener : listeners) { - listener.onHudLast(client, context, tickCounter); - } - }); + public static final Event LAST = createEventForStage(); private HudRenderEvents() { } - @FunctionalInterface - public interface Start { - /** - * Called at the start of HUD rendering, right before anything is rendered. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void onHudStart(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); - } - - @FunctionalInterface - public interface AfterMiscOverlays { - /** - * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void afterMiscOverlays(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); - } - - @FunctionalInterface - public interface AfterMainHud { - /** - * Called after the hotbar, status bars, experience bar, status effects overlays, and boss bar have been rendered, and before the sleep overlay is rendered. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void afterMainHud(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); - } - - @FunctionalInterface - public interface AfterSleepOverlay { - /** - * Called after the sleep overlay has been rendered, and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle are rendered. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void afterSleepOverlay(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); - } - - @FunctionalInterface - public interface BeforeChat { - /** - * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void beforeChat(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + private static Event createEventForStage() { + return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (client, context, tickCounter) -> { + for (HudRenderStage listener : listeners) { + listener.onHudRender(client, context, tickCounter); + } + }); } @FunctionalInterface - public interface Last { + public interface HudRenderStage { /** - * Called after the entire HUD is rendered. + * Called during a HUD render stage. * * @param client the {@link MinecraftClient} instance * @param context the {@link DrawContext} instance * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta */ - void onHudLast(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); + void onHudRender(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); } } diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index 5aa9e12ad8..234cb8c211 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -44,9 +44,9 @@ public class InGameHudMixin { @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { return (context, tickCounter) -> { - HudRenderEvents.START.invoker().onHudStart(client, context, tickCounter); + HudRenderEvents.START.invoker().onHudRender(client, context, tickCounter); miscOverlaysLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().afterMiscOverlays(client, context, tickCounter); + HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onHudRender(client, context, tickCounter); }; } @@ -55,7 +55,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$afterMainHudExperienceLevelStatusEffectOverlayAndBossBar(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { experienceLevelLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MAIN_HUD.invoker().afterMainHud(client, context, tickCounter); + HudRenderEvents.AFTER_MAIN_HUD.invoker().onHudRender(client, context, tickCounter); }; } @@ -63,7 +63,7 @@ public class InGameHudMixin { @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$afterSleepOverlay(LayeredDrawer.Layer demoTimerLayer) { return (context, tickCounter) -> { - HudRenderEvents.AFTER_SLEEP_OVERLAY.invoker().afterSleepOverlay(client, context, tickCounter); + HudRenderEvents.AFTER_SLEEP_OVERLAY.invoker().onHudRender(client, context, tickCounter); demoTimerLayer.render(context, tickCounter); }; } @@ -72,7 +72,7 @@ public class InGameHudMixin { @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { - HudRenderEvents.BEFORE_CHAT.invoker().beforeChat(client, context, tickCounter); + HudRenderEvents.BEFORE_CHAT.invoker().onHudRender(client, context, tickCounter); beforeChatLayer.render(context, tickCounter); }; } @@ -82,7 +82,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); - HudRenderEvents.LAST.invoker().onHudLast(client, context, tickCounter); + HudRenderEvents.LAST.invoker().onHudRender(client, context, tickCounter); }; } From 0d2bcf291eda8c1b5353412e421323e09eebd2c2 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:35:55 -0400 Subject: [PATCH 10/11] Use vanilla layered drawer layer interface --- .../client/rendering/v1/HudRenderEvents.java | 36 ++++++------------- .../client/rendering/InGameHudMixin.java | 12 +++---- .../client/HudRenderEventsTests.java | 12 +++---- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java index 5c83b2620b..d405274c4f 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/HudRenderEvents.java @@ -16,9 +16,7 @@ package net.fabricmc.fabric.api.client.rendering.v1; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.gui.LayeredDrawer; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; @@ -32,52 +30,40 @@ public final class HudRenderEvents { /** * Called at the start of HUD rendering, right before anything is rendered. */ - public static final Event START = createEventForStage(); + public static final Event START = createEventForStage(); /** * Called after misc overlays (vignette, spyglass, and powder snow) have been rendered, and before the crosshair is rendered. */ - public static final Event AFTER_MISC_OVERLAYS = createEventForStage(); + public static final Event AFTER_MISC_OVERLAYS = createEventForStage(); /** * Called after the hotbar, status bars, experience bar, status effects overlays, and boss bar have been rendered, and before the sleep overlay is rendered. */ - public static final Event AFTER_MAIN_HUD = createEventForStage(); + public static final Event AFTER_MAIN_HUD = createEventForStage(); /** * Called after the sleep overlay has been rendered, and before the demo timer, debug HUD, scoreboard, overlay message (action bar), and title and subtitle are rendered. */ - public static final Event AFTER_SLEEP_OVERLAY = createEventForStage(); + public static final Event AFTER_SLEEP_OVERLAY = createEventForStage(); /** * Called after the debug HUD, scoreboard, overlay message (action bar), and title and subtitle have been rendered, and before the {@link net.minecraft.client.gui.hud.ChatHud} is rendered. */ - public static final Event BEFORE_CHAT = createEventForStage(); + public static final Event BEFORE_CHAT = createEventForStage(); /** * Called after the entire HUD is rendered. */ - public static final Event LAST = createEventForStage(); + public static final Event LAST = createEventForStage(); private HudRenderEvents() { } - private static Event createEventForStage() { - return EventFactory.createArrayBacked(HudRenderStage.class, listeners -> (client, context, tickCounter) -> { - for (HudRenderStage listener : listeners) { - listener.onHudRender(client, context, tickCounter); + private static Event createEventForStage() { + return EventFactory.createArrayBacked(LayeredDrawer.Layer.class, listeners -> (context, tickCounter) -> { + for (LayeredDrawer.Layer listener : listeners) { + listener.render(context, tickCounter); } }); } - - @FunctionalInterface - public interface HudRenderStage { - /** - * Called during a HUD render stage. - * - * @param client the {@link MinecraftClient} instance - * @param context the {@link DrawContext} instance - * @param tickCounter the {@link RenderTickCounter} instance with access to tick delta - */ - void onHudRender(MinecraftClient client, DrawContext context, RenderTickCounter tickCounter); - } } diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index 234cb8c211..0c80d3a582 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -44,9 +44,9 @@ public class InGameHudMixin { @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { return (context, tickCounter) -> { - HudRenderEvents.START.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.START.invoker().render(context, tickCounter); miscOverlaysLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.AFTER_MISC_OVERLAYS.invoker().render(context, tickCounter); }; } @@ -55,7 +55,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$afterMainHudExperienceLevelStatusEffectOverlayAndBossBar(LayeredDrawer.Layer experienceLevelLayer) { return (context, tickCounter) -> { experienceLevelLayer.render(context, tickCounter); - HudRenderEvents.AFTER_MAIN_HUD.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.AFTER_MAIN_HUD.invoker().render(context, tickCounter); }; } @@ -63,7 +63,7 @@ public class InGameHudMixin { @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$afterSleepOverlay(LayeredDrawer.Layer demoTimerLayer) { return (context, tickCounter) -> { - HudRenderEvents.AFTER_SLEEP_OVERLAY.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.AFTER_SLEEP_OVERLAY.invoker().render(context, tickCounter); demoTimerLayer.render(context, tickCounter); }; } @@ -72,7 +72,7 @@ public class InGameHudMixin { @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 5)) private LayeredDrawer.Layer fabric$beforeChat(LayeredDrawer.Layer beforeChatLayer) { return (context, tickCounter) -> { - HudRenderEvents.BEFORE_CHAT.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.BEFORE_CHAT.invoker().render(context, tickCounter); beforeChatLayer.render(context, tickCounter); }; } @@ -82,7 +82,7 @@ public class InGameHudMixin { private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); - HudRenderEvents.LAST.invoker().onHudRender(client, context, tickCounter); + HudRenderEvents.LAST.invoker().render(context, tickCounter); }; } diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java index 48e98c7c08..508e97505a 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/HudRenderEventsTests.java @@ -26,34 +26,34 @@ public class HudRenderEventsTests implements ClientModInitializer { @Override public void onInitializeClient() { // Render a blue rectangle at the top right of the screen, and it should be blocked by misc overlays such as vignette, spyglass, and powder snow - HudRenderEvents.START.register((client, context, tickCounter) -> { + HudRenderEvents.START.register((context, tickCounter) -> { context.fill(context.getScaledWindowWidth() - 200, 0, context.getScaledWindowWidth(), 30, Colors.BLUE); context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "1. Blue rectangle blocked by overlays", context.getScaledWindowWidth() - 196, 10, Colors.WHITE); context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "such as powder snow", context.getScaledWindowWidth() - 111, 20, Colors.WHITE); }); // Render a red square in the center of the screen underneath the crosshair - HudRenderEvents.AFTER_MISC_OVERLAYS.register((client, context, tickCounter) -> { + HudRenderEvents.AFTER_MISC_OVERLAYS.register((context, tickCounter) -> { context.fill(context.getScaledWindowWidth() / 2 - 10, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth() / 2 + 10, context.getScaledWindowHeight() / 2 + 10, Colors.RED); context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "2. Red square underneath crosshair", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() / 2 + 10, Colors.WHITE); }); // Render a green rectangle at the bottom of the screen, and it should block the hotbar and status bars - HudRenderEvents.AFTER_MAIN_HUD.register((client, context, tickCounter) -> { + HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> { context.fill(context.getScaledWindowWidth() / 2 - 50, context.getScaledWindowHeight() - 50, context.getScaledWindowWidth() / 2 + 50, context.getScaledWindowHeight() - 10, Colors.GREEN); context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "3. This green rectangle should block the hotbar and status bars.", context.getScaledWindowWidth() / 2, context.getScaledWindowHeight() - 40, Colors.WHITE); }); // Render a yellow rectangle at the right of the screen, and it should be above the sleep overlay but below the scoreboard - HudRenderEvents.AFTER_SLEEP_OVERLAY.register((client, context, tickCounter) -> { + HudRenderEvents.AFTER_SLEEP_OVERLAY.register((context, tickCounter) -> { context.fill(context.getScaledWindowWidth() - 240, context.getScaledWindowHeight() / 2 - 10, context.getScaledWindowWidth(), context.getScaledWindowHeight() / 2 + 10, Colors.YELLOW); context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "4. This yellow rectangle should be above", context.getScaledWindowWidth() - 236, context.getScaledWindowHeight() / 2 - 10, Colors.WHITE); context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "the sleep overlay but below the scoreboard.", context.getScaledWindowWidth() - 236, context.getScaledWindowHeight() / 2, Colors.WHITE); }); // Render a blue rectangle at the bottom left of the screen, and it should be blocked by the chat - HudRenderEvents.BEFORE_CHAT.register((client, context, tickCounter) -> { + HudRenderEvents.BEFORE_CHAT.register((context, tickCounter) -> { context.fill(0, context.getScaledWindowHeight() - 40, 300, context.getScaledWindowHeight() - 50, Colors.BLUE); context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "5. This blue rectangle should be blocked by the chat.", 0, context.getScaledWindowHeight() - 50, Colors.WHITE); }); // Render a yellow rectangle at the top of the screen, and it should block the player list - HudRenderEvents.LAST.register((client, context, tickCounter) -> { + HudRenderEvents.LAST.register((context, tickCounter) -> { context.fill(context.getScaledWindowWidth() / 2 - 150, 0, context.getScaledWindowWidth() / 2 + 150, 15, Colors.YELLOW); context.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "6. This yellow rectangle should block the player list.", context.getScaledWindowWidth() / 2, 0, Colors.WHITE); }); From 4a9d3d8cde4796dbe38860dc8465b306143d3854 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 25 Oct 2024 00:15:24 -0400 Subject: [PATCH 11/11] Cleanup InGameHudMixin --- .../fabric/mixin/client/rendering/InGameHudMixin.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java index 0c80d3a582..df8bc84ece 100644 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java +++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/InGameHudMixin.java @@ -16,16 +16,13 @@ package net.fabricmc.fabric.mixin.client.rendering; -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; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.LayeredDrawer; import net.minecraft.client.gui.hud.InGameHud; @@ -36,10 +33,6 @@ @Mixin(InGameHud.class) public class InGameHudMixin { - @Shadow - @Final - private MinecraftClient client; - // Targeting the first addLayer call of the first layered drawer, currently the misc overlays layer (renderMiscOverlays) as of 1.21. @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 0)) private LayeredDrawer.Layer fabric$beforeStartAndAfterMiscOverlays(LayeredDrawer.Layer miscOverlaysLayer) { @@ -79,7 +72,7 @@ public class InGameHudMixin { // Targeting the last addLayer call of the second layered drawer, currently the subtitles hud layer (subtitlesHud.render) as of 1.21. @ModifyArg(method = "", slice = @Slice(from = @At(value = "NEW", target = "Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 2)), at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/LayeredDrawer;addLayer(Lnet/minecraft/client/gui/LayeredDrawer$Layer;)Lnet/minecraft/client/gui/LayeredDrawer;", ordinal = 7)) - private LayeredDrawer.Layer fabric$AfterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { + private LayeredDrawer.Layer fabric$afterSubtitlesHud(LayeredDrawer.Layer subtitlesHudLayer) { return (context, tickCounter) -> { subtitlesHudLayer.render(context, tickCounter); HudRenderEvents.LAST.invoker().render(context, tickCounter);