Compare commits

...

12 Commits
1.6 ... 1.7

12 changed files with 253 additions and 270 deletions

13
API.md
View File

@ -73,10 +73,6 @@ end)
Removes the recipe filter with the given name. Removes the recipe filter with the given name.
#### `craftguide.set_recipe_filter(name, function(recipe, player))`
Removes all recipe filters and adds a new one.
#### `craftguide.get_recipe_filters()` #### `craftguide.get_recipe_filters()`
Returns a map of recipe filters, indexed by name. Returns a map of recipe filters, indexed by name.
@ -155,3 +151,12 @@ You can add a stereotype like so:
```Lua ```Lua
craftguide.group_stereotypes.radioactive = "mod:item" craftguide.group_stereotypes.radioactive = "mod:item"
``` ```
#### `craftguide.background`
You can set a custom background theme by overriding this variable:
```Lua
craftguide.background = "my_custom_bg.png"
```

View File

@ -17,5 +17,4 @@ Use the command `/craft` to show the recipe(s) of the pointed node.
For developers, `craftguide` also has a [modding API](https://github.com/minetest-mods/craftguide/blob/master/API.md). For developers, `craftguide` also has a [modding API](https://github.com/minetest-mods/craftguide/blob/master/API.md).
![Preview2](https://i.imgur.com/bToFH38.png) ![Preview2](https://i.imgur.com/oGSvbTW.png)

View File

@ -1,2 +0,0 @@
sfinv?
sfinv_buttons?

503
init.lua
View File

@ -1,6 +1,9 @@
craftguide = {} craftguide = {}
craftguide.background = "craftguide_bg_full.png"
local pdata = {} local pdata = {}
local core = core
-- Caches -- Caches
local init_items = {} local init_items = {}
@ -12,21 +15,29 @@ local fuel_cache = {}
local progressive_mode = core.settings:get_bool("craftguide_progressive_mode") local progressive_mode = core.settings:get_bool("craftguide_progressive_mode")
local sfinv_only = core.settings:get_bool("craftguide_sfinv_only") and rawget(_G, "sfinv") local sfinv_only = core.settings:get_bool("craftguide_sfinv_only") and rawget(_G, "sfinv")
local log = core.log
local after = core.after local after = core.after
local colorize = core.colorize local colorize = core.colorize
local reg_items = core.registered_items local reg_items = core.registered_items
local get_result = core.get_craft_result
local get_players = core.get_connected_players
local show_formspec = core.show_formspec local show_formspec = core.show_formspec
local globalstep = core.register_globalstep
local on_shutdown = core.register_on_shutdown
local get_craft_result = core.get_craft_result
local get_players = core.get_connected_players
local on_joinplayer = core.register_on_joinplayer
local register_command = core.register_chatcommand
local get_all_recipes = core.get_all_craft_recipes local get_all_recipes = core.get_all_craft_recipes
local get_player_by_name = core.get_player_by_name local get_player_by_name = core.get_player_by_name
local on_mods_loaded = core.register_on_mods_loaded
local on_leaveplayer = core.register_on_leaveplayer
local serialize, deserialize = core.serialize, core.deserialize local serialize, deserialize = core.serialize, core.deserialize
local on_receive_fields = core.register_on_player_receive_fields
local ESC = core.formspec_escape local ESC = core.formspec_escape
local S = core.get_translator("craftguide") local S = core.get_translator("craftguide")
local maxn, sort, concat, copy = local maxn, sort, concat, copy, insert =
table.maxn, table.sort, table.concat, table.copy table.maxn, table.sort, table.concat, table.copy, table.insert
local fmt, find, gmatch, match, sub, split, upper, lower = local fmt, find, gmatch, match, sub, split, upper, lower =
string.format, string.find, string.gmatch, string.match, string.format, string.find, string.gmatch, string.match,
@ -36,11 +47,10 @@ local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil
local pairs, next = pairs, next local pairs, next = pairs, next
local vec_add, vec_mul = vector.add, vector.multiply local vec_add, vec_mul = vector.add, vector.multiply
local DEFAULT_SIZE = 10 local ROWS = sfinv_only and 9 or 11
local MIN_LIMIT, MAX_LIMIT = 10, 12 local LINES = 5
DEFAULT_SIZE = min(MAX_LIMIT, max(MIN_LIMIT, DEFAULT_SIZE)) local IPP = ROWS * LINES
local GRID_LIMIT = 8
local GRID_LIMIT = 5
local FMT = { local FMT = {
box = "box[%f,%f;%f,%f;%s]", box = "box[%f,%f;%f,%f;%s]",
@ -63,24 +73,6 @@ craftguide.group_stereotypes = {
mesecon_conductor_craftable = "mesecons:wire_00000000_off", mesecon_conductor_craftable = "mesecons:wire_00000000_off",
} }
local item_lists = {
"main",
"craft",
"craftpreview",
}
local function table_merge(t, t2)
t, t2 = t or {}, t2 or {}
local c = #t
for i = 1, #t2 do
c = c + 1
t[c] = t2[i]
end
return t
end
local function table_replace(t, val, new) local function table_replace(t, val, new)
for k, v in pairs(t) do for k, v in pairs(t) do
if v == val then if v == val then
@ -89,36 +81,6 @@ local function table_replace(t, val, new)
end end
end end
local function table_diff(t, t2)
local hash = {}
for i = 1, #t do
local v = t[i]
hash[v] = true
end
for i = 1, #t2 do
local v = t2[i]
hash[v] = nil
end
local diff, c = {}, 0
for i = 1, #t do
local v = t[i]
if hash[v] then
c = c + 1
diff[c] = v
end
end
return diff
end
local function __func()
return debug.getinfo(2, "n").name
end
local function is_str(x) local function is_str(x)
return type(x) == "string" return type(x) == "string"
end end
@ -135,24 +97,35 @@ local function is_func(x)
return type(x) == "function" return type(x) == "function"
end end
local custom_crafts, craft_types = {}, {} local craft_types = {}
function craftguide.register_craft_type(name, def) function craftguide.register_craft_type(name, def)
local func = "craftguide." .. __func() .. "(): " if not is_str(name) or name == "" then
assert(is_str(name), func .. "'name' field missing") return log("error", "craftguide.register_craft_type(): name missing")
assert(is_str(def.description), func .. "'description' field missing") end
assert(is_str(def.icon), func .. "'icon' field missing")
if not is_str(def.description) then
def.description = ""
end
if not is_str(def.icon) then
def.icon = ""
end
craft_types[name] = def craft_types[name] = def
end end
function craftguide.register_craft(def) function craftguide.register_craft(def)
if not is_table(def) or not next(def) then
return log("error", "craftguide.register_craft(): craft definition missing")
end
if def.result then if def.result then
def.output = def.result -- Backward compatibility def.output = def.result -- Backward compatibility
end end
if not is_str(def.output) then if not is_str(def.output) or def.output == "" then
def.output = "" return log("error", "craftguide.register_craft(): output missing")
end end
if not is_table(def.items) then if not is_table(def.items) then
@ -188,15 +161,19 @@ function craftguide.register_craft(def)
end end
end end
custom_crafts[#custom_crafts + 1] = def local output = match(def.output, "%S*")
recipes_cache[output] = recipes_cache[output] or {}
insert(recipes_cache[output], def)
end end
local recipe_filters = {} local recipe_filters = {}
function craftguide.add_recipe_filter(name, f) function craftguide.add_recipe_filter(name, f)
local func = "craftguide." .. __func() .. "(): " if not is_str(name) or name == "" then
assert(is_str(name), func .. "filter name missing") return log("error", "craftguide.add_recipe_filter(): name missing")
assert(is_func(f), func .. "filter function missing") elseif not is_func(f) then
return log("error", "craftguide.add_recipe_filter(): function missing")
end
recipe_filters[name] = f recipe_filters[name] = f
end end
@ -205,14 +182,6 @@ function craftguide.remove_recipe_filter(name)
recipe_filters[name] = nil recipe_filters[name] = nil
end end
function craftguide.set_recipe_filter(name, f)
local func = "craftguide." .. __func() .. "(): "
assert(is_str(name), func .. "filter name missing")
assert(is_func(f), func .. "filter function missing")
recipe_filters = {[name] = f}
end
function craftguide.get_recipe_filters() function craftguide.get_recipe_filters()
return recipe_filters return recipe_filters
end end
@ -228,9 +197,11 @@ end
local search_filters = {} local search_filters = {}
function craftguide.add_search_filter(name, f) function craftguide.add_search_filter(name, f)
local func = "craftguide." .. __func() .. "(): " if not is_str(name) or name == "" then
assert(is_str(name), func .. "filter name missing") return log("error", "craftguide.add_search_filter(): name missing")
assert(is_func(f), func .. "filter function missing") elseif not is_func(f) then
return log("error", "craftguide.add_search_filter(): function missing")
end
search_filters[name] = f search_filters[name] = f
end end
@ -246,9 +217,7 @@ end
local function item_has_groups(item_groups, groups) local function item_has_groups(item_groups, groups)
for i = 1, #groups do for i = 1, #groups do
local group = groups[i] local group = groups[i]
if (item_groups[group] or 0) == 0 then if (item_groups[group] or 0) == 0 then return end
return
end
end end
return true return true
@ -270,7 +239,7 @@ 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)
if item_has_groups(item_groups, groups) then if item_has_groups(item_groups, groups) then
local usage = copy(recipe) local usage = copy(recipe)
@ -338,17 +307,17 @@ end
local function cache_recipes(output) local function cache_recipes(output)
local recipes = get_all_recipes(output) or {} local recipes = get_all_recipes(output) or {}
local num = #recipes
for i = 1, #custom_crafts do if num > 0 then
local custom_craft = custom_crafts[i] if recipes_cache[output] then
if match(custom_craft.output, "%S*") == output then for i = 1, num do
recipes[#recipes + 1] = custom_craft insert(recipes_cache[output], 1, recipes[i])
end
else
recipes_cache[output] = recipes
end end
end end
if #recipes > 0 then
recipes_cache[output] = recipes
end
end end
local function cache_usages(item) local function cache_usages(item)
@ -375,16 +344,14 @@ local function get_recipes(item, data, player)
if data.show_usages then if data.show_usages then
recipes = apply_recipe_filters(usages_cache[item], player) recipes = apply_recipe_filters(usages_cache[item], player)
if recipes and #recipes == 0 then if recipes and #recipes == 0 then return end
return
end
end end
return recipes return recipes
end end
local function get_burntime(item) local function get_burntime(item)
return get_result({method = "fuel", width = 1, items = {item}}).time return get_craft_result({method = "fuel", width = 1, items = {item}}).time
end end
local function cache_fuel(item) local function cache_fuel(item)
@ -452,11 +419,12 @@ local function get_tooltip(item, groups, cooktime, burntime)
return fmt("tooltip[%s;%s]", 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)
local fs = {} local fs = {}
local recipe = data.recipes[data.rnum] local recipe = data.recipes[data.rnum]
local width = recipe.width local width = recipe.width
local xoffset = data.iX / 2.15 local xoffset = sfinv_only and 3.83 or 4.66
local yoffset = sfinv_only and 6 or 6.6
local cooktime, shapeless local cooktime, shapeless
if recipe.type == "cooking" then if recipe.type == "cooking" then
@ -475,32 +443,36 @@ local function get_recipe_fs(data, iY)
ESC(S("Recipe @1 of @2", data.rnum, #data.recipes)) ESC(S("Recipe @1 of @2", data.rnum, #data.recipes))
fs[#fs + 1] = fmt(FMT.button, fs[#fs + 1] = fmt(FMT.button,
sfinv_only and 5.8 or data.iX - 2.6, xoffset + (sfinv_only and 1.98 or 2.7),
sfinv_only and 7.9 or iY + 3.3, yoffset + (sfinv_only and 1.9 or 1.2),
2.2, 2.2, 1, "alternate", btn_lab)
1,
"alternate",
btn_lab)
if width > GRID_LIMIT or rows > GRID_LIMIT then if width > GRID_LIMIT or rows > GRID_LIMIT then
fs[#fs + 1] = fmt(FMT.label, fs[#fs + 1] = fmt(FMT.label,
(data.iX / 2) - 2, sfinv_only and 2 or 3, 7,
iY + 2.2,
ESC(S("Recipe is too big to be displayed (@1x@2)", width, rows))) ESC(S("Recipe is too big to be displayed (@1x@2)", width, rows)))
return concat(fs) return concat(fs)
end end
for i, item in pairs(recipe.items) do for i = 1, width * rows do
local X = ceil((i - 1) % width + xoffset - width) - local item = recipe.items[i] or ""
(sfinv_only and 0 or 0.2) local X = ceil((i - 1) % width - width) + xoffset
local Y = ceil(i / width + (iY + 2) - min(2, rows)) local Y = ceil(i / width) + yoffset - min(2, rows)
if width > 3 or rows > 3 then if width > 3 or rows > 3 then
btn_size = width > 3 and 3 / width or 3 / rows local xof = 1 - 4 / width
local yof = 1 - 4 / rows
local x_y = width > rows and xof or yof
btn_size = width > rows and
(3.5 + (xof * 2)) / width or (3.5 + (yof * 2)) / rows
s_btn_size = btn_size s_btn_size = btn_size
X = btn_size * ((i - 1) % width) + xoffset - 2.65
Y = btn_size * floor((i - 1) / width) + (iY + 3) - min(2, rows) X = (btn_size * ((i - 1) % width) + xoffset -
(sfinv_only and 2.83 or (xoffset - 2))) * (0.83 - (x_y / 5))
Y = (btn_size * floor((i - 1) / width) +
(5 + ((sfinv_only and 0.81 or 1.5) + x_y))) * (0.86 - (x_y / 5))
end end
if X > rightest then if X > rightest then
@ -517,13 +489,8 @@ local function get_recipe_fs(data, iY)
local label = groups and "\nG" or "" local label = groups and "\nG" or ""
fs[#fs + 1] = fmt(FMT.item_image_button, fs[#fs + 1] = fmt(FMT.item_image_button,
X, X, Y + (sfinv_only and 0.7 or 0),
Y + (sfinv_only and 0.7 or 0.2), btn_size, btn_size, item, match(item, "%S*"), ESC(label))
btn_size,
btn_size,
item,
match(item, "%S*"),
ESC(label))
local burntime = fuel_cache[item] local burntime = fuel_cache[item]
@ -542,70 +509,47 @@ local function get_recipe_fs(data, iY)
icon = fmt("craftguide_%s.png^[resize:16x16", icon) icon = fmt("craftguide_%s.png^[resize:16x16", icon)
end end
local pos_y = yoffset + (sfinv_only and 0.25 or -0.45)
fs[#fs + 1] = fmt(FMT.image, fs[#fs + 1] = fmt(FMT.image,
min(3.9, rightest) + 1.2, min(3.9, rightest) + 1.2, pos_y, 0.5, 0.5, icon)
sfinv_only and 6.2 or iY + 1.7,
0.5,
0.5,
icon)
local tooltip = custom_recipe and custom_recipe.description or local tooltip = custom_recipe and custom_recipe.description or
shapeless and S("Shapeless") or S("Cooking") shapeless and S("Shapeless") or S("Cooking")
fs[#fs + 1] = fmt("tooltip[%f,%f;%f,%f;%s]", fs[#fs + 1] = fmt("tooltip[%f,%f;%f,%f;%s]",
rightest + 1.2, rightest + 1.2, pos_y, 0.5, 0.5, ESC(tooltip))
sfinv_only and 6.2 or iY + 1.7,
0.5,
0.5,
ESC(tooltip))
end end
local arrow_X = rightest + (s_btn_size or 1.1) local arrow_X = rightest + (s_btn_size or 1.1)
local output_X = arrow_X + 0.9 local output_X = arrow_X + 0.9
fs[#fs + 1] = fmt(FMT.image, fs[#fs + 1] = fmt(FMT.image,
arrow_X, arrow_X, yoffset + (sfinv_only and 0.9 or 0.2),
sfinv_only and 6.85 or iY + 2.35, 0.9, 0.7, "craftguide_arrow.png")
0.9,
0.7,
"craftguide_arrow.png")
if recipe.type == "fuel" then if recipe.type == "fuel" then
fs[#fs + 1] = fmt(FMT.image, fs[#fs + 1] = fmt(FMT.image,
output_X, output_X, yoffset + (sfinv_only and 0.7 or 0),
sfinv_only and 6.68 or iY + 2.18, 1.1, 1.1, "craftguide_fire.png")
1.1,
1.1,
"craftguide_fire.png")
else else
local output_name = match(recipe.output, "%S+") local output_name = match(recipe.output, "%S+")
local burntime = fuel_cache[output_name] local burntime = fuel_cache[output_name]
fs[#fs + 1] = fmt(FMT.item_image_button, fs[#fs + 1] = fmt(FMT.item_image_button,
output_X, output_X, yoffset + (sfinv_only and 0.7 or 0),
sfinv_only and 6.7 or iY + 2.2, 1.1, 1.1, recipe.output, ESC(output_name), "")
1.1,
1.1,
recipe.output,
ESC(output_name),
"")
if burntime then if burntime then
fs[#fs + 1] = get_tooltip(output_name, nil, nil, burntime) fs[#fs + 1] = get_tooltip(output_name, nil, nil, burntime)
fs[#fs + 1] = fmt(FMT.image, fs[#fs + 1] = fmt(FMT.image,
output_X + 1, output_X + 1, yoffset + (sfinv_only and 0.7 or 0.1),
sfinv_only and 6.83 or iY + 2.33, 0.6, 0.4, "craftguide_arrow.png")
0.6,
0.4,
"craftguide_arrow.png")
fs[#fs + 1] = fmt(FMT.image, fs[#fs + 1] = fmt(FMT.image,
output_X + 1.6, output_X + 1.6, yoffset + (sfinv_only and 0.55 or 0),
sfinv_only and 6.68 or iY + 2.18, 0.6, 0.6, "craftguide_fire.png")
0.6,
0.6,
"craftguide_fire.png")
end end
end end
@ -614,53 +558,53 @@ end
local function make_formspec(name) local function make_formspec(name)
local data = pdata[name] local data = pdata[name]
local iY = sfinv_only and 4 or data.iX - 5 data.pagemax = max(1, ceil(#data.items / IPP))
local ipp = data.iX * iY
data.pagemax = max(1, ceil(#data.items / ipp))
local fs = {} local fs = {}
if not sfinv_only then if not sfinv_only then
fs[#fs + 1] = fmt("size[%f,%f;]", data.iX - 0.35, iY + 4)
fs[#fs + 1] = [[
no_prepend[]
background[1,1;1,1;craftguide_bg.png;true]
]]
fs[#fs + 1] = fmt([[ fs[#fs + 1] = fmt([[
image_button[%f,0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;] size[%f,%f;]
image_button[%f,0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;] no_prepend[]
]], bgcolor[#00000000;false]
data.iX * 0.47, background[1,1;1,1;%s;true;10]
data.iX * 0.47 + 0.6) ]],
9.5, 8.4, craftguide.background)
end end
fs[#fs + 1] = fmt("field[0.3,0.33;2.5,1;filter;;%s]", ESC(data.filter)) fs[#fs + 1] = fmt([[
field[0.25,0.2;%f,1;filter;;%s]
fs[#fs + 1] = [[
image_button[2.4,0.12;0.8,0.8;craftguide_search_icon.png;search;]
image_button[3.05,0.12;0.8,0.8;craftguide_clear_icon.png;clear;]
field_close_on_enter[filter;false] field_close_on_enter[filter;false]
]] ]],
sfinv_only and 2.76 or 2.72, ESC(data.filter))
fs[#fs + 1] = fmt("label[%f,%f;%s / %u]", local search_icon = "craftguide_search_icon.png"
sfinv_only and 6.3 or data.iX - 2.2, local clear_icon = "craftguide_clear_icon.png"
0.22,
colorize("yellow", data.pagenum),
data.pagemax)
fs[#fs + 1] = fmt([[ fs[#fs + 1] = fmt([[
image_button[%f,0.12;0.8,0.8;craftguide_prev_icon.png;prev;] image_button[%f,-0.05;0.85,0.85;%s;search;;;false;%s^\[colorize:yellow:255]
image_button[%f,0.12;0.8,0.8;craftguide_next_icon.png;next;] image_button[%f,-0.05;0.85,0.85;%s;clear;;;false;%s^\[colorize:red:255]
]], ]],
sfinv_only and 5.5 or data.iX - 3.1, sfinv_only and 2.6 or 2.54, search_icon, search_icon,
sfinv_only and 7.3 or (data.iX - 1.2) - (data.iX >= 11 and 0.08 or 0)) sfinv_only and 3.3 or 3.25, clear_icon, clear_icon)
fs[#fs + 1] = fmt("label[%f,%f;%s / %u]",
sfinv_only and 6.35 or 7.85, 0.06,
colorize("yellow", data.pagenum), data.pagemax)
local prev_icon = "craftguide_next_icon.png^\\[transformFX"
local next_icon = "craftguide_next_icon.png"
fs[#fs + 1] = fmt([[
image_button[%f,-0.05;0.8,0.8;%s;prev;;;false;%s^\[colorize:yellow:255]
image_button[%f,-0.05;0.8,0.8;%s;next;;;false;%s^\[colorize:yellow:255]
]],
sfinv_only and 5.45 or 6.83, prev_icon, prev_icon,
sfinv_only and 7.2 or 8.75, next_icon, next_icon)
if #data.items == 0 then if #data.items == 0 then
local no_item = S("No item to show") local no_item = S("No item to show")
local pos = (data.iX / 2) - 1 local pos = sfinv_only and 3 or 3.8
if next(recipe_filters) and #init_items > 0 and data.filter == "" then if next(recipe_filters) and #init_items > 0 and data.filter == "" then
no_item = S("Collect items to reveal more recipes") no_item = S("Collect items to reveal more recipes")
@ -670,27 +614,22 @@ local function make_formspec(name)
fs[#fs + 1] = fmt(FMT.label, pos, 2, ESC(no_item)) fs[#fs + 1] = fmt(FMT.label, pos, 2, ESC(no_item))
end end
local first_item = (data.pagenum - 1) * ipp local first_item = (data.pagenum - 1) * IPP
for i = first_item, first_item + ipp - 1 do for i = first_item, first_item + IPP - 1 do
local item = data.items[i + 1] local item = data.items[i + 1]
if not item then if not item then break end
break
end
local X = i % data.iX local X = i % ROWS
local Y = (i % ipp - X) / data.iX + 1 local Y = (i % IPP - X) / ROWS + 1
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s_inv;]", fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s_inv;]",
X - (sfinv_only and 0 or (X * 0.05)), X - (X * (sfinv_only and 0.12 or 0.14)) - 0.05,
Y, Y - (Y * 0.1) - 0.1,
1.1, 1, 1, item, item)
1.1,
item,
item)
end end
if data.recipes and #data.recipes > 0 then if data.recipes and #data.recipes > 0 then
fs[#fs + 1] = get_recipe_fs(data, iY) fs[#fs + 1] = get_recipe_fs(data)
end end
return concat(fs) return concat(fs)
@ -781,7 +720,6 @@ local function init_data(name)
pdata[name] = { pdata[name] = {
filter = "", filter = "",
pagenum = 1, pagenum = 1,
iX = sfinv_only and 8 or DEFAULT_SIZE,
items = init_items, items = init_items,
items_raw = init_items, items_raw = init_items,
} }
@ -831,41 +769,38 @@ local function get_init_items()
sort(init_items) sort(init_items)
end end
local function on_receive_fields(player, fields) local function _fields(player, fields)
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
local _f = fields
if fields.clear then if _f.clear then
reset_data(data) reset_data(data)
show_fs(player, name) show_fs(player, name)
return true
elseif fields.alternate then elseif _f.alternate then
if #data.recipes == 1 then if #data.recipes == 1 then return end
return
end
local num_next = data.rnum + 1 local num_next = data.rnum + 1
data.rnum = data.recipes[num_next] and num_next or 1 data.rnum = data.recipes[num_next] and num_next or 1
show_fs(player, name)
elseif (fields.key_enter_field == "filter" or fields.search) and show_fs(player, name)
fields.filter ~= "" then return true
local fltr = lower(fields.filter)
if data.filter == fltr then elseif (_f.key_enter_field == "filter" or _f.search) and _f.filter ~= "" then
return local fltr = lower(_f.filter)
end if data.filter == fltr then return end
data.filter = fltr data.filter = fltr
data.pagenum = 1 data.pagenum = 1
search(data) search(data)
show_fs(player, name) show_fs(player, name)
return true
elseif fields.prev or fields.next then elseif _f.prev or _f.next then
if data.pagemax == 1 then if data.pagemax == 1 then return end
return data.pagenum = data.pagenum - (_f.prev and 1 or -1)
end
data.pagenum = data.pagenum - (fields.prev and 1 or -1)
if data.pagenum > data.pagemax then if data.pagenum > data.pagemax then
data.pagenum = 1 data.pagenum = 1
@ -874,15 +809,10 @@ local function on_receive_fields(player, fields)
end end
show_fs(player, name) show_fs(player, name)
return true
elseif (fields.size_inc and data.iX < MAX_LIMIT) or
(fields.size_dec and data.iX > MIN_LIMIT) then
data.pagenum = 1
data.iX = data.iX + (fields.size_inc and 1 or -1)
show_fs(player, name)
else else
local item local item
for field in pairs(fields) do for field in pairs(_f) do
if find(field, ":") then if find(field, ":") then
item = field item = field
break break
@ -892,7 +822,7 @@ local function on_receive_fields(player, fields)
if not item then if not item then
return return
elseif sub(item, -4) == "_inv" then elseif sub(item, -4) == "_inv" then
item = sub(item, 1, -5) item = sub(item, 1,-5)
end end
if item ~= data.query_item then if item ~= data.query_item then
@ -902,21 +832,20 @@ local function on_receive_fields(player, fields)
end end
local recipes = get_recipes(item, data, player) local recipes = get_recipes(item, data, player)
if not recipes then if not recipes then return end
return
end
data.query_item = item data.query_item = item
data.recipes = recipes data.recipes = recipes
data.rnum = 1 data.rnum = 1
show_fs(player, name) show_fs(player, name)
return true
end end
end end
core.register_on_mods_loaded(get_init_items) on_mods_loaded(get_init_items)
core.register_on_joinplayer(function(player) on_joinplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
init_data(name) init_data(name)
end) end)
@ -943,13 +872,13 @@ if sfinv_only then
end, end,
on_player_receive_fields = function(self, player, context, fields) on_player_receive_fields = function(self, player, context, fields)
on_receive_fields(player, fields) _fields(player, fields)
end, end,
}) })
else else
core.register_on_player_receive_fields(function(player, formname, fields) on_receive_fields(function(player, formname, fields)
if formname == "craftguide" then if formname == "craftguide" then
on_receive_fields(player, fields) _fields(player, fields)
end end
end) end)
@ -980,17 +909,17 @@ else
description = S("Crafting Guide Sign"), description = S("Crafting Guide Sign"),
drawtype = "nodebox", drawtype = "nodebox",
tiles = {"craftguide_sign.png"}, tiles = {"craftguide_sign.png"},
inventory_image = "craftguide_sign_inv.png", inventory_image = "craftguide_sign.png",
wield_image = "craftguide_sign_inv.png", wield_image = "craftguide_sign.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
sunlight_propagates = true, sunlight_propagates = true,
groups = {oddly_breakable_by_hand = 1, flammable = 3}, groups = {oddly_breakable_by_hand = 1, flammable = 3},
node_box = { node_box = {
type = "wallmounted", type = "wallmounted",
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125}, wall_top = {-0.5, 0.4375, -0.5, 0.5, 0.5, 0.5},
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125}, wall_bottom = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375} wall_side = {-0.5, -0.5, -0.5, -0.4375, 0.5, 0.5}
}, },
on_construct = function(pos) on_construct = function(pos)
@ -1048,7 +977,7 @@ if progressive_mode then
local function item_in_inv(item, inv_items) local function item_in_inv(item, inv_items)
local inv_items_size = #inv_items local inv_items_size = #inv_items
if sub(item, 1, 6) == "group:" then if sub(item, 1,6) == "group:" then
local groups = extract_groups(item) local groups = extract_groups(item)
for i = 1, inv_items_size do for i = 1, inv_items_size do
local inv_item = reg_items[inv_items[i]] local inv_item = reg_items[inv_items[i]]
@ -1070,9 +999,7 @@ if progressive_mode then
local function recipe_in_inv(recipe, inv_items) local function recipe_in_inv(recipe, inv_items)
for _, item in pairs(recipe.items) do for _, item in pairs(recipe.items) do
if not item_in_inv(item, inv_items) then if not item_in_inv(item, inv_items) then return end
return
end
end end
return true return true
@ -1102,6 +1029,50 @@ if progressive_mode then
return filtered return filtered
end end
local item_lists = {
"main",
"craft",
"craftpreview",
}
local function table_merge(t, t2)
t, t2 = t or {}, t2 or {}
local c = #t
for i = 1, #t2 do
c = c + 1
t[c] = t2[i]
end
return t
end
local function table_diff(t, t2)
local hash = {}
for i = 1, #t do
local v = t[i]
hash[v] = true
end
for i = 1, #t2 do
local v = t2[i]
hash[v] = nil
end
local diff, c = {}, 0
for i = 1, #t do
local v = t[i]
if hash[v] then
c = c + 1
diff[c] = v
end
end
return diff
end
local function get_inv_items(player) local function get_inv_items(player)
local inv = player:get_inventory() local inv = player:get_inventory()
local stacks = {} local stacks = {}
@ -1196,7 +1167,7 @@ if progressive_mode then
poll_new_items() poll_new_items()
minetest.register_globalstep(function(dtime) globalstep(function(dtime)
for i = 1, #PLAYERS do for i = 1, #PLAYERS do
local player = PLAYERS[i] local player = PLAYERS[i]
local name = player:get_player_name() local name = player:get_player_name()
@ -1210,7 +1181,7 @@ if progressive_mode then
craftguide.add_recipe_filter("Default progressive filter", progressive_filter) craftguide.add_recipe_filter("Default progressive filter", progressive_filter)
core.register_on_joinplayer(function(player) on_joinplayer(function(player)
PLAYERS = get_players() PLAYERS = get_players()
local meta = player:get_meta() local meta = player:get_meta()
@ -1223,15 +1194,15 @@ if progressive_mode then
data.hud = { data.hud = {
bg = player:hud_add({ bg = player:hud_add({
hud_elem_type = "image", hud_elem_type = "image",
position = {x = 0.8, y = 1}, position = {x = 0.78, y = 1},
alignment = {x = 1, y = 1}, alignment = {x = 1, y = 1},
scale = {x = 320, y = 112}, scale = {x = 370, y = 112},
text = "craftguide_bg.png", text = "craftguide_bg.png",
}), }),
book = player:hud_add({ book = player:hud_add({
hud_elem_type = "image", hud_elem_type = "image",
position = {x = 0.81, y = 1.02}, position = {x = 0.79, y = 1.02},
alignment = {x = 1, y = 1}, alignment = {x = 1, y = 1},
scale = {x = 4, y = 4}, scale = {x = 4, y = 4},
text = "craftguide_book.png", text = "craftguide_book.png",
@ -1239,7 +1210,7 @@ if progressive_mode then
text = player:hud_add({ text = player:hud_add({
hud_elem_type = "text", hud_elem_type = "text",
position = {x = 0.85, y = 1.04}, position = {x = 0.84, y = 1.04},
alignment = {x = 1, y = 1}, alignment = {x = 1, y = 1},
number = 0xFFFFFF, number = 0xFFFFFF,
text = "", text = "",
@ -1247,21 +1218,28 @@ if progressive_mode then
} }
end) end)
local to_save = {
"inv_items",
"known_recipes",
}
local function save_meta(player) local function save_meta(player)
local meta = player:get_meta() local meta = player:get_meta()
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
meta:set_string("inv_items", serialize(data.inv_items)) for i = 1, #to_save do
meta:set_string("known_recipes", serialize(data.known_recipes)) local meta_name = to_save[i]
meta:set_string(meta_name, serialize(data[meta_name]))
end
end end
core.register_on_leaveplayer(function(player) on_leaveplayer(function(player)
PLAYERS = get_players() PLAYERS = get_players()
save_meta(player) save_meta(player)
end) end)
core.register_on_shutdown(function() on_shutdown(function()
for i = 1, #PLAYERS do for i = 1, #PLAYERS do
local player = PLAYERS[i] local player = PLAYERS[i]
save_meta(player) save_meta(player)
@ -1269,12 +1247,12 @@ if progressive_mode then
end) end)
end end
core.register_on_leaveplayer(function(player) on_leaveplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
pdata[name] = nil pdata[name] = nil
end) end)
core.register_chatcommand("craft", { register_command("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)
@ -1334,8 +1312,9 @@ core.register_chatcommand("craft", {
}) })
function craftguide.show(name, item, show_usages) function craftguide.show(name, item, show_usages)
local func = "craftguide." .. __func() .. "(): " if not is_str(name) or name == "" then
assert(is_str(name), func .. "player name missing") return log("error", "craftguide.show(): player name missing")
end
local data = pdata[name] local data = pdata[name]
local player = get_player_by_name(name) local player = get_player_by_name(name)

View File

@ -1 +1,3 @@
name = craftguide name = craftguide
optional_depends = sfinv, sfinv_buttons
description = The most comprehensive Crafting Guide on Minetest

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB