From 7ea0a41fe2b782cb84f84e90807aefa7967bf997 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 14 Nov 2025 10:42:03 -0500 Subject: [PATCH] Fix ItemStack in RenderTooltipEvent always EMPTY, merges RenderTooltipEvent.Background into .Pre (#10655) (#10702) --- .../client/gui/GuiGraphics.java.patch | 33 +++++++-- .../client/ForgeHooksClient.java | 4 +- .../client/event/ForgeEventFactoryClient.java | 4 - .../client/event/RenderTooltipEvent.java | 37 +++------- .../stack_present_in_pre.json | 7 ++ .../debug/client/RenderTooltipTest.java | 73 +++++++++++++++++++ .../item/GatherComponentsEventTest.java | 9 ++- .../render_tooltip_test/META-INF/mods.toml | 1 + 8 files changed, 125 insertions(+), 43 deletions(-) create mode 100644 src/test/generated/render_tooltip_test/data/forge/test_instance/render_tooltip_test/stack_present_in_pre.json create mode 100644 src/test/java/net/minecraftforge/debug/client/RenderTooltipTest.java create mode 100644 src/test/resources/render_tooltip_test/META-INF/mods.toml diff --git a/patches/minecraft/net/minecraft/client/gui/GuiGraphics.java.patch b/patches/minecraft/net/minecraft/client/gui/GuiGraphics.java.patch index da44fe24fa..78a3380751 100644 --- a/patches/minecraft/net/minecraft/client/gui/GuiGraphics.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/GuiGraphics.java.patch @@ -82,11 +82,31 @@ } public void setComponentTooltipForNextFrame(Font p_408650_, List p_407512_, int p_406019_, int p_408123_, @Nullable ResourceLocation p_409993_) { -@@ -1069,11 +_,13 @@ - ClientTooltipPositioner p_409451_, - @Nullable ResourceLocation p_409298_ +@@ -1056,9 +_,14 @@ ) { -+ var preEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipPre(this.tooltipStack, this, p_283678_, p_281696_, guiWidth(), guiHeight(), p_282716_, p_283128_, p_409451_); + if (!p_409928_.isEmpty()) { + if (this.deferredTooltip == null || p_410618_) { +- this.deferredTooltip = () -> this.renderTooltip(p_406605_, p_409928_, p_407794_, p_408784_, p_408798_, p_407676_); ++ final var stackContext = this.tooltipStack; ++ this.deferredTooltip = () -> this.renderTooltip(p_406605_, p_409928_, p_407794_, p_408784_, p_408798_, p_407676_, stackContext); + } + } ++ } ++ ++ public void renderTooltip(Font p_283128_, List p_282716_, int p_283678_, int p_281696_, ClientTooltipPositioner p_409451_, @Nullable ResourceLocation p_409298_) { ++ renderTooltip(p_283128_, p_282716_, p_283678_, p_281696_, p_409451_, p_409298_, ItemStack.EMPTY); + } + + public void renderTooltip( +@@ -1067,13 +_,16 @@ + int p_283678_, + int p_281696_, + ClientTooltipPositioner p_409451_, +- @Nullable ResourceLocation p_409298_ ++ @Nullable ResourceLocation p_409298_, ++ ItemStack itemstack + ) { ++ var preEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipPre(itemstack, this, p_283678_, p_281696_, guiWidth(), guiHeight(), p_282716_, p_283128_, p_409451_, p_409298_); + if (preEvent == null) return; int i = 0; int j = p_282716_.size() == 1 ? -2 : 0; @@ -97,7 +117,7 @@ if (k > i) { i = k; } -@@ -1083,16 +_,17 @@ +@@ -1083,16 +_,16 @@ int l1 = i; int i2 = j; @@ -107,8 +127,7 @@ int i1 = vector2ic.y(); this.pose.pushMatrix(); - TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, p_409298_); -+ var background_event = net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTooltipBackground(this.tooltipStack, this, l, i1, preEvent.getFont(), p_282716_, p_409298_); -+ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, background_event.getBackground()); ++ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, preEvent.getBackground()); int j1 = i1; for (int k1 = 0; k1 < p_282716_.size(); k1++) { diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index 915ee0b2bc..8a5ed900ff 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -658,8 +658,8 @@ public class ForgeHooksClient { return stackFont == null ? fallbackFont : stackFont; } - public static @Nullable RenderTooltipEvent.Pre onRenderTooltipPre(@NotNull ItemStack stack, GuiGraphics graphics, int x, int y, int screenWidth, int screenHeight, @NotNull List components, @NotNull Font fallbackFont, @NotNull ClientTooltipPositioner positioner) { - var preEvent = new RenderTooltipEvent.Pre(stack, graphics, x, y, screenWidth, screenHeight, getTooltipFont(stack, fallbackFont), components, positioner); + public static @Nullable RenderTooltipEvent.Pre onRenderTooltipPre(@NotNull ItemStack stack, GuiGraphics graphics, int x, int y, int screenWidth, int screenHeight, @NotNull List components, @NotNull Font fallbackFont, @NotNull ClientTooltipPositioner positioner, @Nullable ResourceLocation background) { + var preEvent = new RenderTooltipEvent.Pre(stack, graphics, x, y, screenWidth, screenHeight, getTooltipFont(stack, fallbackFont), components, positioner, background); return RenderTooltipEvent.Pre.BUS.post(preEvent) ? null : preEvent; } diff --git a/src/main/java/net/minecraftforge/client/event/ForgeEventFactoryClient.java b/src/main/java/net/minecraftforge/client/event/ForgeEventFactoryClient.java index eba5785da9..1d472d48e1 100644 --- a/src/main/java/net/minecraftforge/client/event/ForgeEventFactoryClient.java +++ b/src/main/java/net/minecraftforge/client/event/ForgeEventFactoryClient.java @@ -244,10 +244,6 @@ public final class ForgeEventFactoryClient { TickEvent.RenderTickEvent.Post.BUS.post(new TickEvent.RenderTickEvent.Post(timer)); } - public static RenderTooltipEvent.Background onRenderTooltipBackground(@NotNull ItemStack stack, GuiGraphics graphics, int x, int y, @NotNull Font font, @NotNull List components, @Nullable ResourceLocation backgroundPrefix) { - return RenderTooltipEvent.Background.BUS.fire(new RenderTooltipEvent.Background(stack, graphics, x, y, font, components, backgroundPrefix)); - } - public static boolean onToastAdd(Toast toast) { return ToastAddEvent.BUS.post(new ToastAddEvent(toast)); } diff --git a/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java b/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java index d1abbe423f..27b771f531 100644 --- a/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java +++ b/src/main/java/net/minecraftforge/client/event/RenderTooltipEvent.java @@ -35,7 +35,6 @@ import java.util.List; * * @see RenderTooltipEvent.GatherComponents * @see RenderTooltipEvent.Pre - * @see RenderTooltipEvent.Background */ @NullMarked public abstract sealed class RenderTooltipEvent extends MutableEvent implements InheritableEvent { @@ -117,7 +116,7 @@ public abstract sealed class RenderTooltipEvent extends MutableEvent implements * *

This event is {@linkplain Cancellable cancellable}. * If this event is cancelled, then the list of components will be empty, causing the tooltip to not be rendered and - * the corresponding {@link RenderTooltipEvent.Pre} and {@link RenderTooltipEvent.Background} to not be fired.

+ * the corresponding {@link RenderTooltipEvent.Pre} to not be fired.

* *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, * only on the {@linkplain LogicalSide#CLIENT logical client}.

@@ -195,11 +194,10 @@ public abstract sealed class RenderTooltipEvent extends MutableEvent implements /** * Fired before the tooltip is rendered. - * This can be used to modify the positioning and font of the tooltip. + * This can be used to modify the positioning, font, and background of the tooltip. * *

This event is {@linkplain Cancellable cancellable}. - * If this event is cancelled, then the tooltip will not be rendered and the corresponding - * {@link RenderTooltipEvent.Background} will not be fired.

+ * If this event is cancelled, then the tooltip will not be rendered * *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, * only on the {@linkplain LogicalSide#CLIENT logical client}.

@@ -210,13 +208,19 @@ public abstract sealed class RenderTooltipEvent extends MutableEvent implements private final int screenWidth; private final int screenHeight; private final ClientTooltipPositioner positioner; + @Nullable + private ResourceLocation background; + @Nullable + private ResourceLocation originalBackground; @ApiStatus.Internal - public Pre(ItemStack stack, GuiGraphics graphics, int x, int y, int screenWidth, int screenHeight, Font font, List components, ClientTooltipPositioner positioner) { + public Pre(ItemStack stack, GuiGraphics graphics, int x, int y, int screenWidth, int screenHeight, Font font, List components, ClientTooltipPositioner positioner, @Nullable ResourceLocation background) { super(stack, graphics, x, y, font, components); this.screenWidth = screenWidth; this.screenHeight = screenHeight; this.positioner = positioner; + this.background = background; + this.originalBackground = background; } /** @@ -266,27 +270,6 @@ public abstract sealed class RenderTooltipEvent extends MutableEvent implements public void setY(int y) { this.y = y; } - } - - /** - * Fired when the tooltip background prefix is determined. - * This can be used to modify the textures to be used for the tooltip background. - * - *

This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, - * only on the {@linkplain LogicalSide#CLIENT logical client}.

- */ - public static final class Background extends RenderTooltipEvent { - public static final EventBus BUS = EventBus.create(Background.class); - - private final @Nullable ResourceLocation originalBackground; - private @Nullable ResourceLocation background; - - @ApiStatus.Internal - public Background(ItemStack stack, GuiGraphics graphics, int x, int y, Font fr, List components, @Nullable ResourceLocation background) { - super(stack, graphics, x, y, fr, components); - this.originalBackground = background; - this.background = background; - } /** * Sets the new prefix for the background texture diff --git a/src/test/generated/render_tooltip_test/data/forge/test_instance/render_tooltip_test/stack_present_in_pre.json b/src/test/generated/render_tooltip_test/data/forge/test_instance/render_tooltip_test/stack_present_in_pre.json new file mode 100644 index 0000000000..83b5a0aa5a --- /dev/null +++ b/src/test/generated/render_tooltip_test/data/forge/test_instance/render_tooltip_test/stack_present_in_pre.json @@ -0,0 +1,7 @@ +{ + "type": "minecraft:function", + "environment": "minecraft:default", + "function": "forge:render_tooltip_test/stack_present_in_pre", + "max_ticks": 100, + "structure": "forge:empty3x3x3" +} \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/debug/client/RenderTooltipTest.java b/src/test/java/net/minecraftforge/debug/client/RenderTooltipTest.java new file mode 100644 index 0000000000..f00295bef5 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/client/RenderTooltipTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.InventoryScreen; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.event.AddGuiOverlayLayersEvent; +import net.minecraftforge.client.event.RenderTooltipEvent; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.gametest.GameTest; +import net.minecraftforge.gametest.GameTestNamespace; +import net.minecraftforge.test.BaseTestMod; + +import java.util.Random; + +@GameTestNamespace("forge") +@Mod(RenderTooltipTest.MODID) +public class RenderTooltipTest extends BaseTestMod { + public static final String MODID = "render_tooltip_test"; + private static boolean testMode = false; + private static int shouldOpen = 0; + // Need some randomness so this test isn't asinine. + private static Object[] possibleChoices = BuiltInRegistries.ITEM.listElements().map(Holder::get).map(Item::getDefaultInstance).toArray(); + private static int itemStack = 0; + private static ItemStack lastItemstackSeenInEvent = null; + public RenderTooltipTest(FMLJavaModLoadingContext context) { + super(context, false, false); + AddGuiOverlayLayersEvent.BUS.addListener(event -> { + event.getLayeredDraw().addWithCondition(rl("render_tooltip_test"), (gg, dt) -> { + gg.setTooltipForNextFrame(Minecraft.getInstance().font, (ItemStack) possibleChoices[itemStack], 50, 50); + }, () -> testMode) ; + }); + } + + @SuppressWarnings("all") + @GameTest + public static void stack_present_in_pre(GameTestHelper helper) { + testMode = true; + shouldOpen = 1; + helper.addEventListener(RenderTooltipEvent.Pre.BUS, event -> { + lastItemstackSeenInEvent = event.getItemStack(); + }); + + helper.addRecordListener(TickEvent.RenderTickEvent.Pre.BUS, (event) -> { + if (shouldOpen == 1) { + Minecraft.getInstance().setScreen(new InventoryScreen(Minecraft.getInstance().player)); + shouldOpen = 2; + } else if (shouldOpen == 2) { + Minecraft.getInstance().setScreen(null); + shouldOpen = 0; + } + }); + itemStack = new Random().nextInt(possibleChoices.length); + helper.runAfterDelay(10, () -> { + testMode = false; + var copyOfLastSeen = lastItemstackSeenInEvent; + boolean testPassed = lastItemstackSeenInEvent == possibleChoices[itemStack]; + lastItemstackSeenInEvent = null; + helper.assertTrue(testPassed, "Itemstack from last tooltip was not correct. Was " + copyOfLastSeen + " expected " + possibleChoices[itemStack]); + helper.succeed(); + }); + } +} \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/debug/gameplay/item/GatherComponentsEventTest.java b/src/test/java/net/minecraftforge/debug/gameplay/item/GatherComponentsEventTest.java index d395ffd4ec..8a6749abb4 100644 --- a/src/test/java/net/minecraftforge/debug/gameplay/item/GatherComponentsEventTest.java +++ b/src/test/java/net/minecraftforge/debug/gameplay/item/GatherComponentsEventTest.java @@ -34,8 +34,11 @@ public class GatherComponentsEventTest extends BaseTestMod { @GameTest public static void is_food(GameTestHelper helper) { - helper.assertTrue(Items.IRON_NUGGET.components().has(DataComponents.FOOD), "Iron Nugget is not edible, failed to apply DataComponents.FOOD to it."); - helper.assertFalse(Items.IRON_INGOT.components().has(DataComponents.FOOD), "Iron Ingot is edible, should not have DataComponents.FOOD"); - helper.succeed(); + helper.runAfterDelay(5, () -> { + helper.assertTrue(Items.IRON_NUGGET.components().has(DataComponents.FOOD), "Iron Nugget is not edible, failed to apply DataComponents.FOOD to it."); + helper.assertFalse(Items.IRON_INGOT.components().has(DataComponents.FOOD), "Iron Ingot is edible, should not have DataComponents.FOOD"); + helper.succeed(); + }); + } } diff --git a/src/test/resources/render_tooltip_test/META-INF/mods.toml b/src/test/resources/render_tooltip_test/META-INF/mods.toml new file mode 100644 index 0000000000..c361869e8e --- /dev/null +++ b/src/test/resources/render_tooltip_test/META-INF/mods.toml @@ -0,0 +1 @@ +clientSideOnly=true \ No newline at end of file