Skip to content

Hand the bucket empty result to its caller through a ThreadLocal - #513

Open
lewisgibson wants to merge 2 commits into
PaperMC:ver/26.2.xfrom
lewisgibson:bucket-empty-threadlocal
Open

lewisgibson wants to merge 2 commits into
PaperMC:ver/26.2.xfrom
lewisgibson:bucket-empty-threadlocal

Conversation

@lewisgibson

@lewisgibson lewisgibson commented Oct 1, 2026 •

Copy link
Copy Markdown

BucketItem keeps the item that a PlayerBucketEmptyEvent listener left in the hand in a static field, written by emptyContents and read and cleared by getEmptySuccessItem a few calls later. With regions ticking in parallel, two players emptying buckets at the same time can overwrite each other's field, so one of them gets the other's item, or the default bucket, back in their hand.

This makes the hand-off a ThreadLocal, since both calls always run on the same region thread. The change is folded into 0001-Region-Threading-Base.patch.

Tested on ver/26.2.x with a small test plugin and two players 3000 blocks apart, so in different regions. The plugin's PlayerBucketEmptyEvent listener gives BotA a diamond and BotB an emerald as the result item, and a GenericGameEvent listener holds both region threads after emptyContents has stored its value and before getEmptySuccessItem reads it, so the overlap is certain rather than a matter of timing. Unpatched, BotB ended up with a plain bucket; with this change BotA has the diamond and BotB has the emerald.

This was done with AI (Claude Opus 5.5 and GPT Astra, high effort). I've reviewed it and tested it myself.

BucketItem handed the PlayerBucketEmptyEvent result to getEmptySuccessItem through a static field shared by every region. See the patch for details.
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.

1 participant