1
0
mirror of https://github.com/mt-mods/pipeworks.git synced 2025-05-19 09:20:41 +02:00

Add support for recipes with groups to autocrafter

This commit is contained in:
rubenwardy 2019-09-16 17:09:33 +01:00
parent cec6049dd1
commit 60673db480

@ -6,6 +6,7 @@ local craft_time = 1
local function count_index(invlist) local function count_index(invlist)
local index = {} local index = {}
for _, stack in pairs(invlist) do for _, stack in pairs(invlist) do
stack = ItemStack(stack)
if not stack:is_empty() then if not stack:is_empty() then
local stack_name = stack:get_name() local stack_name = stack:get_name()
index[stack_name] = (index[stack_name] or 0) + stack:get_count() index[stack_name] = (index[stack_name] or 0) + stack:get_count()
@ -25,26 +26,102 @@ local function get_craft(pos, inventory, hash)
local hash = hash or minetest.hash_node_position(pos) local hash = hash or minetest.hash_node_position(pos)
local craft = autocrafterCache[hash] local craft = autocrafterCache[hash]
if not craft then if not craft then
local recipe = inventory:get_list("recipe") local example_recipe = inventory:get_list("recipe")
local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe}) local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = example_recipe})
local recipe = example_recipe
if output and not output.item:is_empty() then
recipe = minetest.get_craft_recipe(output.item:get_name()).items or example_recipe
end
craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input} craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
autocrafterCache[hash] = craft autocrafterCache[hash] = craft
end end
return craft return craft
end end
-- 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)
local consumption = {}
local groups = {}
-- First consume all non-group requirements
-- 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)
else
if not inv_index[key] or inv_index[key] < count then
return nil
end
consumption[key] = (consumption[key] or 0) + count
consumption_with_groups[key] = consumption_with_groups[key] - count
assert(consumption_with_groups[key] == 0)
consumption_with_groups[key] = nil
inv_index[key] = inv_index[key] - count
assert(inv_index[key] >= 0)
end
end
-- Next, resolve groups using the remaining items in the inventory
if #groups > 0 then
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] >= 1 and consumption_with_groups[groupname] > 0 then
local take = math.min(count, consumption_with_groups[groupname])
consumption_with_groups[groupname] = consumption_with_groups[groupname] - take
assert(consumption_with_groups[groupname] >= 0)
consumption[itemname] = (consumption[itemname] or 0) + take
inv_index[itemname] = inv_index[itemname] - take
assert(inv_index[itemname] >= 0)
end
end
end
end
end
-- Finally, check everything has been consumed
for key, count in pairs(consumption_with_groups) do
if count > 0 then
return nil
end
end
return consumption
end
local function autocraft(inventory, craft) local function autocraft(inventory, craft)
if not craft then return false end if not craft then
return false
end
local output_item = craft.output.item local output_item = craft.output.item
-- check if we have enough room in dst -- check if we have enough room in dst
if not inventory:room_for_item("dst", output_item) then return false end if not inventory:room_for_item("dst", output_item) then
local consumption = craft.consumption return false
end
-- get required items and index inventory
local inv_index = count_index(inventory:get_list("src")) local inv_index = count_index(inventory:get_list("src"))
local consumption = calculate_consumption(inv_index, craft.consumption)
if not consumption then
return false
end
-- check if we have enough material available -- check if we have enough material available
for itemname, number in pairs(consumption) do for itemname, number in pairs(consumption) do
if (not inv_index[itemname]) or inv_index[itemname] < number then return false end if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
end end
-- consume material -- consume material
for itemname, number in pairs(consumption) do for itemname, number in pairs(consumption) do
for _ = 1, number do -- We have to do that since remove_item does not work if count > stack_max for _ = 1, number do -- We have to do that since remove_item does not work if count > stack_max