Autocrafter multi group ingredient (#115)

* check for non-zero group value

in theory groups can have negative values too.

* fix #114 multi group recipe items

Fix the bug that prevented crafting with recipes
that had ingredients that need to match multiple
groups.

* comments and whitespace changes

* fix faulty empty table check
This commit is contained in:
Luke aka SwissalpS 2024-03-13 17:31:38 +01:00 committed by GitHub
parent 8828183bef
commit 1577af738f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,6 +4,7 @@ local S = minetest.get_translator("pipeworks")
local autocrafterCache = {} local autocrafterCache = {}
local craft_time = 1 local craft_time = 1
local next = next
local function count_index(invlist) local function count_index(invlist)
local index = {} local index = {}
@ -48,7 +49,9 @@ local function get_matching_craft(output_name, example_recipe)
elseif recipe_item_name:sub(1, 6) == "group:" then elseif recipe_item_name:sub(1, 6) == "group:" then
group = recipe_item_name:sub(7) group = recipe_item_name:sub(7)
for example_item_name, _ in pairs(index_example) do for example_item_name, _ in pairs(index_example) do
if minetest.get_item_group(example_item_name, group) > 0 then if minetest.get_item_group(
example_item_name, group) ~= 0
then
score = score + 1 score = score + 1
break break
end end
@ -89,22 +92,27 @@ local function get_craft(pos, inventory, hash)
return craft return craft
end end
-- From a consumption table with groups and an inventory index, build -- From a consumption table with groups and an inventory index,
-- a consumption table without groups -- build a consumption table without groups
local function calculate_consumption(inv_index, consumption_with_groups) local function calculate_consumption(inv_index, consumption_with_groups)
inv_index = table.copy(inv_index) inv_index = table.copy(inv_index)
consumption_with_groups = table.copy(consumption_with_groups) consumption_with_groups = table.copy(consumption_with_groups)
-- table of items to actually consume
local consumption = {} local consumption = {}
local groups = {} -- table of ingredients defined as one or more groups each
local grouped_ingredients = {}
-- First consume all non-group requirements -- First consume all non-group requirements
-- This is done to avoid consuming a non-group item which is also -- This is done to avoid consuming a non-group item which
-- in a group -- is also in a group
for key, count in pairs(consumption_with_groups) do for key, count in pairs(consumption_with_groups) do
if key:sub(1, 6) == "group:" then if key:sub(1, 6) == "group:" then
groups[#groups + 1] = key:sub(7, #key) -- build table with group recipe items while looping
grouped_ingredients[key] = key:sub(7):split(',')
else else
-- if the item to consume doesn't exist in inventory
-- or not enough of them, abort crafting
if not inv_index[key] or inv_index[key] < count then if not inv_index[key] or inv_index[key] < count then
return nil return nil
end end
@ -118,20 +126,36 @@ local function calculate_consumption(inv_index, consumption_with_groups)
end end
end end
-- helper function to resolve matching ingredients with multiple group
-- requirements
local function ingredient_groups_match_item(ingredient_groups, name)
local found = 0
local count_ingredient_groups = #ingredient_groups
for i = 1, count_ingredient_groups do
if minetest.get_item_group(name,
ingredient_groups[i]) ~= 0
then
found = found + 1
end
end
return found == count_ingredient_groups
end
-- Next, resolve groups using the remaining items in the inventory -- Next, resolve groups using the remaining items in the inventory
if next(grouped_ingredients) ~= nil then
local take local take
if #groups > 0 then
for itemname, count in pairs(inv_index) do for itemname, count in pairs(inv_index) do
if count > 0 then if count > 0 then
local def = minetest.registered_items[itemname] -- groupname is the string as defined by recipe.
local item_groups = def and def.groups or {} -- e.g. group:dye,color_blue
for i = 1, #groups do -- groups holds the group names split into a list
local group = groups[i] -- ready to be passed to core.get_item_group()
local groupname = "group:" .. group for groupname, groups in pairs(grouped_ingredients) do
if item_groups[group] and item_groups[group] >= 1 if consumption_with_groups[groupname] > 0
and consumption_with_groups[groupname] > 0 and ingredient_groups_match_item(groups, itemname)
then then
take = math.min(count, consumption_with_groups[groupname]) take = math.min(count,
consumption_with_groups[groupname])
consumption_with_groups[groupname] = consumption_with_groups[groupname] =
consumption_with_groups[groupname] - take consumption_with_groups[groupname] - take
@ -139,7 +163,8 @@ local function calculate_consumption(inv_index, consumption_with_groups)
consumption[itemname] = consumption[itemname] =
(consumption[itemname] or 0) + take (consumption[itemname] or 0) + take
inv_index[itemname] = inv_index[itemname] - take inv_index[itemname] =
inv_index[itemname] - take
assert(inv_index[itemname] >= 0) assert(inv_index[itemname] >= 0)
end end
end end