Improve group matching for 'copy to craft'

This commit is contained in:
SmallJoker 2023-01-04 11:08:20 +01:00 committed by SmallJoker
parent b590764026
commit bda9f2598f
3 changed files with 68 additions and 51 deletions

40
api.lua
View File

@ -146,46 +146,10 @@ minetest.after(0.01, function()
end end
-- Step 1: group-indexed lookup table for items -- Step 1: group-indexed lookup table for items
local spec_matcher = {} unified_inventory.init_matching_cache()
for _, name in ipairs(ui.items_list) do
-- we only need to care about groups, exact items are handled separately
for group, value in pairs(minetest.registered_items[name].groups) do
if value and value ~= 0 then
if not spec_matcher[group] then
spec_matcher[group] = {}
end
spec_matcher[group][name] = true
end
end
end
-- Step 2: Find all matching items for the given spec (groups) -- Step 2: Find all matching items for the given spec (groups)
local function get_matching_spec_items(specname) local get_matching_spec_items = unified_inventory.get_matching_items
if specname:sub(1,6) ~= "group:" then
return { [specname] = true }
end
local accepted = {}
for i, group in ipairs(specname:sub(7):split(",")) do
if i == 1 then
-- First step: Copy all possible item names in this group
for name, _ in pairs(spec_matcher[group] or {}) do
accepted[name] = true
end
else
-- Perform filtering
if spec_matcher[group] then
for name, _ in pairs(accepted) do
accepted[name] = spec_matcher[group][name]
end
else
-- No matching items
return {}
end
end
end
return accepted
end
for _, recipes in pairs(ui.crafts_for.recipe) do for _, recipes in pairs(ui.crafts_for.recipe) do
-- List of crafts that return this item string (variable "_") -- List of crafts that return this item string (variable "_")

View File

@ -1,4 +1,5 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local ui = unified_inventory
function unified_inventory.extract_groupnames(groupname) function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name() local specname = ItemStack(groupname):get_name()
@ -26,6 +27,7 @@ end
-- It may be a comma-separated list of group names. This is really a -- It may be a comma-separated list of group names. This is really a
-- "group:..." ingredient specification, minus the "group:" prefix. -- "group:..." ingredient specification, minus the "group:" prefix.
-- TODO Replace this with the more efficient spec matcher (below)
local function compute_group_item(group_name_list) local function compute_group_item(group_name_list)
local group_names = group_name_list:split(",") local group_names = group_name_list:split(",")
local candidate_items = {} local candidate_items = {}
@ -84,3 +86,61 @@ function unified_inventory.get_group_item(group_name)
return group_item_cache[group_name] return group_item_cache[group_name]
end end
--[[
This is for filtering known items by groups
e.g. find all items that match "group:flower,yellow" (flower AND yellow groups)
]]
local spec_matcher = {}
function unified_inventory.init_matching_cache()
for _, name in ipairs(ui.items_list) do
-- we only need to care about groups, exact items are handled separately
for group, value in pairs(minetest.registered_items[name].groups) do
if value and value ~= 0 then
if not spec_matcher[group] then
spec_matcher[group] = {}
end
spec_matcher[group][name] = true
end
end
end
end
--[[
Retrieves all matching items
Arguments:
specname (string): Item name or group(s) to filter
Output:
{
matchingitem1 = true,
...
}
]]
function unified_inventory.get_matching_items(specname)
if specname:sub(1,6) ~= "group:" then
return { [specname] = true }
end
local accepted = {}
for i, group in ipairs(specname:sub(7):split(",")) do
if i == 1 then
-- First step: Copy all possible item names in this group
for name, _ in pairs(spec_matcher[group] or {}) do
accepted[name] = true
end
else
-- Perform filtering
if spec_matcher[group] then
for name, _ in pairs(accepted) do
accepted[name] = spec_matcher[group][name]
end
else
-- No matching items
return {}
end
end
end
return accepted
end

View File

@ -126,25 +126,18 @@ Example output:
} }
--]] --]]
function unified_inventory.find_usable_items(inv_items, craft_items) function unified_inventory.find_usable_items(inv_items, craft_items)
local get_group = minetest.get_item_group
local result = {} local result = {}
for craft_item in pairs(craft_items) do for craft_item in pairs(craft_items) do
local group = craft_item:match("^group:(.+)") -- may specify group:type1,type2
local items = unified_inventory.get_matching_items(craft_item)
local found = {} local found = {}
for itemname, _ in pairs(items) do
if group ~= nil then if inv_items[itemname] then
for inv_item in pairs(inv_items) do found[itemname] = true
if get_group(inv_item, group) > 0 then
found[inv_item] = true
end end
end end
else
if inv_items[craft_item] ~= nil then
found[craft_item] = true
end
end
result[craft_item] = found result[craft_item] = found
end end