-- TODO: aliases? local function get_drops(item, def) local normalDrops = {} local randomDrops = {} if type(def.drop) == "table" then -- Handle complex drops. This is the method used by Unified Inventory. local maxStart = true local itemsLeft = def.drop.max_items local dropTables = def.drop.items or {} local dStack, dName, dCount for _, dropTable in ipairs(dropTables) do if itemsLeft and itemsLeft <= 0 then break end for _, dropItem in ipairs(dropTable.items) do dStack = ItemStack(dropItem) dName = dStack:get_name() dCount = dStack:get_count() if dCount > 0 and dName ~= item then if #dropTable.items == 1 and dropTable.rarity == 1 and maxStart then normalDrops[dName] = (normalDrops[dName] or 0) + dCount if itemsLeft then itemsLeft = itemsLeft - 1 if itemsLeft <= 0 then break end end else if itemsLeft then maxStart = false end randomDrops[dName] = (randomDrops[dName] or 0) + dCount end end end end else -- Handle simple, one-item drops. local dStack = ItemStack(def.drop) if not dStack:is_empty() and dStack:get_name() ~= item then normalDrops[dStack:get_name()] = dStack:get_count() end end return normalDrops, randomDrops end function cg.build_item_list() local startTime = minetest.get_us_time() cg.items_all.list = {} for item, def in pairs(minetest.registered_items) do if def.description and def.description ~= "" and minetest.get_item_group(item, "not_in_creative_inventory") == 0 and minetest.get_item_group(item, "not_in_craft_guide") == 0 then table.insert(cg.items_all.list, item) cg.crafts[item] = minetest.get_all_craft_recipes(item) or {} end end local def, fuel, decremented for _, item in ipairs(cg.items_all.list) do def = minetest.registered_items[item] fuel, decremented = minetest.get_craft_result({ method = "fuel", width = 0, items = {ItemStack(item)} }) if fuel.time > 0 then table.insert(cg.crafts[item], { type = "fuel", items = {item}, output = decremented.items[1]:to_string(), time = fuel.time, }) end if def.drop then local normalDrops, randomDrops = get_drops(item, def) for dItem, dCount in pairs(normalDrops) do if cg.crafts[dItem] then table.insert(cg.crafts[dItem], { type = "digging", width = 0, items = {item}, output = ItemStack({ name = dItem, count = dCount }):to_string() }) end end for dItem, dCount in pairs(randomDrops) do if cg.crafts[dItem] then table.insert(cg.crafts[dItem], { type = "digging_chance", width = 0, items = {item}, output = ItemStack({ name = dItem, count = dCount }):to_string() }) end end end for group, _ in pairs(def.groups) do if not cg.group_stereotypes[group] then cg.group_stereotypes[group] = item end end end table.sort(cg.items_all.list) cg.items_all.num_pages = math.ceil(#cg.items_all.list / cg.PAGE_ITEMS) minetest.log("info", string.format( "[cg_plus] Finished building item list in %.3f s.", (minetest.get_us_time() - startTime) / 1000000 ) ) end function cg.filter_items(player, filter) local playerName = player:get_player_name() local playerData = cg.player_data[playerName] if not filter or filter == "" then playerData.items = nil return end playerData.items = {list = {}} filter = filter:lower() local groupFilter = string.sub(filter, 1, 6) == "group:" and filter:sub(7) if groupFilter and cg.GROUP_SEARCH then -- Search by group local groups = string.split(groupFilter, ",") local isInGroups for _, item in ipairs(cg.items_all.list) do isInGroups = true for idx = 1, math.min(#groups, cg.GROUP_SEARCH_MAX) do if minetest.get_item_group(item, groups[idx]) == 0 then isInGroups = false break end end if isInGroups then table.insert(playerData.items.list, item) end end else -- Regular search local langCode = playerData.lang_code for _, item in ipairs(cg.items_all.list) do if item:lower():find(filter, 1, true) or minetest.get_translated_string(langCode, minetest.registered_items[item].description) :lower():find(filter, 1, true) then table.insert(playerData.items.list, item) end end end playerData.items.num_pages = math.ceil(#cg.get_item_list(player).list / cg.PAGE_ITEMS) end function cg.parse_craft(craft) local type = craft.type local template = cg.craft_types[type] or {} if craft.width == 0 and template.alt_zero_width then type = template.alt_zero_width template = cg.craft_types[template.alt_zero_width] or {} end local newCraft = { type = type, items = {}, output = craft.output, } if template.get_infotext then newCraft.infotext = template.get_infotext(craft) or "" end local width = math.max(craft.width or 0, 1) if template.get_grid_size then newCraft.grid_size = template.get_grid_size(craft) else newCraft.grid_size = { x = width, y = math.ceil(table.maxn(craft.items) / width) } end if template.inherit_width then -- For shapeless recipes, there is no need to modify the item list. newCraft.items = craft.items else -- The craft's width is not always the same as the grid size, so items -- need to be shifted around. for idx, item in pairs(craft.items) do newCraft.items[idx + (newCraft.grid_size.x - width) * math.floor((idx - 1) / width)] = item end end return newCraft end function cg.get_item_list(player) return cg.player_data[player:get_player_name()].items or cg.items_all end function cg.register_craft_type(name, def) cg.craft_types[name] = def end function cg.register_group_stereotype(group, item) cg.group_stereotypes[group] = item end minetest.register_on_mods_loaded(cg.build_item_list) minetest.register_on_joinplayer(function(player) local playerName = player:get_player_name() local langCode = minetest.get_player_information(playerName).lang_code cg.player_data[playerName] = { lang_code = langCode } end) minetest.register_on_leaveplayer(function(player, timed_out) cg.player_data[player:get_player_name()] = nil end)