2017-02-11 23:30:24 +01:00
|
|
|
local filter = smart_inventory.filter
|
|
|
|
|
2017-02-08 21:55:29 +01:00
|
|
|
local cache = {}
|
2017-02-17 09:10:33 +01:00
|
|
|
cache.cgroups = {}
|
|
|
|
cache.citems = {}
|
2017-02-17 15:39:29 +01:00
|
|
|
cache.crecipes = {}
|
2017-02-11 23:30:24 +01:00
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
|
|
|
-- Group labels
|
|
|
|
-----------------------------------------------------
|
2017-02-11 23:30:24 +01:00
|
|
|
cache.group_info = {
|
2017-02-17 09:10:33 +01:00
|
|
|
--[[ group_level = { shortdesc = "Uses level information" },
|
2017-02-11 23:30:24 +01:00
|
|
|
group_dig_immediate = { shortdesc = "Fast removable" },
|
|
|
|
group_disable_jump = { shortdesc = "Not jumpable" },
|
|
|
|
group_less_damage = { shortdesc = "Less damage" },
|
|
|
|
group_more_damage = { shortdesc = "More damage" },
|
|
|
|
group_bouncy = { shortdesc = "Bouncy" },
|
|
|
|
group_falling_node = { shortdesc = "Falling" },
|
|
|
|
group_attached_node = { shortdesc = "Attachable" },
|
|
|
|
group_connect_to_raillike = { shortdesc = "Rail-like" },
|
|
|
|
-- TODO: http://dev.minetest.net/Groups/Custom_groups
|
|
|
|
|
2017-02-12 02:48:17 +01:00
|
|
|
group_armor_use = { shortdesc = "Armor" },
|
|
|
|
group_armor_heal = { shortdesc = "Armor" },
|
|
|
|
group_cracky = { shortdesc = "Cracky" },
|
|
|
|
group_flammable = { shortdesc = "Flammable" },
|
|
|
|
group_snappy = { shortdesc = "Snappy" },
|
|
|
|
group_choppy = { shortdesc = "Choppy" },
|
|
|
|
group_oddly_breakable_by_hand = { shortdesc = "Oddly breakable" },
|
2017-02-11 23:30:24 +01:00
|
|
|
type_tool = { shortdesc = "Tools" },
|
2017-02-12 02:48:17 +01:00
|
|
|
type_node = { shortdesc = "Nodes" },
|
|
|
|
type_craft = { shortdesc = "Craft Items" },
|
2017-02-11 23:30:24 +01:00
|
|
|
|
|
|
|
-- custom
|
|
|
|
transluc = { shortdesc = "Translucent blocks" },
|
|
|
|
inventory = { shortdesc = "Chestlike vessels" },
|
2017-02-17 09:10:33 +01:00
|
|
|
]]
|
2017-02-11 23:30:24 +01:00
|
|
|
-- list specific
|
|
|
|
all = {shortdesc = "All items" },
|
|
|
|
other = {shortdesc = "Other items" }
|
|
|
|
}
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
|
|
|
|
-----------------------------------------------------
|
|
|
|
-- Add a item to cache group
|
|
|
|
-----------------------------------------------------
|
2017-02-17 15:39:29 +01:00
|
|
|
function cache.add_to_cache_group(group_name, itemdef, shortdesc)
|
2017-02-17 09:10:33 +01:00
|
|
|
if not cache.cgroups[group_name] then
|
2017-02-11 23:30:24 +01:00
|
|
|
local group = {
|
|
|
|
name = group_name,
|
|
|
|
group_desc = shortdesc,
|
|
|
|
items = {}
|
|
|
|
}
|
|
|
|
if not group.group_desc and cache.group_info[group_name] then
|
|
|
|
group.group_desc = cache.group_info[group_name].shortdesc
|
|
|
|
end
|
|
|
|
if not group.group_desc then
|
|
|
|
group.group_desc = group_name
|
|
|
|
end
|
2017-02-17 09:10:33 +01:00
|
|
|
cache.cgroups[group_name] = group
|
2017-02-11 23:30:24 +01:00
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
table.insert(cache.cgroups[group_name].items,itemdef)
|
2017-02-11 23:30:24 +01:00
|
|
|
|
2017-02-17 15:39:29 +01:00
|
|
|
if not cache.citems[itemdef.name] then
|
2017-02-17 09:10:33 +01:00
|
|
|
local entry = {
|
2017-02-17 15:39:29 +01:00
|
|
|
name = itemdef.name,
|
|
|
|
in_output_recipe = {},
|
|
|
|
in_craft_recipe = {},
|
2017-02-17 09:10:33 +01:00
|
|
|
cgroups = {}
|
2017-02-11 23:30:24 +01:00
|
|
|
}
|
2017-02-17 15:39:29 +01:00
|
|
|
cache.citems[itemdef.name] = entry
|
2017-02-11 23:30:24 +01:00
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
table.insert(cache.citems[itemdef.name].cgroups,cache.cgroups[group_name])
|
2017-02-11 23:30:24 +01:00
|
|
|
end
|
2017-02-08 21:55:29 +01:00
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-17 15:39:29 +01:00
|
|
|
-- Resolve item in recipe described by groups to items list
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-17 15:39:29 +01:00
|
|
|
function cache.recipe_items_resolve_group(group_item)
|
|
|
|
local retitems = cache.cgroups[group_item]
|
|
|
|
if retitems then
|
|
|
|
return retitems.items
|
|
|
|
end
|
2017-02-11 23:30:24 +01:00
|
|
|
|
2017-02-17 15:39:29 +01:00
|
|
|
for groupname in string.gmatch(group_item:sub(7), '([^,]+)') do
|
|
|
|
if not retitems then --first entry
|
|
|
|
if cache.cgroups["group:"..groupname] then
|
|
|
|
retitems = table.copy(cache.cgroups["group:"..groupname].items)
|
|
|
|
else
|
|
|
|
minetest.log("verbose", "[smartfs_inventory] unknown group description in recipe: "..group_item, groupname)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
for i = #retitems, 1, -1 do
|
|
|
|
local item_in_group = false
|
|
|
|
for _, item_group in pairs(cache.citems[retitems[i].name].cgroups) do
|
|
|
|
if item_group.name == "group:"..groupname then
|
|
|
|
item_in_group = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if item_in_group == false then
|
|
|
|
table.remove(retitems,i)
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
if not retitems or not next(retitems) then
|
|
|
|
minetest.log("verbose", "[smartfs_inventory] no items matches group: "..group_item)
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--create new group
|
|
|
|
if retitems then
|
|
|
|
for _, itemdef in ipairs(retitems) do
|
|
|
|
cache.add_to_cache_group(group_item, itemdef)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return retitems
|
|
|
|
end
|
|
|
|
|
2017-02-08 21:55:29 +01:00
|
|
|
|
2017-02-17 15:39:29 +01:00
|
|
|
function cache.fill_recipe_cache()
|
|
|
|
for itemname, _ in pairs(cache.citems) do
|
|
|
|
local recipelist = minetest.get_all_craft_recipes(itemname)
|
2017-02-08 21:55:29 +01:00
|
|
|
if recipelist then
|
|
|
|
for _, recipe in ipairs(recipelist) do
|
2017-02-17 15:39:29 +01:00
|
|
|
-- apply recipe output
|
2017-02-08 21:55:29 +01:00
|
|
|
if recipe.output ~= "" then
|
2017-02-17 15:39:29 +01:00
|
|
|
local outdef = minetest.registered_items[recipe.output]
|
|
|
|
if not outdef then
|
|
|
|
recipe.output:gsub("[^%s]+", function(z)
|
|
|
|
if minetest.registered_items[z] then
|
|
|
|
outdef = minetest.registered_items[z]
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
2017-02-19 02:26:42 +01:00
|
|
|
if not outdef or not outdef.name or not cache.citems[outdef.name] then
|
2017-02-17 15:39:29 +01:00
|
|
|
minetest.log("verbose", "[smartfs_inventory] unknown recipe result "..recipe.output.." for item "..itemname)
|
|
|
|
else
|
|
|
|
table.insert(cache.citems[outdef.name].in_output_recipe, recipe)
|
|
|
|
cache.crecipes[recipe] = {
|
|
|
|
recipe_items = {},
|
|
|
|
out_item = outdef.name
|
|
|
|
}
|
|
|
|
for idx, recipe_item in pairs(recipe.items) do
|
|
|
|
local itemlist = {}
|
|
|
|
if recipe_item:sub(1, 6) == "group:" then
|
|
|
|
local groupitems = cache.recipe_items_resolve_group(recipe_item)
|
|
|
|
if not groupitems then
|
|
|
|
minetest.log("verbose", "[smartfs_inventory] skip recipe for: "..itemname)
|
|
|
|
else
|
|
|
|
for _, item in ipairs(cache.recipe_items_resolve_group(recipe_item)) do
|
|
|
|
table.insert(itemlist, item.name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
2017-02-17 17:33:05 +01:00
|
|
|
if minetest.registered_items[recipe_item] == nil then
|
|
|
|
minetest.log("verbose", "[smartfs_inventory] unknown item in recipe: "..itemname)
|
|
|
|
else
|
|
|
|
table.insert(itemlist,recipe_item)
|
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
end
|
|
|
|
cache.crecipes[recipe].recipe_items[recipe_item] = {}
|
|
|
|
for _, itemname in ipairs(itemlist) do
|
|
|
|
if cache.citems[itemname] then
|
|
|
|
table.insert(cache.citems[itemname].in_craft_recipe, recipe)
|
|
|
|
table.insert(cache.crecipes[recipe].recipe_items[recipe_item], itemname)
|
|
|
|
end
|
|
|
|
end
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-17 15:39:29 +01:00
|
|
|
-- Fill the cache at start
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-17 15:39:29 +01:00
|
|
|
function cache.fill_cache()
|
|
|
|
for name, def in pairs(minetest.registered_items) do
|
|
|
|
-- build groups and items cache
|
|
|
|
if def.description and def.description ~= "" and not def.groups.not_in_creative_inventory then
|
|
|
|
for group, grval in pairs(def.groups) do
|
|
|
|
local group_name = "group:"..group
|
|
|
|
cache.add_to_cache_group(group_name, def)
|
2017-02-23 09:15:25 +01:00
|
|
|
cache.add_to_cache_group(group_name..":"..tostring(grval), def)
|
2017-02-12 12:36:50 +01:00
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
cache.add_to_cache_group("type:"..def.type, def)
|
|
|
|
cache.add_to_cache_group("mod:"..def.mod_origin, def) -- TODO: get mod description and add it to shortdesc
|
|
|
|
|
|
|
|
-- extended registred filters
|
|
|
|
for _, flt in pairs(filter.registered_filter) do
|
|
|
|
if flt:check_item_by_def(def) == true then
|
|
|
|
cache.add_to_cache_group("filter:"..flt.name, def, flt.shortdesc)
|
|
|
|
end
|
2017-02-12 12:36:50 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
minetest.after(0, cache.fill_recipe_cache) --fill in second step
|
2017-02-12 12:36:50 +01:00
|
|
|
end
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-08 21:55:29 +01:00
|
|
|
-- Get all recipes with at least one item existing in players inventory
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-15 22:01:30 +01:00
|
|
|
function cache.get_recipes_craftable_atnext(player, item)
|
2017-02-08 21:55:29 +01:00
|
|
|
local inventory = minetest.get_player_by_name(player):get_inventory()
|
|
|
|
local invlist = inventory:get_list("main")
|
|
|
|
local items_in_inventory = {}
|
|
|
|
local recipe_with_one_item_in_inventory = {}
|
2017-02-15 22:01:30 +01:00
|
|
|
if item then
|
|
|
|
items_in_inventory[item] = true
|
|
|
|
else
|
|
|
|
for _, stack in ipairs(invlist) do
|
|
|
|
local itemname = stack:get_name()
|
2017-02-17 15:39:29 +01:00
|
|
|
if itemname and itemname ~= "" then
|
|
|
|
items_in_inventory[itemname] = true
|
|
|
|
end
|
2017-02-16 23:23:45 +01:00
|
|
|
end
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
for itemname, _ in pairs(items_in_inventory) do
|
2017-02-19 02:26:42 +01:00
|
|
|
if cache.citems[itemname] and cache.citems[itemname].in_craft_recipe then
|
|
|
|
for _, recipe in ipairs(cache.citems[itemname].in_craft_recipe) do
|
|
|
|
local def = minetest.registered_items[recipe.output]
|
|
|
|
if not def then
|
|
|
|
recipe.output:gsub("[^%s]+", function(z)
|
|
|
|
if minetest.registered_items[z] then
|
|
|
|
def = minetest.registered_items[z]
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
if def then
|
|
|
|
local recipe_ok = false
|
|
|
|
for recipe_item, itemtab in pairs(cache.crecipes[recipe].recipe_items) do
|
|
|
|
recipe_ok = false
|
|
|
|
for _, itemname in ipairs(itemtab) do
|
|
|
|
if filter.is_revealed_item(itemname, player) == true then
|
|
|
|
recipe_ok = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if recipe_ok == false then
|
2017-02-16 23:23:45 +01:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2017-02-19 02:26:42 +01:00
|
|
|
if recipe_ok then
|
|
|
|
recipe_with_one_item_in_inventory[recipe] = true
|
2017-02-16 23:23:45 +01:00
|
|
|
end
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return recipe_with_one_item_in_inventory, items_in_inventory
|
|
|
|
end
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-08 21:55:29 +01:00
|
|
|
-- Get all recipes with all required items in players inventory. Without count match
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-11 23:30:24 +01:00
|
|
|
function cache.get_recipes_craftable(player)
|
|
|
|
local all, items_in_inventory = cache.get_recipes_craftable_atnext(player)
|
2017-02-08 21:55:29 +01:00
|
|
|
local craftable = {}
|
|
|
|
for recipe, _ in pairs(all) do
|
2017-02-17 15:39:29 +01:00
|
|
|
local item_ok = false
|
|
|
|
for _, itemtab in pairs(cache.crecipes[recipe].recipe_items) do
|
|
|
|
item_ok = false
|
|
|
|
for _, itemname in ipairs(itemtab) do
|
|
|
|
if items_in_inventory[itemname] then
|
|
|
|
item_ok = true
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
if item_ok == false then
|
2017-02-08 21:55:29 +01:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if item_ok == true then
|
2017-02-17 15:39:29 +01:00
|
|
|
craftable[recipe] = true
|
2017-02-08 21:55:29 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return craftable, items_in_inventory
|
|
|
|
end
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
|
|
|
-- Sort items to groups and decide which groups should be displayed
|
|
|
|
-----------------------------------------------------
|
2017-02-21 21:41:40 +01:00
|
|
|
function cache.get_list_grouped(itemtable, group_count)
|
2017-02-11 23:30:24 +01:00
|
|
|
local grouped = {}
|
|
|
|
-- sort the entries to groups
|
|
|
|
for _, entry in ipairs(itemtable) do
|
2017-02-17 09:10:33 +01:00
|
|
|
if cache.citems[entry.item] then
|
|
|
|
for _, group in ipairs(cache.citems[entry.item].cgroups) do
|
2017-02-11 23:30:24 +01:00
|
|
|
if not grouped[group.name] then
|
2017-02-17 15:39:29 +01:00
|
|
|
local group_info = {}
|
|
|
|
group_info.name = group.name
|
|
|
|
group_info.cgroup = cache.cgroups[group.name]
|
2017-02-11 23:30:24 +01:00
|
|
|
group_info.items = {}
|
|
|
|
grouped[group.name] = group_info
|
|
|
|
end
|
|
|
|
table.insert(grouped[group.name].items, entry)
|
|
|
|
end
|
|
|
|
end
|
2017-02-12 02:48:17 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
-- magic to calculate relevant groups
|
|
|
|
local itemcount = #itemtable
|
2017-02-21 21:41:40 +01:00
|
|
|
local best_group_count = group_count or itemcount ^(1/3)
|
2017-02-12 02:48:17 +01:00
|
|
|
local best_group_size = (itemcount / best_group_count) * 1.5
|
|
|
|
best_group_count = math.floor(best_group_count)
|
|
|
|
local sorttab = {}
|
|
|
|
|
|
|
|
for k,v in pairs(grouped) do
|
|
|
|
v.group_size = #v.items
|
|
|
|
v.unique_count = #v.items
|
|
|
|
v.diff = math.abs(v.group_size - best_group_size)
|
|
|
|
table.insert(sorttab, v)
|
|
|
|
end
|
|
|
|
|
|
|
|
local outtab = {}
|
|
|
|
local assigned_items = {}
|
|
|
|
if best_group_count > 0 then
|
|
|
|
for i = 1, best_group_count do
|
|
|
|
-- sort by best size
|
|
|
|
table.sort(sorttab, function(a,b)
|
|
|
|
return a.diff < b.diff
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- select the best
|
|
|
|
local sel = sorttab[1]
|
|
|
|
if not sel then
|
|
|
|
break
|
|
|
|
end
|
2017-02-17 15:39:29 +01:00
|
|
|
outtab[sel.name] = {
|
|
|
|
name = sel.name,
|
|
|
|
group_desc = sel.cgroup.group_desc,
|
|
|
|
items = sel.items
|
|
|
|
}
|
2017-02-12 02:48:17 +01:00
|
|
|
table.remove(sorttab,1)
|
|
|
|
|
|
|
|
for _, item in ipairs(sel.items) do
|
|
|
|
assigned_items[item.item] = true
|
|
|
|
-- update the not selected groups
|
2017-02-17 09:10:33 +01:00
|
|
|
for _, group in ipairs(cache.citems[item.item].cgroups) do
|
2017-02-12 02:48:17 +01:00
|
|
|
if group.name ~= sel.name then
|
|
|
|
local u = grouped[group.name]
|
|
|
|
if u and u.unique_count then
|
|
|
|
u.unique_count = u.unique_count-1
|
2017-02-12 11:16:33 +01:00
|
|
|
if (u.group_size < best_group_size) or
|
|
|
|
(u.group_size - best_group_size) < (best_group_size - u.unique_count) then
|
2017-02-12 02:48:17 +01:00
|
|
|
sel.diff = best_group_size - u.unique_count
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for idx = #sorttab, 1, -1 do
|
|
|
|
if sorttab[idx].unique_count <= 1 then
|
|
|
|
table.remove(sorttab, idx)
|
|
|
|
end
|
|
|
|
end
|
2017-02-11 23:30:24 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-02-12 02:48:17 +01:00
|
|
|
-- fill other group
|
|
|
|
local other = {}
|
|
|
|
for _, item in ipairs(itemtable) do
|
|
|
|
if not assigned_items[item.item] then
|
|
|
|
table.insert(other, item)
|
|
|
|
end
|
|
|
|
end
|
2017-02-11 23:30:24 +01:00
|
|
|
|
|
|
|
-- default groups
|
2017-02-12 02:48:17 +01:00
|
|
|
outtab.all = {}
|
|
|
|
outtab.all.name = "all"
|
|
|
|
outtab.all.group_desc = cache.group_info[outtab.all.name].shortdesc
|
|
|
|
outtab.all.items = itemtable
|
2017-02-11 23:30:24 +01:00
|
|
|
|
2017-02-12 02:48:17 +01:00
|
|
|
outtab.other = {}
|
|
|
|
outtab.other.name = "other"
|
|
|
|
outtab.other.group_desc = cache.group_info[outtab.other.name].shortdesc
|
|
|
|
outtab.other.items = other
|
2017-02-11 23:30:24 +01:00
|
|
|
|
2017-02-12 02:48:17 +01:00
|
|
|
return outtab
|
2017-02-11 23:30:24 +01:00
|
|
|
end
|
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-08 21:55:29 +01:00
|
|
|
-- fill the cache after all mods loaded
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-11 23:30:24 +01:00
|
|
|
minetest.after(0, cache.fill_cache)
|
2017-02-08 21:55:29 +01:00
|
|
|
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-08 21:55:29 +01:00
|
|
|
-- return the reference to the mod
|
2017-02-17 09:10:33 +01:00
|
|
|
-----------------------------------------------------
|
2017-02-08 21:55:29 +01:00
|
|
|
return cache
|