Skip to content

Fix craftability check in FurnitureWorkbenchScreen to prevent false positives when ingredients overlap #62

@coderabbitai

Description

@coderabbitai

Problem

In FurnitureWorkbenchScreen.canCraft() (lines 218-247), the current ingredient checking logic can falsely report that crafting is possible when it will actually fail server-side. This occurs because the same item stack can satisfy multiple ingredient checks independently, rather than being consumed as ingredients are matched.

Current Behaviour

The method:

  1. Groups ingredients by their holder lists
  2. Checks each ingredient group independently against the full inventory
  3. Allows the same stack to satisfy multiple different ingredient requirements

This means if a recipe needs 2 sticks and 3 planks, but the player only has 3 sticks total, the client may incorrectly enable the craft button because the sticks satisfy both the "2 sticks" requirement and part of the "3 planks" requirement (if planks can match sticks via tag overlap).

Expected Behaviour

The craftability check should simulate server-side consume-on-match behaviour:

  1. Create a mutable snapshot of available item counts (player inventory + networked nearby items)
  2. For each ingredient requirement, attempt to match and consume from the snapshot
  3. If any ingredient cannot be satisfied after accounting for previous consumption, return false
  4. Only return true if all ingredients can be satisfied with the available pool

Suggested Solution

Replace the current aggregation approach with a consumption-based check:

Map<Item, Integer> available = new HashMap<>();
for (int i = 0; i < inv.getContainerSize(); i++) {
    ItemStack stack = inv.getItem(i);
    if (!stack.isEmpty()) available.merge(stack.getItem(), stack.getCount(), Integer::sum);
}
if (this.menu instanceof AbstractWorkbenchContainerMenu workbenchMenu) {
    for (ItemStack stack : workbenchMenu.getNetworkedNearbyItems()) {
        if (!stack.isEmpty()) available.merge(stack.getItem(), stack.getCount(), Integer::sum);
    }
}

for (Ingredient ingredient : reqs.get()) {
    int needed = craftCount;
    while (needed-- > 0) {
        boolean matched = false;
        for (Map.Entry<Item, Integer> e : available.entrySet()) {
            if (e.getValue() > 0 && ingredient.test(e.getKey().getDefaultInstance())) {
                e.setValue(e.getValue() - 1);
                matched = true;
                break;
            }
        }
        if (!matched) return false;
    }
}

Related

Files to Update

  • src/client/java/com/tcm/MineTale/block/workbenches/screen/FurnitureWorkbenchScreen.java
  • Consider applying the same fix to other workbench screens if they share the same pattern

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

Status

Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions