From 5ac2558da441b25c19fb6ecbe1cfe427c44663af Mon Sep 17 00:00:00 2001 From: James William Fletcher <78346668+mrbid@users.noreply.github.com> Date: Wed, 23 Feb 2022 20:48:26 +0000 Subject: [PATCH] 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 --- api.lua | 56 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/api.lua b/api.lua index 8cc5532..64efe0b 100644 --- a/api.lua +++ b/api.lua @@ -43,7 +43,7 @@ minetest.after(0.01, function() end table.sort(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 local def = minetest.registered_items[name] -- Simple drops @@ -133,19 +133,61 @@ minetest.after(0.01, function() 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 _, recipe in ipairs(recipes) do local ingredient_items = {} for _, spec in pairs(recipe.items) do - local matches_spec = ui.canonical_item_spec_matcher(spec) - for _, name in ipairs(ui.items_list) do - if matches_spec(name) then - ingredient_items[name] = true - end + -- Get items that fit into this spec (group or item name) + local specname = ItemStack(spec):get_name() + for item_name, _ in pairs(get_matching_spec_items(specname)) do + ingredient_items[item_name] = true end end 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] = {} end table.insert(ui.crafts_for.usage[name], recipe)