Fixes #1532. Also fixes the Sable side of Creators-of-Create/Create#10255. - #1537
Open
aihaoDIYlove wants to merge 3 commits into
Open
Fixes #1532. Also fixes the Sable side of Creators-of-Create/Create#10255.#1537aihaoDIYlove wants to merge 3 commits into
aihaoDIYlove wants to merge 3 commits into
Conversation
Mass invalidation (MassTracker.isInvalid) can only trigger while the plot contains air and zero-mass blocks - any block with mass would keep the tracker valid. destroyBlock(pos, true) therefore only ever dropped weightless decorations, which the disassembly sweep has already moved back to the world: a clean item duplication. Storage blocks with empty collision shapes are the worst case - a shelf or rack holding a loaded shulker box duplicates the box together with all of its contents on every disassembly, even though the shulker itself has mass and never triggers the invalidation. Pass dropItems=false at the invalidation call sites and remove blocks by detaching their block entity and replacing them with the fluid's legacy state: this also suppresses the destroy level event and neighbor updates - nothing needs to react to a wholesale plot deletion, and updates could pop foreign blocks living in adjacent plot grid cells - and prevents container onRemove hooks from spilling contents. The heat-split path keeps dropping, as no sweep races it there.
…level moveBlocks snapshots the source BE and relies on Clearable.tryClear to empty it before the source is destroyed. Block entities that do not implement Clearable keep their contents on the source position, and the unconditional onRemove(...) hook then drops a duplicate of everything the destination copy already received via the NBT snapshot (on disassembly the duplicate is voided inside the dying sub-level instead). Detach the source block entity - the same escape hatch as #sable:silent_assembly_removal, applied automatically. Every vanilla item-holding BE implements Clearable via Container, so this only affects modded blocks.
testMasslessInvalidationDoesNotDrop: assemble a stone block with a zero-mass wall torch on each side, remove the stone so the mass tracker invalidates through the real block-change path, and assert that no torch items drop anywhere in the level when the plot is demolished. The drops land at the plot's position in the level, far away from the test structure, and only torches this test placed count as evidence - the shared plot grid can pop foreign decorations from neighbouring grid content during assembly. Fails on main with four torch items, passes with the previous commits. Non-clearable block entities cannot be covered with vanilla blocks (all of them implement Clearable via Container). bin/ is the default output directory of the VS Code Java language server and Eclipse, mirroring the existing out/ ignore for IntelliJ.
aihaoDIYlove
force-pushed
the
fix/zero-mass-item-duplication
branch
from
September 5, 2026 01:32
d5b5839 to
f1c0189
Compare
aihaoDIYlove
marked this pull request as ready for review
September 5, 2026 05:26
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 #1532. Also fixes the Sable side of Creators-of-Create/Create#10255.
Bug 1:
destroyAllBlocksdrops items when a plot is invalidatedMassTracker.isInvalid()can only trigger once no mass-bearing blocks remain in the plot — any remaining mass-bearing block would keep the tracker valid.ServerLevelPlot.destroyAllBlocks()therefore only ever destroys air/weightless decorations withdestroyBlock(pos, true), while those blocks have already been restored, or are in the process of being restored, by the disassembly sweep. This results in item duplication during disassembly, independent of sweep direction.Storage blocks with empty collision shapes are the worst case — a shelf or rack holding a loaded shulker box can duplicate the box together with all of its contents on every cycle, even though the shulker itself has mass and never triggers the invalidation.
Fix (bc89822)
destroyAllBlocks(boolean dropItems): the invalidation call sites passfalseand remove blocks by detaching their block entity and replacing them with the fluid's legacy state. This also suppresses the destroy-level event and prevents containeronRemovehooks from spilling contents. The heat-split path keeps dropping, as no sweep races it there.Bug 2: non-clearable block entities drop their contents when moved
moveBlockssnapshots the source BE and relies onClearable.tryClearto empty it before the source is destroyed. BEs that do not implementClearablekeep their contents on the source position, and the unconditionalonRemove(...)hook can then drop contents that the destination copy already received via the NBT snapshot (on disassembly the duplicate is voided inside the dying sub-level instead).This was reported independently in Creators-of-Create/Create#10255 (item drain, mechanical arm) — and the existing
#sable:silent_assembly_removaltag exists precisely because of this behavior.Fix (6ef4a6d)
Non-clearable BEs are detached before the source destruction — the same escape hatch as the silent removal tag, applied automatically. Every vanilla item-holding BE implements
ClearableviaContainer, so this only affects modded blocks, and fixes them all at the engine level instead of requiring per-mod tags.Testing
testMasslessInvalidationDoesNotDrop(f1c0189): assemble a stone block with zero-mass wall torches, invalidate the tracker through the real block-change path, and assert that nothing drops near the plot when it is demolished. Fails onmain(torch drops), passes with this PR.Note: vanilla has no non-Clearable item-holding BE, so Bug 2 has no automated coverage here; happy to add a gametest-only test block if preferred.