mirror of
https://github.com/minetest-mods/craftguide.git
synced 2024-11-22 19:03:43 +01:00
Progressive mode: Remember discovered recipes
This commit is contained in:
parent
e6268a395f
commit
c1b1bef263
10
README.md
10
README.md
@ -6,10 +6,10 @@
|
|||||||
This crafting guide is a blue book named *"Crafting Guide"* or a wooden sign.
|
This crafting guide is a blue book named *"Crafting Guide"* or a wooden sign.
|
||||||
|
|
||||||
This crafting guide features a **progressive mode**.
|
This crafting guide features a **progressive mode**.
|
||||||
The progressive mode is a Terraria-like system that only shows recipes you can craft from items in inventory.
|
The progressive mode is a Terraria-like system that only shows recipes you can craft
|
||||||
The progressive mode can be enabled with `craftguide_progressive_mode = true` in `minetest.conf`.
|
from items you ever had in your inventory. To enable it: `craftguide_progressive_mode = true` in `minetest.conf`.
|
||||||
|
|
||||||
`craftguide` is also integrated in `sfinv` (Minetest Game inventory) when you enable it with
|
`craftguide` is also integrated in `sfinv` (Minetest Game inventory). To enable it:
|
||||||
`craftguide_sfinv_only = true` in `minetest.conf`.
|
`craftguide_sfinv_only = true` in `minetest.conf`.
|
||||||
|
|
||||||
Use the command `/craft` to show the recipe(s) of the pointed node.
|
Use the command `/craft` to show the recipe(s) of the pointed node.
|
||||||
@ -49,6 +49,10 @@ craftguide.register_craft({
|
|||||||
This function adds a recipe filter when progressive mode is enabled.
|
This function adds a recipe filter when progressive mode is enabled.
|
||||||
The default `craftguide` filter will still be used.
|
The default `craftguide` filter will still be used.
|
||||||
|
|
||||||
|
The function should return the recipes to be displayed, given the available
|
||||||
|
recipes and an `ObjectRef` to the user. Each recipe is a table of the form
|
||||||
|
returned by `minetest.get_craft_recipe`.
|
||||||
|
|
||||||
Example function to hide recipes for items from a mod called "secretstuff":
|
Example function to hide recipes for items from a mod called "secretstuff":
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
173
init.lua
173
init.lua
@ -16,6 +16,7 @@ local sfinv_only = mt.settings:get_bool("craftguide_sfinv_only")
|
|||||||
local reg_items = mt.registered_items
|
local reg_items = mt.registered_items
|
||||||
local get_result = mt.get_craft_result
|
local get_result = mt.get_craft_result
|
||||||
local show_formspec = mt.show_formspec
|
local show_formspec = mt.show_formspec
|
||||||
|
local serialize, deserialize = mt.serialize, mt.deserialize
|
||||||
|
|
||||||
-- Intllib
|
-- Intllib
|
||||||
local S = dofile(mt.get_modpath("craftguide") .. "/intllib.lua")
|
local S = dofile(mt.get_modpath("craftguide") .. "/intllib.lua")
|
||||||
@ -47,6 +48,28 @@ local group_stereotypes = {
|
|||||||
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function table_merge(t, t2)
|
||||||
|
for i = 1, #t2 do
|
||||||
|
t[#t + 1] = t2[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function table_clean(t)
|
||||||
|
local hash, ct = {}, {}
|
||||||
|
for i = 1, #t do
|
||||||
|
local v = t[i]
|
||||||
|
if not hash[v] then
|
||||||
|
ct[#ct + 1] = v
|
||||||
|
hash[v] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sort(ct)
|
||||||
|
return ct
|
||||||
|
end
|
||||||
|
|
||||||
local function __func()
|
local function __func()
|
||||||
return debug.getinfo(2, "n").name
|
return debug.getinfo(2, "n").name
|
||||||
end
|
end
|
||||||
@ -328,8 +351,8 @@ local function get_recipe_fs(data, iY)
|
|||||||
return concat(fs)
|
return concat(fs)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function make_formspec(player_name)
|
local function make_formspec(name)
|
||||||
local data = player_data[player_name]
|
local data = player_data[name]
|
||||||
local iY = sfinv_only and 4 or data.iX - 5
|
local iY = sfinv_only and 4 or data.iX - 5
|
||||||
local ipp = data.iX * iY
|
local ipp = data.iX * iY
|
||||||
|
|
||||||
@ -376,8 +399,8 @@ local function make_formspec(player_name)
|
|||||||
|
|
||||||
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 name = data.items[i + 1]
|
local item = data.items[i + 1]
|
||||||
if not name then
|
if not item then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -389,8 +412,8 @@ local function make_formspec(player_name)
|
|||||||
Y,
|
Y,
|
||||||
1.1,
|
1.1,
|
||||||
1.1,
|
1.1,
|
||||||
name,
|
item,
|
||||||
name)
|
item)
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.recipes and #data.recipes > 0 then
|
if data.recipes and #data.recipes > 0 then
|
||||||
@ -400,13 +423,13 @@ local function make_formspec(player_name)
|
|||||||
return concat(fs)
|
return concat(fs)
|
||||||
end
|
end
|
||||||
|
|
||||||
local show_fs = function(player, player_name)
|
local show_fs = function(player, name)
|
||||||
if sfinv_only then
|
if sfinv_only then
|
||||||
sfinv.set_player_inventory_formspec(player)
|
sfinv.set_player_inventory_formspec(player)
|
||||||
else
|
else
|
||||||
local data = player_data[player_name]
|
local data = player_data[name]
|
||||||
data.formspec = make_formspec(player_name)
|
data.formspec = make_formspec(name)
|
||||||
show_formspec(player_name, "craftguide", data.formspec)
|
show_formspec(name, "craftguide", data.formspec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -417,7 +440,7 @@ local function filter_items(data)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local items_list = progressive_mode and data.progressive_items or init_items
|
local items_list = progressive_mode and data.p_items or init_items
|
||||||
local filtered_list, c = {}, 0
|
local filtered_list, c = {}, 0
|
||||||
|
|
||||||
for i = 1, #items_list do
|
for i = 1, #items_list do
|
||||||
@ -478,17 +501,14 @@ local function get_inv_items(player)
|
|||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
local stacks = inv:get_list("main")
|
local stacks = inv:get_list("main")
|
||||||
local craftlist = inv:get_list("craft")
|
local craftlist = inv:get_list("craft")
|
||||||
|
stacks = table_merge(stacks, craftlist)
|
||||||
for i = 1, #craftlist do
|
|
||||||
stacks[#stacks + 1] = craftlist[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
local inv_items = {}
|
local inv_items = {}
|
||||||
for i = 1, #stacks do
|
for i = 1, #stacks do
|
||||||
local stack = stacks[i]
|
local stack = stacks[i]
|
||||||
if not stack:is_empty() then
|
if not stack:is_empty() then
|
||||||
local name = stack:get_name()
|
local name = stack:get_name()
|
||||||
if not inv_items[name] and reg_items[name] then
|
if reg_items[name] then
|
||||||
inv_items[#inv_items + 1] = name
|
inv_items[#inv_items + 1] = name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -498,16 +518,17 @@ local function get_inv_items(player)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function item_in_inv(item, inv_items)
|
local function item_in_inv(item, inv_items)
|
||||||
|
local inv_items_size = #inv_items
|
||||||
if item:sub(1,6) == "group:" then
|
if item:sub(1,6) == "group:" then
|
||||||
local groups = extract_groups(item)
|
local groups = extract_groups(item)
|
||||||
for i = 1, #inv_items do
|
for i = 1, inv_items_size do
|
||||||
local item_groups = reg_items[inv_items[i]].groups
|
local item_groups = reg_items[inv_items[i]].groups
|
||||||
if item_has_groups(item_groups, groups) then
|
if item_has_groups(item_groups, groups) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for i = 1, #inv_items do
|
for i = 1, inv_items_size do
|
||||||
if inv_items[i] == item then
|
if inv_items[i] == item then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -516,15 +537,25 @@ local function item_in_inv(item, inv_items)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function progressive_default_filter(recipes, player)
|
local function progressive_default_filter(recipes, player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
local data = player_data[name]
|
||||||
local inv_items = get_inv_items(player)
|
local inv_items = get_inv_items(player)
|
||||||
|
|
||||||
|
if data.inv_items then
|
||||||
|
inv_items = table_merge(data.inv_items, inv_items)
|
||||||
|
end
|
||||||
|
|
||||||
if #inv_items == 0 then
|
if #inv_items == 0 then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
data.inv_items = inv_items
|
||||||
|
|
||||||
local filtered = {}
|
local filtered = {}
|
||||||
for i = 1, #recipes do
|
for i = 1, #recipes do
|
||||||
local recipe = recipes[i]
|
local recipe = recipes[i]
|
||||||
local recipe_in_inv = true
|
local recipe_in_inv = true
|
||||||
|
|
||||||
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
|
||||||
recipe_in_inv = false
|
recipe_in_inv = false
|
||||||
@ -571,8 +602,10 @@ local function apply_progressive_filters(recipes, player)
|
|||||||
return recipes
|
return recipes
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_progressive_items(player)
|
local function get_progressive_items(player, name)
|
||||||
local items = {}
|
local data = player_data[name]
|
||||||
|
local items = data and data.p_items or {}
|
||||||
|
|
||||||
for i = 1, #init_items do
|
for i = 1, #init_items do
|
||||||
local item = init_items[i]
|
local item = init_items[i]
|
||||||
local recipes = recipes_cache[item]
|
local recipes = recipes_cache[item]
|
||||||
@ -585,18 +618,35 @@ local function get_progressive_items(player)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
items = table_clean(items)
|
||||||
return items
|
return items
|
||||||
end
|
end
|
||||||
|
|
||||||
local function init_data(player, name)
|
local function init_data(player, name)
|
||||||
local p_items = progressive_mode and get_progressive_items(player) or nil
|
|
||||||
player_data[name] = {
|
player_data[name] = {
|
||||||
filter = "",
|
filter = "",
|
||||||
pagenum = 1,
|
pagenum = 1,
|
||||||
iX = sfinv_only and 8 or DEFAULT_SIZE,
|
iX = sfinv_only and 8 or DEFAULT_SIZE,
|
||||||
items = p_items or init_items,
|
|
||||||
progressive_items = p_items,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local p_items
|
||||||
|
if progressive_mode then
|
||||||
|
local meta = player:get_meta()
|
||||||
|
player_data[name].inv_items = deserialize(meta:get_string("inv_items"))
|
||||||
|
p_items = get_progressive_items(player, name)
|
||||||
|
|
||||||
|
if p_items then
|
||||||
|
local old_items = deserialize(meta:get_string("p_items"))
|
||||||
|
if old_items then
|
||||||
|
p_items = table_merge(p_items, old_items)
|
||||||
|
p_items = table_clean(p_items)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player_data[name].p_items = p_items
|
||||||
|
end
|
||||||
|
|
||||||
|
player_data[name].items = p_items or init_items
|
||||||
end
|
end
|
||||||
|
|
||||||
local function reset_data(data)
|
local function reset_data(data)
|
||||||
@ -605,7 +655,7 @@ local function reset_data(data)
|
|||||||
data.query_item = nil
|
data.query_item = nil
|
||||||
data.show_usages = nil
|
data.show_usages = nil
|
||||||
data.recipes = nil
|
data.recipes = nil
|
||||||
data.items = progressive_mode and data.progressive_items or init_items
|
data.items = progressive_mode and data.p_items or init_items
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_init_items()
|
local function get_init_items()
|
||||||
@ -624,15 +674,13 @@ local function get_init_items()
|
|||||||
sort(init_items)
|
sort(init_items)
|
||||||
end
|
end
|
||||||
|
|
||||||
mt.register_on_mods_loaded(get_init_items)
|
|
||||||
|
|
||||||
local function on_receive_fields(player, fields)
|
local function on_receive_fields(player, fields)
|
||||||
local player_name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local data = player_data[player_name]
|
local data = player_data[name]
|
||||||
|
|
||||||
if fields.clear then
|
if fields.clear then
|
||||||
reset_data(data)
|
reset_data(data)
|
||||||
show_fs(player, player_name)
|
show_fs(player, name)
|
||||||
|
|
||||||
elseif fields.alternate then
|
elseif fields.alternate then
|
||||||
if #data.recipes == 1 then
|
if #data.recipes == 1 then
|
||||||
@ -641,7 +689,7 @@ local function on_receive_fields(player, fields)
|
|||||||
|
|
||||||
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, player_name)
|
show_fs(player, name)
|
||||||
|
|
||||||
elseif (fields.key_enter_field == "filter" or fields.search) and
|
elseif (fields.key_enter_field == "filter" or fields.search) and
|
||||||
fields.filter ~= "" then
|
fields.filter ~= "" then
|
||||||
@ -653,7 +701,7 @@ local function on_receive_fields(player, fields)
|
|||||||
data.filter = fltr
|
data.filter = fltr
|
||||||
data.pagenum = 1
|
data.pagenum = 1
|
||||||
filter_items(data)
|
filter_items(data)
|
||||||
show_fs(player, player_name)
|
show_fs(player, name)
|
||||||
|
|
||||||
elseif fields.prev or fields.next then
|
elseif fields.prev or fields.next then
|
||||||
if data.pagemax == 1 then
|
if data.pagemax == 1 then
|
||||||
@ -667,13 +715,13 @@ local function on_receive_fields(player, fields)
|
|||||||
data.pagenum = data.pagemax
|
data.pagenum = data.pagemax
|
||||||
end
|
end
|
||||||
|
|
||||||
show_fs(player, player_name)
|
show_fs(player, name)
|
||||||
|
|
||||||
elseif (fields.size_inc and data.iX < MAX_LIMIT) or
|
elseif (fields.size_inc and data.iX < MAX_LIMIT) or
|
||||||
(fields.size_dec and data.iX > MIN_LIMIT) then
|
(fields.size_dec and data.iX > MIN_LIMIT) then
|
||||||
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, player_name)
|
show_fs(player, name)
|
||||||
|
|
||||||
else
|
else
|
||||||
local item
|
local item
|
||||||
@ -728,7 +776,7 @@ local function on_receive_fields(player, fields)
|
|||||||
data.recipes = recipes
|
data.recipes = recipes
|
||||||
data.rnum = 1
|
data.rnum = 1
|
||||||
|
|
||||||
show_fs(player, player_name)
|
show_fs(player, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -737,18 +785,20 @@ if sfinv_only then
|
|||||||
title = "Craft Guide",
|
title = "Craft Guide",
|
||||||
|
|
||||||
get = function(self, player, context)
|
get = function(self, player, context)
|
||||||
local formspec = make_formspec(player:get_player_name())
|
local name = player:get_player_name()
|
||||||
|
local formspec = make_formspec(name)
|
||||||
|
|
||||||
return sfinv.make_formspec(player, context, formspec)
|
return sfinv.make_formspec(player, context, formspec)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_enter = function(self, player, context)
|
on_enter = function(self, player, context)
|
||||||
local player_name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local data = player_data[player_name]
|
local data = player_data[name]
|
||||||
|
|
||||||
if not data then
|
if not data then
|
||||||
init_data(player, player_name)
|
init_data(player, name)
|
||||||
elseif progressive_mode then
|
elseif progressive_mode then
|
||||||
data.progressive_items = get_progressive_items(player)
|
data.p_items = get_progressive_items(player, name)
|
||||||
filter_items(data)
|
filter_items(data)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@ -765,20 +815,20 @@ else
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
local function on_use(user)
|
local function on_use(user)
|
||||||
local player_name = user:get_player_name()
|
local name = user:get_player_name()
|
||||||
local data = player_data[player_name]
|
local data = player_data[name]
|
||||||
|
|
||||||
if not data then
|
if not data then
|
||||||
init_data(user, player_name)
|
init_data(user, name)
|
||||||
data = player_data[player_name]
|
data = player_data[name]
|
||||||
data.formspec = make_formspec(player_name)
|
data.formspec = make_formspec(name)
|
||||||
elseif progressive_mode then
|
elseif progressive_mode then
|
||||||
data.progressive_items = get_progressive_items(user)
|
data.p_items = get_progressive_items(user, name)
|
||||||
filter_items(data)
|
filter_items(data)
|
||||||
data.formspec = make_formspec(player_name)
|
data.formspec = make_formspec(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
show_formspec(player_name, "craftguide", data.formspec)
|
show_formspec(name, "craftguide", data.formspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
mt.register_craftitem("craftguide:book", {
|
mt.register_craftitem("craftguide:book", {
|
||||||
@ -911,13 +961,36 @@ if not progressive_mode then
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
mt.register_on_mods_loaded(get_init_items)
|
||||||
|
|
||||||
|
local function save_meta(player, data)
|
||||||
|
local meta = player:get_meta()
|
||||||
|
meta:set_string("p_items", serialize(data.p_items))
|
||||||
|
meta:set_string("inv_items", serialize(data.inv_items))
|
||||||
|
end
|
||||||
|
|
||||||
mt.register_on_leaveplayer(function(player)
|
mt.register_on_leaveplayer(function(player)
|
||||||
if player then
|
local name = player:get_player_name()
|
||||||
local name = player:get_player_name()
|
if progressive_mode then
|
||||||
player_data[name] = nil
|
save_meta(player, player_data[name])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
player_data[name] = nil
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
if progressive_mode then
|
||||||
|
mt.register_on_shutdown(function()
|
||||||
|
local players = mt.get_connected_players()
|
||||||
|
for i = 1, #players do
|
||||||
|
local player = players[i]
|
||||||
|
if player then
|
||||||
|
local name = player:get_player_name()
|
||||||
|
save_meta(player, player_data[name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
--[[ Custom recipes (>3x3) test code
|
--[[ Custom recipes (>3x3) test code
|
||||||
|
|
||||||
mt.register_craftitem(":secretstuff:custom_recipe_test", {
|
mt.register_craftitem(":secretstuff:custom_recipe_test", {
|
||||||
|
Loading…
Reference in New Issue
Block a user