diff --git a/match_craft.lua b/match_craft.lua index 2d43934..07e2a72 100644 --- a/match_craft.lua +++ b/match_craft.lua @@ -317,6 +317,8 @@ can be one of the source lists. If destination list position is already occupied with some other item then function tries to move it to the source lists if possible. +Warning!!! Moving oversized stacks is undefined and can lead to item loss! + Arguments: inv: minetest inventory reference src_lists: names of source lists @@ -328,44 +330,48 @@ function unified_inventory.move_match(inv, src_lists, dst_list, match_table, amo local moved_positions = {} for item, pos_set in pairs(match_table) do - local stack_max = ItemStack(item):get_stack_max() + local needed = {} + local remained = {} + + local stack = ItemStack(item) + local stack_max = stack:get_stack_max() local bounded_amount = math.min(stack_max, amount) - local pos_count = 0; - for _ in pairs(pos_set) do - pos_count = pos_count + 1 - end - - local total = ItemStack{ - name = item, - count = bounded_amount * pos_count - } - - local removed = unified_inventory.remove_item(inv, src_lists, total) - local current = ItemStack(removed) - current:set_count(bounded_amount) + -- Pass 1: Remove stacks needed for craft + stack:set_count(bounded_amount) for pos in pairs(pos_set) do + needed[pos] = unified_inventory.remove_item(inv, src_lists, stack) + end + + -- Pass 2: Remove remainder to free up positions + stack:set_count(stack_max) + + for pos in pairs(pos_set) do + remained[pos] = unified_inventory.remove_item(inv, src_lists, stack) + end + + -- Pass 3: Move only needed stacks + for pos, current in pairs(needed) do local occupied = inv:get_stack(dst_list, pos) inv:set_stack(dst_list, pos, current) - repeat - if not occupied:is_empty() then - local leftover = unified_inventory.add_item(inv, src_lists, occupied) + if not occupied:is_empty() then + local leftover = unified_inventory.add_item(inv, src_lists, occupied) - if not leftover:is_empty() then - inv:set_stack(dst_list, pos, leftover) - break - end + if not leftover:is_empty() then + inv:set_stack(dst_list, pos, leftover) + unified_inventory.add_item(inv, src_lists, current) end - - removed:take_item(bounded_amount) - until true + end moved_positions[pos] = true end - unified_inventory.add_item(inv, src_lists, removed) + -- Pass 4: Re-add remainder stacks + for _, current in pairs(remained) do + unified_inventory.add_item(inv, src_lists, current) + end end unified_inventory.swap_items(inv, dst_list, src_lists, moved_positions)