Compare commits

..

13 Commits
1.5 ... 1.5.1

3 changed files with 122 additions and 78 deletions

16
API.md
View File

@ -70,10 +70,15 @@ Returns a map of recipe filters, indexed by name.
Search filters are used to perform specific searches inside the search field. Search filters are used to perform specific searches inside the search field.
They can be used like so: `<optional name>+<filter name>=<value1>,<value2>,<...>` They can be used like so: `<optional name>+<filter name>=<value1>,<value2>,<...>`
Examples:
- `+groups=cracky,crumbly`: search for groups `cracky` and `crumbly` in all items.
- `sand+groups=falling_node`: search for group `falling_node` for items which contain `sand` in their names.
Notes: Notes:
- If `optional name` is omitted, the search filter will apply to all items, without pre-filtering. - If `optional name` is omitted, the search filter will apply to all items, without pre-filtering.
- Filters can be combined. - Filters can be combined.
- The `+groups=` filter is currently implemented by default. - The `groups` filter is currently implemented by default.
#### `craftguide.add_search_filter(name, function(item, values))` #### `craftguide.add_search_filter(name, function(item, values))`
@ -166,3 +171,12 @@ Opens the Crafting Guide with the current filter applied.
* `player_name`: string param. * `player_name`: string param.
* `item`: optional, string param. If set, this item is pre-selected. If the item does not exist or has no recipe, use the player's previous selection. By default, player's previous selection is used * `item`: optional, string param. If set, this item is pre-selected. If the item does not exist or has no recipe, use the player's previous selection. By default, player's previous selection is used
* `show_usages`: optional, boolean param. If true, show item usages. * `show_usages`: optional, boolean param. If true, show item usages.
#### `craftguide.group_stereotypes`
This is the table indexing the item groups by stereotypes.
You can add a stereotype like so:
```Lua
craftguide.group_stereotypes.radioactive = "mod:item"
```

160
init.lua
View File

