From cbb5bed9872265a738d4f22c43515700c2e7d457 Mon Sep 17 00:00:00 2001 From: Paul Ouellette Date: Fri, 11 Jan 2019 17:32:25 -0500 Subject: [PATCH] Progressive: refactor and fix some bugs --- init.lua | 275 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 144 insertions(+), 131 deletions(-) diff --git a/init.lua b/init.lua index eb3c07a..905d05e 100644 --- a/init.lua +++ b/init.lua @@ -20,7 +20,7 @@ local S = dofile(mt.get_modpath("craftguide") .. "/intllib.lua") -- Lua 5.3 removed `table.maxn`, use this alternative in case of breakage: -- https://github.com/kilbith/xdecor/blob/master/handlers/helpers.lua#L1 -local remove, maxn, sort, concat = table.remove, table.maxn, table.sort, table.concat +local maxn, sort, concat = table.maxn, table.sort, table.concat local vector_add, vector_mul = vector.add, vector.multiply local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil local fmt = string.format @@ -120,39 +120,6 @@ local function get_fueltime(item) return get_result({method = "fuel", width = 1, items = {item}}).time end -local function reset_data(data) - data.show_usage = nil - data.filter = "" - data.input = nil - data.pagenum = 1 - data.rnum = 1 - data.items = progressive_mode and data.init_filter_items or init_items -end - -local function in_table(T) - for i = 1, #T do - if T[i] then - return true - end - end -end - -local function group_to_items(group) - local items_with_group, c = {}, 0 - for name, def in pairs(reg_items) do - if def.groups[group:sub(7)] then - c = c + 1 - items_with_group[c] = name - end - end - - return items_with_group -end - -local function item_in_inv(inv, item) - return inv:contains_item("main", item) -end - local function extract_groups(str) return str:sub(7):split(",") end @@ -382,10 +349,6 @@ local function get_formspec(player_name) local iY = sfinv_only and 4 or data.iX - 5 local ipp = data.iX * iY - if not data.items then - data.items = init_items - end - data.pagemax = max(1, ceil(#data.items / ipp)) local fs = {} @@ -458,12 +421,11 @@ local function get_formspec(player_name) end fs = concat(fs) - data.formspec = fs if sfinv_only then return fs else - show_formspec(player_name, "craftguide", fs) + data.formspec = fs end end @@ -473,75 +435,32 @@ local show_fs = function(player, player_name) sfinv.set_player_inventory_formspec(player, context) else get_formspec(player_name) + local data = player_data[player_name] + show_formspec(player_name, "craftguide", data.formspec) end end -local function recipe_in_inv(inv, item_name, recipes_f) - local recipes = recipes_f or get_recipes(item_name) - local show_item_recipes = {} - - for i = 1, #recipes do - show_item_recipes[i] = true - for _, item in pairs(recipes[i].items) do - local group_in_inv = false - if item:sub(1,6) == "group:" then - local groups = group_to_items(item) - for j = 1, #groups do - if item_in_inv(inv, groups[j]) then - group_in_inv = true - end - end - end - - if not group_in_inv and not item_in_inv(inv, item) then - show_item_recipes[i] = false - end - end - end - - for i = #show_item_recipes, 1, -1 do - if not show_item_recipes[i] then - remove(recipes, i) - end - end - - return recipes, in_table(show_item_recipes) -end - -local function get_filter_items(data, player) +local function filter_items(data) local filter = data.filter if searches[filter] then data.items = searches[filter] return end - local items_list = progressive_mode and data.init_filter_items or init_items - local inv = player:get_inventory() + local items_list = progressive_mode and data.progressive_items or init_items local filtered_list, c = {}, 0 for i = 1, #items_list do local item = items_list[i] local item_desc = reg_items[item].description:lower() - if filter ~= "" then - if item:find(filter, 1, true) or item_desc:find(filter, 1, true) then - c = c + 1 - filtered_list[c] = item - end - elseif progressive_mode then - local _, has_item = recipe_in_inv(inv, item) - if has_item then - c = c + 1 - filtered_list[c] = item - end + if item:find(filter, 1, true) or item_desc:find(filter, 1, true) then + c = c + 1 + filtered_list[c] = item end end - if progressive_mode then - if not data.items then - data.init_filter_items = filtered_list - end - elseif filter ~= "" then + if not progressive_mode then -- Cache the results only if searched 2 times if searches[filter] == nil then searches[filter] = false @@ -553,31 +472,6 @@ local function get_filter_items(data, player) data.items = filtered_list end -local function init_data(user, name) - player_data[name] = {filter = "", pagenum = 1, iX = sfinv_only and 8 or DEFAULT_SIZE} - if progressive_mode then - get_filter_items(player_data[name], user) - end -end - -local function get_init_items() - local c = 0 - for name, def in pairs(reg_items) do - local is_fuel = get_fueltime(name) > 0 - if not (def.groups.not_in_craft_guide == 1 or - def.groups.not_in_creative_inventory == 1) and - (get_recipe(name).items or is_fuel) and - def.description and def.description ~= "" then - c = c + 1 - init_items[c] = name - end - end - - sort(init_items) -end - -mt.register_on_mods_loaded(get_init_items) - local function item_in_recipe(item, recipe) local item_groups = reg_items[item].groups for _, recipe_item in pairs(recipe.items) do @@ -613,6 +507,119 @@ local function get_item_usages(item) return usages end +local function get_inv_items(player) + local invlist = player:get_inventory():get_list("main") + local inv_items = {} + + for i = 1, #invlist do + local stack = invlist[i] + if not stack:is_empty() then + inv_items[#inv_items + 1] = stack:get_name() + end + end + + return inv_items +end + +local function progressive_show_recipe(recipe, inv_items) + for _, item in pairs(recipe.items) do + local item_in_inv + if item:sub(1,6) == "group:" then + local groups = extract_groups(item) + for i = 1, #inv_items do + local item_def = reg_items[inv_items[i]] + if item_def then + local item_groups = item_def.groups + if item_has_groups(item_groups, groups) then + item_in_inv = true + end + end + end + else + for i = 1, #inv_items do + if inv_items[i] == item then + item_in_inv = true + end + end + end + + if not item_in_inv then + return + end + end + + return true +end + +local function progressive_filter_recipes(recipes, player) + local inv_items = get_inv_items(player) + if #inv_items == 0 then + return {} + end + + local filtered = {} + for i = 1, #recipes do + local recipe = recipes[i] + if progressive_show_recipe(recipe, inv_items) then + filtered[#filtered + 1] = recipe + end + end + + return filtered +end + +local function get_progressive_items(player) + local items = {} + for i = 1, #init_items do + local item = init_items[i] + local recipes = progressive_filter_recipes(get_recipes(item), player) + + if #recipes > 0 then + items[#items + 1] = item + end + end + + return items +end + +local function init_data(player, name) + local p_items = progressive_mode and get_progressive_items(player) or nil + player_data[name] = { + filter = "", + pagenum = 1, + iX = sfinv_only and 8 or DEFAULT_SIZE, + items = p_items or init_items, + progressive_items = p_items + } +end + +local function reset_data(data) + data.show_usage = nil + data.filter = "" + data.input = nil + data.pagenum = 1 + data.rnum = 1 + data.items = progressive_mode and data.progressive_items or init_items +end + +local function get_init_items() + local c = 0 + for name, def in pairs(reg_items) do + local is_fuel = get_fueltime(name) > 0 + if not (def.groups.not_in_craft_guide == 1 or + def.groups.not_in_creative_inventory == 1) and + (get_recipe(name).items or is_fuel) and + def.description and def.description ~= "" then + c = c + 1 + init_items[c] = name + end + end + + sort(init_items) +end + +mt.register_on_mods_loaded(get_init_items) + local function get_fields(player, ...) local args, formname, fields = {...} if sfinv_only then @@ -656,7 +663,7 @@ local function get_fields(player, ...) data.filter = fltr data.pagenum = 1 - get_filter_items(data, player) + filter_items(data) show_fs(player, player_name) elseif fields.prev or fields.next then @@ -679,9 +686,12 @@ local function get_fields(player, ...) if item:find(":") then local is_fuel = get_fueltime(item) > 0 local recipes = get_recipes(item) + if progressive_mode then + recipes = progressive_filter_recipes(recipes, player) + end local no_recipes = not next(recipes) - if no_recipes and not is_fuel then + if no_recipes and (progressive_mode or not is_fuel) then return end @@ -707,17 +717,12 @@ local function get_fields(player, ...) } end - if not next(data.usages) then - data.show_usage = nil + if progressive_mode then + data.usages = progressive_filter_recipes(data.usages, player) end - elseif progressive_mode then - local inv = player:get_inventory() - local has_item - recipes, has_item = recipe_in_inv(inv, item, recipes) - - if not has_item then - return + if not next(data.usages) then + data.show_usage = nil end end @@ -748,8 +753,11 @@ if sfinv_only then local player_name = player:get_player_name() local data = player_data[player_name] - if progressive_mode or not data then + if not data then init_data(player, player_name) + elseif progressive_mode then + data.progressive_items = get_progressive_items(player) + filter_items(data) end end, @@ -764,12 +772,17 @@ else local player_name = user:get_player_name() local data = player_data[player_name] - if progressive_mode or not data then + if not data then init_data(user, player_name) get_formspec(player_name) - else - show_formspec(player_name, "craftguide", data.formspec) + data = player_data[player_name] + elseif progressive_mode then + data.progressive_items = get_progressive_items(user) + filter_items(data) + get_formspec(player_name) end + + show_formspec(player_name, "craftguide", data.formspec) end mt.register_craftitem("craftguide:book", {