From 1577af738fe2f57df2194ea76ecfa515a4a3e714 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Wed, 13 Mar 2024 17:31:38 +0100 Subject: [PATCH] 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 --- autocrafter.lua | 65 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/autocrafter.lua b/autocrafter.lua index bd9a669..014c4a5 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -4,6 +4,7 @@ local S = minetest.get_translator("pipeworks") local autocrafterCache = {} local craft_time = 1 +local next = next local function count_index(invlist) local index = {} @@ -48,7 +49,9 @@ local function get_matching_craft(output_name, example_recipe) elseif recipe_item_name:sub(1, 6) == "group:" then group = recipe_item_name:sub(7) 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 break end @@ -89,22 +92,27 @@ local function get_craft(pos, inventory, hash) return craft end --- From a consumption table with groups and an inventory index, build --- a consumption table without groups +-- From a consumption table with groups and an inventory index, +-- build a consumption table without groups local function calculate_consumption(inv_index, consumption_with_groups) inv_index = table.copy(inv_index) consumption_with_groups = table.copy(consumption_with_groups) + -- table of items to actually consume local consumption = {} - local groups = {} + -- table of ingredients defined as one or more groups each + local grouped_ingredients = {} -- First consume all non-group requirements - -- This is done to avoid consuming a non-group item which is also - -- in a group + -- This is done to avoid consuming a non-group item which + -- is also in a group for key, count in pairs(consumption_with_groups) do 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 + -- 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 return nil end @@ -118,28 +126,45 @@ local function calculate_consumption(inv_index, consumption_with_groups) 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 - local take - if #groups > 0 then + if next(grouped_ingredients) ~= nil then + local take for itemname, count in pairs(inv_index) do if count > 0 then - local def = minetest.registered_items[itemname] - local item_groups = def and def.groups or {} - for i = 1, #groups do - local group = groups[i] - local groupname = "group:" .. group - if item_groups[group] and item_groups[group] >= 1 - and consumption_with_groups[groupname] > 0 + -- groupname is the string as defined by recipe. + -- e.g. group:dye,color_blue + -- groups holds the group names split into a list + -- ready to be passed to core.get_item_group() + for groupname, groups in pairs(grouped_ingredients) do + if consumption_with_groups[groupname] > 0 + and ingredient_groups_match_item(groups, itemname) 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] - take + consumption_with_groups[groupname] - take assert(consumption_with_groups[groupname] >= 0) 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) end end