@ -13,6 +13,7 @@ local fuel_cache = {}
local progressive_mode = M.settings:get_bool("craftguide_progressive_mode") local progressive_mode = M.settings:get_bool("craftguide_progressive_mode")
local sfinv_only = M.settings:get_bool("craftguide_sfinv_only") and rawget(_G, "sfinv") local sfinv_only = M.settings:get_bool("craftguide_sfinv_only") and rawget(_G, "sfinv")
local after = M.after
local colorize = M.colorize local colorize = M.colorize
local reg_items = M.registered_items local reg_items = M.registered_items
local get_result = M.get_craft_result local get_result = M.get_craft_result
@ -47,13 +48,13 @@ local FMT = {
label = "label[%f,%f;%s]", label = "label[%f,%f;%s]",
image = "image[%f,%f;%f,%f;%s]", image = "image[%f,%f;%f,%f;%s]",
button = "button[%f,%f;%f,%f;%s;%s]", button = "button[%f,%f;%f,%f;%s;%s]",
tooltip = "tooltip[%s;%s]", tooltip = "tooltip[%f,%f;%f,%f;%s]",
item_image = "item_image[%f,%f;%f,%f;%s]", item_image = "item_image[%f,%f;%f,%f;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]", image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",
item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]", item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
} }
local group_stereotypes = { craftguide.group_stereotypes = {
wool = "wool:white", wool = "wool:white",
dye = "dye:white", dye = "dye:white",
water_bucket = "bucket:bucket_water", water_bucket = "bucket:bucket_water",
@ -119,23 +120,39 @@ local function __func()
return debug.getinfo(2, "n").name return debug.getinfo(2, "n").name
end end
local function is_str(x)
return type(x) == "string"
end
local function is_num(x)
return type(x) == "number"
end
local function is_table(x)
return type(x) == "table"
end
local function is_func(x)
return type(x) == "function"
end
local custom_crafts, craft_types = {}, {} local custom_crafts, craft_types = {}, {}
function craftguide.register_craft_type(name, def) function craftguide.register_craft_type(name, def)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "'name' field missing") assert(is_str(name), func .. "'name' field missing")
assert(def.description, func .. "'description' field missing") assert(is_str(def.description), func .. "'description' field missing")
assert(def.icon, func .. "'icon' field missing") assert(is_str(def.icon), func .. "'icon' field missing")
craft_types[name] = def craft_types[name] = def
end end
function craftguide.register_craft(def) function craftguide.register_craft(def)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(def.type, func .. "'type' field missing") assert(is_str(def.type), func .. "'type' field missing")
assert(def.width, func .. "'width' field missing") assert(is_num(def.width), func .. "'width' field missing")
assert(def.output, func .. "'output' field missing") assert(is_str(def.output), func .. "'output' field missing")
assert(def.items, func .. "'items' field missing") assert(is_table(def.items), func .. "'items' field missing")
custom_crafts[#custom_crafts + 1] = def custom_crafts[#custom_crafts + 1] = def
end end
@ -144,8 +161,8 @@ local recipe_filters = {}
function craftguide.add_recipe_filter(name, f) function craftguide.add_recipe_filter(name, f)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "filter name missing") assert(is_str(name), func .. "filter name missing")
assert(f and type(f) == "function", func .. "filter function missing") assert(is_func(f), func .. "filter function missing")
recipe_filters[name] = f recipe_filters[name] = f
end end
@ -156,8 +173,8 @@ end
function craftguide.set_recipe_filter(name, f) function craftguide.set_recipe_filter(name, f)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "filter name missing") assert(is_str(name), func .. "filter name missing")
assert(f and type(f) == "function", func .. "filter function missing") assert(is_func(f), func .. "filter function missing")
recipe_filters = {[name] = f} recipe_filters = {[name] = f}
end end
@ -178,8 +195,8 @@ local search_filters = {}
function craftguide.add_search_filter(name, f) function craftguide.add_search_filter(name, f)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "filter name missing") assert(is_str(name), func .. "filter name missing")
assert(f and type(f) == "function", func .. "filter function missing") assert(is_func(f), func .. "filter function missing")
search_filters[name] = f search_filters[name] = f
end end
@ -196,8 +213,9 @@ local formspec_elements = {}
function craftguide.add_formspec_element(name, def) function craftguide.add_formspec_element(name, def)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(def.element, func .. "'element' field not defined") assert(is_str(name), func .. "formspec element name missing")
assert(def.type, func .. "'type' field not defined") assert(is_str(def.element), func .. "'element' field not defined")
assert(is_str(def.type), func .. "'type' field not defined")
assert(FMT[def.type], func .. "'" .. def.type .. "' type not supported by the API") assert(FMT[def.type], func .. "'" .. def.type .. "' type not supported by the API")
formspec_elements[name] = { formspec_elements[name] = {
@ -240,6 +258,7 @@ end
local function groups_item_in_recipe(item, recipe) local function groups_item_in_recipe(item, recipe)
local item_groups = reg_items[item].groups local item_groups = reg_items[item].groups
for _, recipe_item in pairs(recipe.items) do for _, recipe_item in pairs(recipe.items) do
if sub(recipe_item, 1, 6) == "group:" then if sub(recipe_item, 1, 6) == "group:" then
local groups = extract_groups(recipe_item) local groups = extract_groups(recipe_item)
@ -355,9 +374,11 @@ local function groups_to_item(groups)
if #groups == 1 then if #groups == 1 then
local group = groups[1] local group = groups[1]
local def_gr = "default:" .. group local def_gr = "default:" .. group
local stereotypes = craftguide.group_stereotypes
local stereotype = stereotypes and stereotypes[group]
if group_stereotypes[group] then if stereotype then
return group_stereotypes[group] return stereotype
elseif reg_items[def_gr] then elseif reg_items[def_gr] then
return def_gr return def_gr
end end
@ -399,7 +420,7 @@ local function get_tooltip(item, groups, cooktime, burntime)
S("Burning time: @1", colorize("yellow", burntime)) S("Burning time: @1", colorize("yellow", burntime))
end end
return fmt(FMT.tooltip, item, ESC(tooltip)) return fmt("tooltip[%s;%s]", item, ESC(tooltip))
end end
local function get_recipe_fs(data, iY) local function get_recipe_fs(data, iY)
@ -413,7 +434,8 @@ local function get_recipe_fs(data, iY)
cooktime, width = width, 1 cooktime, width = width, 1
elseif width == 0 then elseif width == 0 then
shapeless = true shapeless = true
width = min(3, #recipe.items) local n = #recipe.items
width = n <= 4 and 2 or min(3, n)
end end
local rows = ceil(maxn(recipe.items) / width) local rows = ceil(maxn(recipe.items) / width)
@ -457,6 +479,7 @@ local function get_recipe_fs(data, iY)
end end
local groups local groups
if sub(item, 1, 6) == "group:" then if sub(item, 1, 6) == "group:" then
groups = extract_groups(item) groups = extract_groups(item)
item = groups_to_item(groups) item = groups_to_item(groups)
@ -699,24 +722,31 @@ local function search(data)
end end
local filtered_list, c = {}, 0 local filtered_list, c = {}, 0
local extras = "^(.-)%+([%w_]+)=([%w_,]+)"
local search_filter = next(search_filters) and match(filter, extras)
local filters = {}
if search_filter then
for filter_name, values in gmatch(filter, sub(extras, 6, -1)) do
if search_filters[filter_name] then
values = split(values, ",")
filters[filter_name] = values
end
end
end
for i = 1, #data.items_raw do for i = 1, #data.items_raw do
local item = data.items_raw[i] local item = data.items_raw[i]
local def = reg_items[item] local def = reg_items[item]
local desc = lower(def.description) local desc = lower(def.description)
local search_in = item .. desc local search_in = item .. desc
local pattern = "%+([%w_]+)=([%w_,]+)"
local to_add local to_add
if find(filter, pattern) then if search_filter then
local prepend = match(filter, "^(.-)%+") for filter_name, values in pairs(filters) do
for filter_name, values in gmatch(filter, pattern) do
local func = search_filters[filter_name] local func = search_filters[filter_name]
if func then to_add = func(item, values) and (search_filter == "" or
values = split(values, ",") find(search_in, search_filter, 1, true))
to_add = func(item, values) and (not prepend or
find(search_in, prepend, 1, true))
end
end end
else else
to_add = find(search_in, filter, 1, true) to_add = find(search_in, filter, 1, true)
@ -740,31 +770,6 @@ local function search(data)
data.items = filtered_list data.items = filtered_list
end end
local function get_inv_items(player)
local inv = player:get_inventory()
local stacks = {}
for i = 1, #item_lists do
local l = inv:get_list(item_lists[i])
stacks = table_merge(stacks, l)
end
local inv_items, c = {}, 0
for i = 1, #stacks do
local stack = stacks[i]
if not stack:is_empty() then
local name = stack:get_name()
if reg_items[name] then
c = c + 1
inv_items[c] = name
end
end
end
return inv_items
end
local function init_data(name) local function init_data(name)
player_data[name] = { player_data[name] = {
filter = "", filter = "",
@ -864,7 +869,6 @@ local function on_receive_fields(player, fields)
data.pagenum = 1 data.pagenum = 1
data.iX = data.iX + (fields.size_inc and 1 or -1) data.iX = data.iX + (fields.size_inc and 1 or -1)
show_fs(player, name) show_fs(player, name)
else else
local item local item
for field in pairs(fields) do for field in pairs(fields) do
@ -906,11 +910,6 @@ M.register_on_joinplayer(function(player)
init_data(name) init_data(name)
end) end)
M.register_on_leaveplayer(function(player)
local name = player:get_player_name()
player_data[name] = nil
end)
if sfinv_only then if sfinv_only then
sfinv.register_page("craftguide:craftguide", { sfinv.register_page("craftguide:craftguide", {
title = S("Craft Guide"), title = S("Craft Guide"),
@ -1085,6 +1084,31 @@ if progressive_mode then
return filtered return filtered
end end
local function get_inv_items(player)
local inv = player:get_inventory()
local stacks = {}
for i = 1, #item_lists do
local list = inv:get_list(item_lists[i])
table_merge(stacks, list)
end
local inv_items, c = {}, 0
for i = 1, #stacks do
local stack = stacks[i]
if not stack:is_empty() then
local name = stack:get_name()
if reg_items[name] then
c = c + 1
inv_items[c] = name
end
end
end
return inv_items
end
-- Workaround. Need an engine call to detect when the contents -- Workaround. Need an engine call to detect when the contents
-- of the player inventory changed, instead. -- of the player inventory changed, instead.
local function poll_new_items() local function poll_new_items()
@ -1101,7 +1125,7 @@ if progressive_mode then
end end
end end
M.after(POLL_FREQ, poll_new_items) after(POLL_FREQ, poll_new_items)
end end
poll_new_items() poll_new_items()
@ -1135,17 +1159,23 @@ if progressive_mode then
end) end)
end end
M.register_on_leaveplayer(function(player)
local name = player:get_player_name()
player_data[name] = nil
end)
M.register_chatcommand("craft", { M.register_chatcommand("craft", {
description = S("Show recipe(s) of the pointed node"), description = S("Show recipe(s) of the pointed node"),
func = function(name) func = function(name)
local player = get_player_by_name(name) local player = get_player_by_name(name)
local ppos = player:get_pos() local ppos = player:get_pos()
local dir = player:get_look_dir() local dir = player:get_look_dir()
local eye_h = {x = ppos.x, y = ppos.y + 1.625, z = ppos.z}
ppos.y = ppos.y + 1.625
local node_name local node_name
for i = 1, 10 do for i = 1, 10 do
local look_at = vec_add(eye_h, vec_mul(dir, i)) local look_at = vec_add(ppos, vec_mul(dir, i))
local node = M.get_node(look_at) local node = M.get_node(look_at)
if node.name ~= "air" then if node.name ~= "air" then
@ -1195,7 +1225,7 @@ M.register_chatcommand("craft", {
function craftguide.show(name, item, show_usages) function craftguide.show(name, item, show_usages)
local func = "craftguide." .. __func() .. "(): " local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "player name missing") assert(is_str(name), func .. "player name missing")
local data = player_data[name] local data = player_data[name]
local player = get_player_by_name(name) local player = get_player_by_name(name)

View File

@ -2,7 +2,7 @@
Craft Guide=книга рецептов крафта Craft Guide=книга рецептов крафта
Crafting Guide=книга рецептов крафта Crafting Guide=книга рецептов крафта
Crafting Guide Sign= Crafting Guide Sign=Знак с книгой рецептов
Search=Поиск Search=Поиск
Reset=Сброс Reset=Сброс
Previous page=Предыдущая страница Previous page=Предыдущая страница
@ -13,13 +13,13 @@ Burning time: @1=Время горения: @1
Cooking time: @1=Время преготовления: @1 Cooking time: @1=Время преготовления: @1
Any item belonging to the group(s): @1=Любой элемент из группы: @1 Any item belonging to the group(s): @1=Любой элемент из группы: @1
Recipe is too big to be displayed (@1x@2)=Рецепт слишком большой для показа (@1x@2) Recipe is too big to be displayed (@1x@2)=Рецепт слишком большой для показа (@1x@2)
Shapeless= Shapeless=Бесформенный
Cooking= Cooking=Приготовление
Increase window size=Увеличить окно Increase window size=Увеличить окно
Decrease window size=Уменьшить окно Decrease window size=Уменьшить окно
No item to show=Нет элемента для показа No item to show=Нет элемента для показа
Collect items to reveal more recipes= Collect items to reveal more recipes=Собирайте предметы, чтобы раскрыть больше рецептов
Show recipe(s) of the pointed node= Show recipe(s) of the pointed node=Показать рецепт(ы) выбранной ноды
No node pointed= No node pointed=Не указана нода
You don't know a recipe for this node= You don't know a recipe for this node=Вы не знаете рецепт для этой ноды
No recipe for this node= No recipe for this node=Нет рецептов для этой ноды