Skip to content

feat(invcleaner): keep the fullest block stack in the block slot#8450

Open
m1trenv0 wants to merge 3 commits into
CCBlueX:nextgenfrom
m1trenv0:feat/invcleaner-most-blocks
Open

feat(invcleaner): keep the fullest block stack in the block slot#8450
m1trenv0 wants to merge 3 commits into
CCBlueX:nextgenfrom
m1trenv0:feat/invcleaner-most-blocks

Conversation

@m1trenv0

@m1trenv0 m1trenv0 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

What

Makes InventoryCleaner keep the fullest block stack in the block slot, instead of a near-empty one.

Problem

BlockItemFacet used ModuleScaffold.BLOCK_COMPARATOR_FOR_INVENTORY, which prefers the smaller stack (PreferStackSize.PREFER_FEWER). So the cleaner could leave a nearly empty stack in the block slot while a full stack sat elsewhere in the inventory, and the choice between similar stacks felt random.

How

BlockItemFacet now has its own comparator chain:

  • Block quality first (favourable / solid / full-cube / walkable / hardness) — unchanged, so a worse block never wins just by count.
  • Among equally good blocks, prefer the one with more items.
  • A small hysteresis: counts within 1 of each other are treated as equal and the tie is broken by hotbar preference — so the cleaner does not keep swapping between, say, a 63 and a 64 stack, but a clearly larger inventory stack will still replace a nearly empty one in hand.

Scaffold's own comparators are left untouched.

🤖 Generated with Claude Code

InventoryCleaner used the scaffold inventory comparator for blocks, which
prefers the SMALLER stack (PreferStackSize.PREFER_FEWER). As a result the
block slot would end up holding a near-empty stack while a full stack sat in
the inventory.

Give BlockItemFacet its own comparator that, among equally good blocks, keeps
the stack with MORE blocks. A small hysteresis (counts within 1 are treated as
equal, tie broken by hotbar preference) prevents pointless swaps between two
near-equal stacks (e.g. 63 vs 64), while a clearly larger inventory stack will
still replace a nearly empty one in hand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@1zun4 1zun4 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code seems alright so far and makes sense, however, have you actually tested it in action?

Comment on lines +35 to +50
/**
* Stack counts within this many blocks of each other are treated as equal, so the cleaner
* does not keep swapping between two near-equal stacks (e.g. 63 vs 64). The tie is then
* broken by [PREFER_ITEMS_IN_HOTBAR], i.e. the stack already in the hotbar is kept.
*/
private const val COUNT_HYSTERESIS = 1

/**
* Prefers the block with MORE items, but only when the difference is meaningful (greater than
* [COUNT_HYSTERESIS]). This keeps the fullest stack in the block slot while avoiding pointless
* swaps over a one-block difference.
*/
private val PREFER_MORE_BLOCKS_FUZZY: Comparator<ItemStack> = Comparator { a, b ->
val diff = a.count - b.count
if (diff in -COUNT_HYSTERESIS..COUNT_HYSTERESIS) 0 else diff
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does not belong into BlockItemFacet. Should go into a new file, the way "PreferFullCubeBlocks" etc do it.

m1trenv0 and others added 2 commits June 8, 2026 17:35
…temFacet

Addresses review feedback: the count comparator does not belong inside BlockItemFacet. Extracted
it to ItemStackComparators.kt as a reusable PreferMoreBlocksFuzzy(hysteresis) class, alongside
PreferFullCubeBlocks and the other block comparators. BlockItemFacet now just references it; the
comparator chain and behaviour are unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
…ss stacks win

A glass stack with 2x the count was ignored in favour of a tiny stack of a 'nicer' block (esp.
stained glass), even though the glass was in neither the disallowed nor unfavorable list. Cause:
the comparator put all soft quality preferences (solid/redstone-conductor, walkable, hardness)
before count, so glass (not a redstone conductor) always lost to a full opaque block regardless
of stack size. Reordered: usability gates first (favourable + full-cube), then count, then the
soft quality tiebreakers. Among usable full-cube blocks the fullest stack now wins.

Co-Authored-By: Claude <noreply@anthropic.com>
@m1trenv0

m1trenv0 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

The code seems alright so far and makes sense, however, have you actually tested it in action?

yes, it works, tested with own compiled build

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.

2 participants