Speed up group filtering code

This improves the startup time dramatically by lowering the algorithm complexity.
Mainly noticeable with large inventory sizes.

Written by Test_User, post-edited by SmallJoker
This commit is contained in:
James William Fletcher 2022-02-23 20:48:26 +00:00 committed by SmallJoker
parent 25c40fea6c
commit 5ac2558da4

56
api.lua

@ -43,7 +43,7 @@ minetest.after(0.01, function()
end end
table.sort(ui.items_list) table.sort(ui.items_list)
ui.items_list_size = #ui.items_list ui.items_list_size = #ui.items_list
print("Unified Inventory. inventory size: "..ui.items_list_size) print("Unified Inventory. Inventory size: "..ui.items_list_size)
for _, name in ipairs(ui.items_list) do for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name] local def = minetest.registered_items[name]
-- Simple drops -- Simple drops
@ -133,19 +133,61 @@ minetest.after(0.01, function()
end end
end end
end end
-- Step 1: group-indexed lookup table for items
local spec_matcher = {}
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)
local function get_matching_spec_items(specname)
if specname:sub(1,6) ~= "group:" then
return { specname }
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
for _, recipe in ipairs(recipes) do for _, recipe in ipairs(recipes) do
local ingredient_items = {} local ingredient_items = {}
for _, spec in pairs(recipe.items) do for _, spec in pairs(recipe.items) do
local matches_spec = ui.canonical_item_spec_matcher(spec) -- Get items that fit into this spec (group or item name)
for _, name in ipairs(ui.items_list) do local specname = ItemStack(spec):get_name()
if matches_spec(name) then for item_name, _ in pairs(get_matching_spec_items(specname)) do
ingredient_items[name] = true ingredient_items[item_name] = true
end
end end
end end
for name, _ in pairs(ingredient_items) do for name, _ in pairs(ingredient_items) do
if ui.crafts_for.usage[name] == nil then if not ui.crafts_for.usage[name] then
ui.crafts_for.usage[name] = {} ui.crafts_for.usage[name] = {}
end end
table.insert(ui.crafts_for.usage[name], recipe) table.insert(ui.crafts_for.usage[name], recipe)