local txt = smart_inventory.txt -------------------------------------------------------------- -- Filter class -------------------------------------------------------------- local filter_class = {} local filter_class_mt = {__index = filter_class} function filter_class:check_item_by_name(itemname) if minetest.registered_items[itemname] then return self:check_item_by_def(minetest.registered_items[itemname]) end end function filter_class:check_item_by_def(def) error("check_item_by_def needs redefinition:"..debug.traceback()) end function filter_class:_get_description(group) if txt then if txt[group.name] then return txt[group.name].." ("..group.name..")" elseif group.parent and group.parent.childs[group.name] and txt[group.parent.name] then return txt[group.parent.name].." "..group.parent.childs[group.name].." ("..group.name..")" else return group.name end else return group.name end end filter_class.get_description = filter_class._get_description function filter_class:_get_keyword(group) return group.group_desc end filter_class.get_keyword = filter_class._get_keyword function filter_class:is_valid(group) return true end local filter = {} filter.registered_filter = {} function filter.get(name) return filter.registered_filter[name] end function filter.register_filter(def) assert(def.name, "filter needs a name") assert(def.check_item_by_def, "filter function check_item_by_def required") assert(not filter.registered_filter[def.name], "filter already exists") setmetatable(def, filter_class_mt) filter.registered_filter[def.name] = def end -- rename groups for beter consistency filter.group_rename = { customnode_default = "customnode", } -- group configurations per basename -- true means is dimension -- 1 means replace the base only ("food_choco_powder" => food:choco_powder") filter.base_group_config = { armor = true, physics = true, basecolor = true, excolor = true, color = true, unicolor = true, food = 1, customnode = true, } -- hide this groups filter.group_hide_config = { armor_count = true, not_in_creative_inventory = false, } -- value of this group will be recalculated to % filter.group_wear_config = { armor_use = true, } -- Ususally 1 means true for group values. This is an exceptions table for this rule filter.group_with_value_1_config = { oddly_breakable_by_hand = true, } -------------------------------------------------------------- -- Filter group -------------------------------------------------------------- filter.register_filter({ name = "group", check_item_by_def = function(self, def) local ret = {} for k_orig, v in pairs(def.groups) do local k = filter.group_rename[k_orig] or k_orig local mk, mv -- Check group base local basename for z in k:gmatch("[^_]+") do basename = z break end local basegroup_config = filter.base_group_config[basename] if basegroup_config == true then mk = string.gsub(k, "_", ":") elseif basegroup_config == 1 then mk = string.gsub(k, "^"..basename.."_", basename..":") else mk = k end -- stack wear related value if filter.group_wear_config[k] then mv = tostring(math.floor(v / 65535 * 10000 + 0.5)/100).." %" -- value-expandable groups elseif v ~= 1 or k == filter.group_with_value_1_config[k] then mv = v else mv = true end if v ~= 0 and mk and not filter.group_hide_config[k] then ret[mk] = mv end end return ret end, }) filter.register_filter({ name = "type", check_item_by_def = function(self, def) return self.name..":"..def.type end, get_keyword = function(self, group) if group.name ~= self.name then return group.parent.childs[group.name] end end }) filter.register_filter({ name = "mod", check_item_by_def = function(self, def) if def.mod_origin then return self.name..":"..def.mod_origin end end, get_keyword = function(self, group) if group.name ~= self.name then return group.parent.childs[group.name] end end }) filter.register_filter({ name = "translucent", check_item_by_def = function(self, def) if def.sunlight_propagates ~= 0 then return def.sunlight_propagates end end, }) filter.register_filter({ name = "light", check_item_by_def = function(self, def) if def.light_source ~= 0 then return def.light_source end end, }) filter.register_filter({ name = "metainv", check_item_by_def = function(self, def) if def.allow_metadata_inventory_move or def.allow_metadata_inventory_take or def.allow_metadata_inventory_put or def.on_metadata_inventory_move or def.on_metadata_inventory_take or def.on_metadata_inventory_put then return true end end, }) --[[ does it sense to filter them? I cannot define the human readable groups for them filter.register_filter({ name = "drawtype", check_item_by_def = function(self, def) if def.drawtype ~= "normal" then return def.drawtype end end, }) ]] local shaped_groups = {} local shaped_list = minetest.setting_get("smart_inventory_shaped_groups") or "carpet,door,fence,stair,slab,wall,micro,panel,slope" if shaped_list then for z in shaped_list:gmatch("[^,]+") do shaped_groups[z] = true end end filter.register_filter({ name = "shape", check_item_by_def = function(self, def) local door_groups if shaped_groups["door"] then local door_filter = filter.get("door") door_groups = door_filter:check_item_by_def(def) if door_groups and door_groups.door then return true end end for k, v in pairs(def.groups) do if k ~= "door" and shaped_groups[k] then return true end end end, }) --[[ disabled since debug.getupvalue is not usable to secure environment filter.register_filter({ name = "food", check_item_by_def = function(self, def) if def.on_use then local name,change=debug.getupvalue(def.on_use, 1) if name~=nil and name=="hp_change" and change > 0 then return tostring(change) end end end, }) filter.register_filter({ name = "toxic", check_item_by_def = function(self, def) if def.on_use then local name,change=debug.getupvalue(def.on_use, 1) if name~=nil and name=="hp_change" and change < 0 then return tostring(change) end end end, }) ]] filter.register_filter({ name = "tool", check_item_by_def = function(self, def) if not def.tool_capabilities then return end local rettab = {} for k, v in pairs(def.tool_capabilities) do if type(v) ~= "table" and v ~= 0 then rettab["tool:"..k] = v end end if def.tool_capabilities.damage_groups then for k, v in pairs(def.tool_capabilities.damage_groups) do if v ~= 0 then rettab["damage:"..k] = v end end end --[[ disabled, I cannot find right human readable interpretation for this if def.tool_capabilities.groupcaps then for groupcap, gdef in pairs(def.tool_capabilities.groupcaps) do for k, v in pairs(gdef) do if type(v) ~= "table" then rettab["groupcaps:"..groupcap..":"..k] = v end end end end ]] return rettab end, get_keyword = function(self, group) if group.name == "tool" or group.name == "damage" then return nil else return self:_get_keyword(group) end end }) filter.register_filter({ name = "armor", check_item_by_def = function(self, def) return def.armor_groups end, }) filter.register_filter({ name = 'clothing_cape', check_item_by_def = function(self, def) if def.groups.cape then return 'clothing' end end }) -- Burn times filter.register_filter({ name = "fuel", check_item_by_def = function(self, def) local burntime = minetest.get_craft_result({method="fuel",width=1,items={def.name}}).time if burntime > 0 then return "fuel:"..burntime end end }) -- Group assignment done in cache framework internally filter.register_filter({ name = "recipetype", check_item_by_def = function(self, def) end, get_keyword = function(self, group) if group.name ~= self.name then return group.parent.childs[group.name] end end }) -- Group assignment done in cache framework internally filter.register_filter({ name = "ingredient", check_item_by_def = function(self, def) end, get_description = function(self, group) local itemname = group.name:sub(12) if txt and txt["ingredient"] and minetest.registered_items[itemname] and minetest.registered_items[itemname].description then return txt["ingredient"] .." "..minetest.registered_items[itemname].description.." ("..group.name..")" else return group.name end end, get_keyword = function(self, group) -- not searchable by ingedient return nil end, is_valid = function(self, groupname) local itemname = groupname:sub(12) if itemname ~= "" and minetest.registered_items[itemname] then return true end end }) local door_groups local function fill_door_groups() door_groups = {} for _, extend_def in pairs(minetest.registered_items) do local base_def if extend_def.groups and extend_def.groups.door then if extend_def.door then base_def = minetest.registered_items[extend_def.door.name] elseif extend_def.drop and type(extend_def.drop) == "string" then base_def = minetest.registered_items[extend_def.drop] end end if base_def then door_groups[base_def.name] = extend_def door_groups[extend_def.name] = false end end end filter.register_filter({ name = "door", check_item_by_def = function(self, def) if not door_groups then fill_door_groups() end if not door_groups[def.name] then return end local group_filter = filter.get("group") local ret = group_filter:check_item_by_def(door_groups[def.name]) if ret then ret["not_in_creative_inventory"] = nil return ret end end }) ---------------- return filter