Skip to content

Fix infobook crash when hovering the top-left corner on recipe pages - #237

Merged
rubensworks merged 1 commit into
master-1.20-ltsfrom
fix/infobook-empty-recipe-slot-tooltip-crash
Sep 2, 2026
Merged

Fix infobook crash when hovering the top-left corner on recipe pages#237
rubensworks merged 1 commit into
master-1.20-ltsfrom
fix/infobook-empty-recipe-slot-tooltip-crash

Conversation

@rubensworks

@rubensworks rubensworks commented Sep 1, 2026

Copy link
Copy Markdown
Member

Found while working on CyclopsMC/IntegratedTerminals#213.

Retargeted from master-1.21-lts to master-1.20-lts, since the bug is present there too.

The crash

Moving the mouse into the top-left 16x16 pixels of the screen while any infobook page with a recipe appendix that has an empty slot is open crashes the game:

java.lang.NullPointerException: Cannot invoke "net.minecraft.world.item.ItemStack.isEmpty()" because "itemStack" is null
	at RecipeAppendix.renderItemTooltip(RecipeAppendix.java:153)
	at RecipeAppendix$ItemButton.renderTooltip(RecipeAppendix.java:299)
	at RecipeAppendix.renderToolTips(RecipeAppendix.java:222)
	at RecipeAppendix.postDrawElement(RecipeAppendix.java:213)
	at SectionAppendix.drawScreen(SectionAppendix.java:60)
	at InfoSection.postDrawScreen(InfoSection.java:427)
	at ScreenInfoBook.render(ScreenInfoBook.java:241)

and the FluidStack variant of the same:

java.lang.NullPointerException: Cannot invoke "net.neoforged.neoforge.fluids.FluidStack.isEmpty()" because "fluidStack" is null
	at RecipeAppendix.renderFluidTooltip(RecipeAppendix.java:165)
	at RecipeAppendix$FluidButton.renderTooltip(RecipeAppendix.java:322)
	...

Cause

renderItemForButton and renderFluidForButton only call button.update(...) when the stack is non-empty, so a button for an empty recipe slot never gets an element and is never positioned either: it keeps AdvancedButton's initial (0, 0) position with a null element.

renderToolTips then calls renderTooltip on every button in renderItemHolders regardless, and renderItemTooltip/renderFluidTooltip check the mouse bounds before the empty check:

if(mx >= x && my >= y && mx <= x + SLOT_SIZE && my <= y + SLOT_SIZE && !itemStack.isEmpty() ) {

So the bounds check passes for a button stuck at (0, 0) as soon as the mouse is in the top-left corner, and the null element is dereferenced.

This affects almost every recipe appendix, since empty slots are the norm rather than the exception: any crafting recipe that does not fill the whole 3x3 grid, and any drying basin or squeezer recipe without a fluid input or output.

Fix

ItemButton#renderTooltip and FluidButton#renderTooltip now return early when there is no element. A null element is already an expected state elsewhere in ElementButton (both update and isVisible handle it), so this only brings the tooltip path in line with the rest of the class.

I kept it to that rather than also positioning the buttons of empty slots, since the latter would change which button ends up in renderItemHolders for appendices that render the same button enum more than once per frame, and this is enough to fix the crash.

Testing

Please note that this change is not verified against this branch locally — see below. It is the same change that was verified on master-1.21-lts, where the two classes are structurally identical (same ElementButton contract, same getElement(), same two overrides).

The crash was originally hit and the fix verified on 1.21.1: with a patched build published to mavenLocal and Integrated Dynamics' infobook opened in a dev client, both reproducers — Terminals -> Storage Terminal -> Crafting page 2/3 (Drying Basin appendices without an output fluid, the FluidButton variant) and page 3/3 (a shaped crafting recipe with empty grid cells, the ItemButton variant) — crashed within a frame of the mouse being parked at 10,10 before the change, and survived it after. ./gradlew build and ./gradlew runGameTestServer passed there.

On this branch I could not get ForgeGradle's MCP setup to run in my environment (extractServer dies with IllegalStateException: ProjectScopeServices has been closed while requesting a toolchain launcher), which is unrelated to this change but blocks the build, so I am relying on CI for the build check here.

No automated test either way: the classes are @OnlyIn(Dist.CLIENT) Button subclasses that need a GuiGraphics, which neither the unit tests nor the game tests can provide.

Other branches

master-1.19-lts has the same unguarded renderTooltip overrides (with the older PoseStack signature), and master-1.21-lts and newer do too, so this presumably wants upmerging forward and possibly one more backport.

@coveralls

coveralls commented Sep 1, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 23.047% (-0.009%) from 23.056% — fix/infobook-empty-recipe-slot-tooltip-crash into master-1.20-lts

Buttons for empty recipe slots never have their element set, and are
never positioned either, so they keep sitting at (0, 0) with a null
element. RecipeAppendix#renderToolTips calls renderTooltip on all
buttons regardless, so as soon as the mouse entered the top-left 16x16
pixels of the screen while a recipe appendix with an empty slot was
shown, ItemButton and FluidButton dereferenced that null element and
crashed the game.

Almost every recipe appendix has empty slots: any crafting recipe that
does not fill the whole 3x3 grid, and any drying basin or squeezer
recipe without a fluid input or output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kzc5LxSaedCXCK4pynhJV3
@rubensworks
rubensworks force-pushed the fix/infobook-empty-recipe-slot-tooltip-crash branch from 4130d09 to 32e3118 Compare September 1, 2026 16:45
@rubensworks
rubensworks changed the base branch from master-1.21-lts to master-1.20-lts September 1, 2026 16:45
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

@rubensworks
rubensworks merged commit 287357f into master-1.20-lts Sep 2, 2026
6 checks passed
@rubensworks
rubensworks deleted the fix/infobook-empty-recipe-slot-tooltip-crash branch September 2, 2026 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants