cg_plus-cd2025/api.lua
random-geek 6511eb8261 Bunch of updates
- Update and document public API
- Fixes to group handling
- New clear icon
2024-04-21 01:39:27 -07:00

305 lines
9.3 KiB
Lua

-- TODO: aliases?
local custom_crafts = {}
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
local function build_group_stereotypes_list()
-- Remember: Some group stereotypes are already registered
local startTime = minetest.get_us_time()
local usedMultiGroups = {}
for _, recipes in pairs(cg.crafts) do
for _, recipe in ipairs(recipes) do
for _, item in ipairs(recipe.items) do
if item:sub(1, 6) == "group:" then
local groupsString = item:sub(7)
local groupsTable = groupsString:split(",")
if #groupsTable > 1 then
usedMultiGroups[groupsString] = groupsTable
end
end
end
end
end
for _, item in ipairs(cg.items_all.list) do
local groups = minetest.registered_items[item].groups
for group, _ in pairs(groups) do
if cg.group_stereotypes[group] == nil then
cg.group_stereotypes[group] = item
end
end
for clusterString, clusterTable in pairs(usedMultiGroups) do
if cg.group_stereotypes[clusterString] == nil then
local match = true
for _, group in ipairs(clusterTable) do
if not groups[group] then
match = false
break
end
end
if match then
cg.group_stereotypes[clusterString] = item
end
end
end
end
minetest.log("info", string.format("[cg_plus] Finished building group stereotype list in %.3f s.",
(minetest.get_us_time() - startTime) / 1000000))
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 {}
table.insert_all(cg.crafts[item], custom_crafts[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], {
method = "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], {
method = "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], {
method = "digging_chance",
width = 0,
items = {item},
output = ItemStack({
name = dItem,
count = dCount
}):to_string()
})
end
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
)
)
build_group_stereotypes_list()
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 method
if craft.method == "normal" and craft.width == 0 then -- Special rules for shapeless recipes
method = "shapeless"
else
method = craft.method
end
local template = cg.craft_methods[method] or {}
local gridSize = (template.get_grid_size and template.get_grid_size(craft)) or {x = 3, y = 3}
local width = craft.width or 0
local items = {}
if width == 0 then
-- Shapeless recipes
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 i, item in pairs(craft.items) do
items[i + (gridSize.x - width) * math.floor((i - 1) / width)] = item
end
end
return {
method = method,
infotext = (template.get_infotext and template.get_infotext(craft)) or "",
grid_size = gridSize,
width = width,
items = items,
output = craft.output or "",
}
end
function cg.get_item_list(player)
return cg.player_data[player:get_player_name()].items or cg.items_all
end
function cg.register_crafting_method(name, def)
cg.craft_methods[name] = def
end
function cg.register_craft(recipe, assign_to)
local item = ItemStack(assign_to or recipe.output):get_name() -- Removes quantity, etc. from itemstring
custom_crafts[item] = custom_crafts[item] or {}
table.insert(custom_crafts[item], recipe)
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)