Greatly speed-up mod loading (thanks @pauloue)

This commit is contained in:
Jean-Patrick Guerrero 2020-07-07 17:17:33 +02:00
parent 0b7bfca0ec
commit e941443a59
2 changed files with 176 additions and 226 deletions

395
init.lua

@ -11,10 +11,8 @@ local toolrepair
local progressive_mode = core.settings:get_bool "craftguide_progressive_mode" local progressive_mode = core.settings:get_bool "craftguide_progressive_mode"
local sfinv_only = core.settings:get_bool "craftguide_sfinv_only" and rawget(_G, "sfinv") local sfinv_only = core.settings:get_bool "craftguide_sfinv_only" and rawget(_G, "sfinv")
local autocache = core.settings:get_bool "craftguide_autocache"
local http = core.request_http_api() local http = core.request_http_api()
local storage = core.get_mod_storage()
local singleplayer = core.is_singleplayer() local singleplayer = core.is_singleplayer()
local reg_items = core.registered_items local reg_items = core.registered_items
@ -349,7 +347,7 @@ function craftguide.register_craft_type(name, def)
end end
function craftguide.register_craft(def) function craftguide.register_craft(def)
local width, c = 0, 0 local width = 0
if true_str(def.url) then if true_str(def.url) then
if not http then if not http then
@ -417,8 +415,7 @@ function craftguide.register_craft(def)
end end
for symbol in gmatch(concat(def.grid), ".") do for symbol in gmatch(concat(def.grid), ".") do
c = c + 1 insert(def.items, def.key[symbol])
def.items[c] = def.key[symbol]
end end
else else
local items, len = def.items, #def.items local items, len = def.items, #def.items
@ -440,17 +437,16 @@ function craftguide.register_craft(def)
end end
for name in gmatch(concat(items, ","), "[%s%w_:]+") do for name in gmatch(concat(items, ","), "[%s%w_:]+") do
c = c + 1 insert(def.items, match(name, "%S+"))
def.items[c] = match(name, "%S+")
end end
end end
local output = match(def.output, "%S+") local item = match(def.output, "%S+")
recipes_cache[output] = recipes_cache[output] or {} recipes_cache[item] = recipes_cache[item] or {}
def.custom = true def.custom = true
def.width = width def.width = width
insert(recipes_cache[output], def) insert(recipes_cache[item], def)
end end
local recipe_filters = {} local recipe_filters = {}
@ -521,35 +517,8 @@ local function item_has_groups(item_groups, groups)
end end
local function extract_groups(str) local function extract_groups(str)
return split(sub(str, 7), ",") if sub(str, 1, 6) == "group:" then
end return split(sub(str, 7), ",")
local function item_in_recipe(item, recipe)
local clean_item = reg_aliases[item] or item
for _, recipe_item in pairs(recipe.items) do
local clean_recipe_item = reg_aliases[recipe_item] or recipe_item
if clean_recipe_item == clean_item then
return true
end
end
end
local function groups_item_in_recipe(item, recipe)
local def = reg_items[item]
if not def then return end
local item_groups = def.groups
for _, recipe_item in pairs(recipe.items) do
if is_group(recipe_item) then
local groups = extract_groups(recipe_item)
if item_has_groups(item_groups, groups) then
local usage = copy(recipe)
table_replace(usage.items, recipe_item, item)
return usage
end
end
end end
end end
@ -581,36 +550,6 @@ local function get_filtered_items(player, data)
return items return items
end end
local function get_usages(item)
local usages, c = {}, 0
for _, recipes in pairs(recipes_cache) do
for i = 1, #recipes do
local recipe = recipes[i]
if item_in_recipe(item, recipe) then
c = c + 1
usages[c] = recipe
else
recipe = groups_item_in_recipe(item, recipe)
if recipe then
c = c + 1
usages[c] = recipe
end
end
end
end
if fuel_cache[item] then
usages[#usages + 1] = {
type = "fuel",
items = {item},
replacements = fuel_cache.replacements[item],
}
end
return usages
end
local function get_burntime(item) local function get_burntime(item)
return get_craft_result{method = "fuel", items = {item}}.time return get_craft_result{method = "fuel", items = {item}}.time
end end
@ -622,18 +561,155 @@ local function cache_fuel(item)
end end
end end
local function cache_usages(item) local function show_item(def)
local usages = get_usages(item) return not (def.groups.not_in_craft_guide == 1 or
if #usages > 0 then def.groups.not_in_creative_inventory == 1) and
usages_cache[item] = table_merge(usages, usages_cache[item] or {}) def.description and def.description ~= ""
end
local function get_usages(recipe)
local added = {}
for _, item in pairs(recipe.items) do
if not added[item] then
local groups = extract_groups(item)
if groups then
for name, def in pairs(reg_items) do
if not added[name] and show_item(def) and
item_has_groups(def.groups, groups) then
local usage = copy(recipe)
table_replace(usage.items, item, name)
usages_cache[name] = usages_cache[name] or {}
insert(usages_cache[name], usage)
added[name] = true
end
end
elseif show_item(reg_items[item]) then
usages_cache[item] = usages_cache[item] or {}
insert(usages_cache[item], recipe)
end
added[item] = true
end
end end
end end
local function cache_recipes(output) local function cache_usages(item)
local recipes = get_all_recipes(output) or {} local recipes = recipes_cache[item] or {}
if #recipes > 0 then
recipes_cache[output] = recipes for i = 1, #recipes do
get_usages(recipes[i])
end end
if fuel_cache[item] then
local fuel = {
type = "fuel",
items = {item},
replacements = fuel_cache.replacements[item],
}
usages_cache[item] = table_merge(usages_cache[item] or {}, {fuel})
end
end
local function drop_table(name, drop)
-- Code borrowed and modified from unified_inventory
-- https://github.com/minetest-mods/unified_inventory/blob/master/api.lua
local drop_sure, drop_maybe = {}, {}
local drop_items = drop.items or {}
local max_items_left = drop.max_items
local max_start = true
for i = 1, #drop_items do
if max_items_left and max_items_left <= 0 then break end
local di = drop_items[i]
for j = 1, #di.items do
local dstack = ItemStack(di.items[j])
local dname = dstack:get_name()
if not dstack:is_empty() and dname ~= name then
local dcount = dstack:get_count()
if #di.items == 1 and max_start and
(not di.rarity or di.rarity <= 1) then
if not drop_sure[dname] then
drop_sure[dname] = {}
end
drop_sure[dname] = {
output = (drop_sure[dname].output or 0) + dcount,
tools = di.tools,
}
if max_items_left then
max_items_left = max_items_left - 1
if max_items_left <= 0 then break end
end
else
if max_items_left then
max_start = false
end
if not drop_maybe[dname] then
drop_maybe[dname] = {}
end
drop_maybe[dname] = {
output = (drop_maybe[dname].output or 0) + dcount,
rarity = di.rarity,
tools = di.tools,
}
end
end
end
end
for item, data in pairs(drop_sure) do
craftguide.register_craft{
type = "digging",
items = {name},
output = fmt("%s %u", item, data.output),
tools = data.tools,
}
end
for item, data in pairs(drop_maybe) do
craftguide.register_craft{
type = "digging_chance",
items = {name},
output = fmt("%s %u", item, data.output),
rarity = data.rarity,
tools = data.tools,
}
end
end
local function cache_drops(name, drop)
if true_str(drop) then
local dstack = ItemStack(drop)
if not dstack:is_empty() and dstack:get_name() ~= name then
craftguide.register_craft{
type = "digging",
items = {name},
output = drop,
}
end
elseif is_table(drop) then
drop_table(name, drop)
end
end
local function cache_recipes(item)
item = reg_aliases[item] or item
local recipes = get_all_recipes(item) or {}
if #recipes > 0 then
recipes_cache[item] = recipes
end
cache_drops(item, reg_items[item].drop)
cache_fuel(item)
end end
local function get_recipes(item, data, player) local function get_recipes(item, data, player)
@ -737,11 +813,10 @@ local function get_tooltip(name, info)
tooltip = group_names[concat(info.groups, ",")] tooltip = group_names[concat(info.groups, ",")]
if not tooltip then if not tooltip then
local groupstr, c = {}, 0 local groupstr = {}
for i = 1, #info.groups do for i = 1, #info.groups do
c = c + 1 insert(groupstr, clr("#ff0", info.groups[i]))
groupstr[c] = clr("#ff0", info.groups[i])
end end
groupstr = concat(groupstr, ", ") groupstr = concat(groupstr, ", ")
@ -1380,16 +1455,14 @@ core.register_craft = function(def)
end end
else else
def.width = #def.recipe[1] def.width = #def.recipe[1]
local c = 0
for j = 1, #def.recipe do for j = 1, #def.recipe do
if def.recipe[j] then if def.recipe[j] then
for h = 1, def.width do for h = 1, def.width do
c = c + 1
local it = def.recipe[j][h] local it = def.recipe[j][h]
if it and it ~= "" then if it and it ~= "" then
def.items[c] = it insert(def.items, it)
end end
end end
end end
@ -1419,95 +1492,7 @@ core.clear_craft = function(def)
end end
end end
local function handle_drops_table(name, drop) local function resolve_aliases(hash)
-- Code borrowed and modified from unified_inventory
-- https://github.com/minetest-mods/unified_inventory/blob/master/api.lua
local drop_sure, drop_maybe = {}, {}
local drop_items = drop.items or {}
local max_items_left = drop.max_items
local max_start = true
for i = 1, #drop_items do
if max_items_left and max_items_left <= 0 then break end
local di = drop_items[i]
for j = 1, #di.items do
local dstack = ItemStack(di.items[j])
local dname = dstack:get_name()
if not dstack:is_empty() and dname ~= name then
local dcount = dstack:get_count()
if #di.items == 1 and max_start and
(not di.rarity or di.rarity <= 1) then
if not drop_sure[dname] then
drop_sure[dname] = {}
end
drop_sure[dname] = {
output = (drop_sure[dname].output or 0) + dcount,
tools = di.tools,
}
if max_items_left then
max_items_left = max_items_left - 1
if max_items_left <= 0 then break end
end
else
if max_items_left then
max_start = false
end
if not drop_maybe[dname] then
drop_maybe[dname] = {}
end
drop_maybe[dname] = {
output = (drop_maybe[dname].output or 0) + dcount,
rarity = di.rarity,
tools = di.tools,
}
end
end
end
end
for item, data in pairs(drop_sure) do
craftguide.register_craft{
type = "digging",
items = {name},
output = fmt("%s %u", item, data.output),
tools = data.tools,
}
end
for item, data in pairs(drop_maybe) do
craftguide.register_craft{
type = "digging_chance",
items = {name},
output = fmt("%s %u", item, data.output),
rarity = data.rarity,
tools = data.tools,
}
end
end
local function register_drops(name, drop)
if true_str(drop) then
local dstack = ItemStack(drop)
if not dstack:is_empty() and dstack:get_name() ~= name then
craftguide.register_craft{
type = "digging",
items = {name},
output = drop,
}
end
elseif is_table(drop) then
handle_drops_table(name, drop)
end
end
local function handle_aliases(hash)
for oldname, newname in pairs(reg_aliases) do for oldname, newname in pairs(reg_aliases) do
cache_recipes(oldname) cache_recipes(oldname)
local recipes = recipes_cache[oldname] local recipes = recipes_cache[oldname]
@ -1545,58 +1530,30 @@ local function handle_aliases(hash)
end end
end end
local function show_item(def)
return not (def.groups.not_in_craft_guide == 1 or
def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= ""
end
local function get_init_items() local function get_init_items()
local init_items_bak = storage:get "init_items" local _select, _preselect = {}, {}
if autocache == false and init_items_bak then for name, def in pairs(reg_items) do
init_items = dslz(init_items_bak) if name ~= "" and show_item(def) then
fuel_cache = dslz(storage:get "fuel_cache") cache_recipes(name)
usages_cache = dslz(storage:get "usages_cache") _preselect[name] = true
recipes_cache = dslz(storage:get "recipes_cache")
else
print "[craftguide] Caching data (this may take a while)"
local _select, _preselect = {}, {}
for name, def in pairs(reg_items) do
if name ~= "" and show_item(def) then
register_drops(name, def.drop)
if not fuel_cache[name] then
cache_fuel(name)
end
if not recipes_cache[name] then
cache_recipes(name)
end
cache_usages(name)
_preselect[name] = true
end
end end
for name in pairs(_preselect) do
if recipes_cache[name] or usages_cache[name] then
init_items[#init_items + 1] = name
_select[name] = true
end
end
handle_aliases(_select)
sort(init_items)
storage:set_string("init_items", slz(init_items))
storage:set_string("fuel_cache", slz(fuel_cache))
storage:set_string("usages_cache", slz(usages_cache))
storage:set_string("recipes_cache", slz(recipes_cache))
end end
for name in pairs(_preselect) do
cache_usages(name)
end
for name in pairs(_preselect) do
if recipes_cache[name] or usages_cache[name] then
init_items[#init_items + 1] = name
_select[name] = true
end
end
resolve_aliases(_select)
sort(init_items)
if http and true_str(craftguide.export_url) then if http and true_str(craftguide.export_url) then
local post_data = { local post_data = {
recipes = recipes_cache, recipes = recipes_cache,

@ -3,10 +3,3 @@ craftguide_progressive_mode (Learn crafting recipes progressively) bool fa
# Integration in the default Minetest Game inventory. # Integration in the default Minetest Game inventory.
craftguide_sfinv_only (Crafting Guide in inventory only) bool false craftguide_sfinv_only (Crafting Guide in inventory only) bool false
# Enable pre-caching of item recipes.
# Do NOT disable the first time the mod loads.
# Disabling the auto-caching will result in faster mod loading.
# If you enable or disable mods, or edit the current mod recipes in your setup, you SHOULD re-enable this setting until the next caching at least.
# Usage at your own risk.
craftguide_autocache (Auto-caching of recipes) bool true