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

View File

@ -1 +1,3 @@
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