Skip to content

Conversation

@HaHaWTH
Copy link
Contributor

@HaHaWTH HaHaWTH commented Jan 10, 2026

This PR fixes #13536, cancelled rooted dirt drops being duped

Analysis

protected static final Map<Block, Pair<Predicate<UseOnContext>, Consumer<UseOnContext>>> TILLABLES = Maps.newHashMap(
        ImmutableMap.of(
            Blocks.GRASS_BLOCK,
            Pair.of(HoeItem::onlyIfAirAbove, changeIntoState(Blocks.FARMLAND.defaultBlockState())),
            Blocks.DIRT_PATH,
            Pair.of(HoeItem::onlyIfAirAbove, changeIntoState(Blocks.FARMLAND.defaultBlockState())),
            Blocks.DIRT,
            Pair.of(HoeItem::onlyIfAirAbove, changeIntoState(Blocks.FARMLAND.defaultBlockState())),
            Blocks.COARSE_DIRT,
            Pair.of(HoeItem::onlyIfAirAbove, changeIntoState(Blocks.DIRT.defaultBlockState())),
            Blocks.ROOTED_DIRT,
            Pair.of(useOnContext -> true, changeIntoStateAndDropItem(Blocks.DIRT.defaultBlockState(), Items.HANGING_ROOTS))
        )
    );

The rooted dirt item drop logic is being processed in HoeItem#useOn, the drop capturing isn't enabled in this path, causing hanging roots to still be dropped even BlockPlaceEvent is cancelled.
This bug has existed since 1.19, after Mojang added the rooted dirt.

@HaHaWTH HaHaWTH requested a review from a team as a code owner January 10, 2026 10:33
@github-project-automation github-project-automation bot moved this to Awaiting review in Paper PR Queue Jan 10, 2026
@Astralchroma
Copy link
Contributor

Paper devs gotta merge this quick before my Server's Rooted Dirt economy experiences hyperinflation!!1! Simply the best currency imaginable.

I know this will immediately get hidden as being spam or off-topic or whatever but I thought it was a funny joke.

Copy link
Member

@electronicboy electronicboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really falls into my qualms about how this logic works in general, it feels messy but it also smells like that is just how this stuff has to work for now

+ }
+ }
+ // Paper start - Fix cancelled rooted dirt drops being duped
+ List<ItemEntity> capturedDrops = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused on the path here.
Why double the variable when the serverLevel.captureDrops exists?

Are we trying to handle the case where this field is non null? In that case, we'd have to store current state and restore later, which we are not doing. If we aren't (which I don't think we need to? captureDrops is for the mineBlock bit, that shouldn't trigger useOn), we don't need such added changes that check for possibly null lists (e.g. if (capturedDrops != null) { below too)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion, I was engaging in a bit of defensive programming there with the extra checks, but I see now it wasn't necessary given the context.

@github-project-automation github-project-automation bot moved this from Awaiting review to Changes required in Paper PR Queue Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Changes required

Development

Successfully merging this pull request may close these issues.

Infinite Hanging Roots Duplication via Hoe Right-Click on Rooted Dirt + BlockPlaceEvent Cancellation

4 participants