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