Repository navigation
Fix player-head update placed in the menu instead of the player inventory - #274
Merged
Maxlego08 merged 1 commit intoOct 27, 2026
Merged
Conversation
…ry buttons Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A button with both
player-headandplayer-inventory: trueshows the head without its skin in the player inventory. Once the skin has loaded, the textured head appears in the menu slot with the same number, on top of whatever button is there.Result: a default (Steve) head in hotbar slot 2, and the player's real head in slot 2 of the chest.
Cause
In
InventoryDefault#displayFinalButton, the first render goes throughaddItem(button.isPlayerInventory(), slot, itemStack), which respectsplayer-inventory. The asynchronous skull update, however, always writes to the menu:It also writes from the async thread, and it bypasses the anti-dupe and the inventory listeners, so with
clear-inventory-type: PACKET_EVENTit could not have been routed to the player inventory either.Fix
VInventory#updateItem(inPlayerInventory, slot, itemStack, enableAntiDupe)replaces the item of a button already placed. It keeps the existingItemButtonand its click handlers, applies the anti-dupe, calls the inventory listeners, then sets the item in the player inventory or in the menu. It does nothing if the inventory is closed or the button no longer exists.runAtEntity).InventoryListener#updateItem(defaultfalse) lets a listener handle a late update.PacketEventPlayerInventoryManageruses it inPACKET_EVENTmode: it replaces the pending packet if the post-open flush has not run yet, and otherwise sends the packet instantly, so the real player inventory is never touched.ItemButton#setDisplayItemstores the new item without placing it.Tests
Tested in game on Paper with
clear-inventory: true(DEFAULTmode) and aplayer-head: "%player%"button usingplayer-inventory: true. The textured head now shows in the hotbar slot, nothing appears in the menu slot, the click still works, and the inventory is restored on close.PACKET_EVENTmode was not tested in game.Note
updateItemMetaandhandleUpdatedButton(refresh requirements andupdate: true) also write withgetSpigotInventory().setItem(slot, …), so they probably have the same issue forplayer-inventorybuttons. They are left out of this PR to keep it focused;updateItemcould be reused there.🤖 Generated with Claude Code