Count multi-block placements (beds, doors) once, not twice (#86)#265
Merged
Conversation
BlockMultiPlaceEvent extends BlockPlaceEvent and does not declare its own HandlerList, so a single multi-place dispatch is delivered to BOTH onBlock(BlockPlaceEvent) and onBlock(BlockMultiPlaceEvent) — each calling process(block, true). A bed (or door, double-tall plant) was therefore counted twice on placement, while breaking it fired a single BlockBreakEvent and decremented once, permanently leaking +1 per place/break cycle until the island hit a phantom limit. Skip BlockMultiPlaceEvent instances in the BlockPlaceEvent handler and let the dedicated handler count them once — the same subtype-guard pattern onBlock(BlockFormEvent) already uses for its subclasses. Tests dispatch through the real plugin manager (so the double delivery actually occurs) and assert a bed counts once and returns to zero after a break. Co-Authored-By: Claude Opus 4.8 (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.



Fixes #86.
The bug
A bed counts as 2 on placement and leaks +1 on every place/break cycle, eventually blocking placement against a phantom limit. Reported by @Espantonius as still reproducing: "If you add a bed it counts as 2 but if you delete it, it only counts as 1."
Root cause
BlockMultiPlaceEvent extends BlockPlaceEventand does not declare its ownHandlerList(verified in the Paper 1.21.11 API source). Bukkit dispatches it onBlockPlaceEvent's shared handler list, and the per-handlerisAssignableFromguard passes for both registered handlers — so a single bed placement is delivered to bothonBlock(BlockPlaceEvent)andonBlock(BlockMultiPlaceEvent), each callingprocess(block, true). That double-counts the placement, while breaking the bed fires a singleBlockBreakEventand decrements once → a permanent +1 leak.This affects any multi-block placement that fires
BlockMultiPlaceEvent: beds, doors, double-tall plants, etc.Fix
Skip
BlockMultiPlaceEventinstances in theBlockPlaceEventhandler and let the dedicatedonBlock(BlockMultiPlaceEvent)count them once — the same subtype guardonBlock(BlockFormEvent)already uses forEntityBlockFormEvent/BlockSpreadEvent.Tests
Two new tests dispatch through the real plugin manager (a direct handler call would hide the double delivery):
testBedPlacedViaMultiPlaceCountsOnce— a bed counts once (was 2 before the fix)testBedPlaceThenBreakLeavesZero— place + break returns to 0 (was 1 before the fix)Both fail red on the current code and pass with the fix. Full suite: 235 tests, 0 failures.
🤖 Generated with Claude Code