Separate recipe filters and progressive mode

This commit is contained in:
Paul Ouellette 2019-02-01 17:10:41 -05:00
parent 5625a0cb1c
commit a0ef0809fe
2 changed files with 128 additions and 148 deletions

View File

@ -42,21 +42,22 @@ craftguide.register_craft({
})
```
### Progressive mode
### Recipe filters
#### `craftguide.add_progressive_filter(name, function(recipes, player))`
Recipe filters can be used to filter the recipes shown to players. Progressive
mode is implemented as a recipe filter.
This function adds a recipe filter when progressive mode is enabled.
The default `craftguide` filter will still be used.
#### `craftguide.add_recipe_filter(name, function(recipes, player))`
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`.
Adds a recipe filter with the given name. The filter 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":
```lua
craftguide.add_progressive_filter("Hide secretstuff", function(recipes)
craftguide.add_recipe_filter("Hide secretstuff", function(recipes)
local filtered = {}
for _, recipe in ipairs(recipes) do
if recipe.output:sub(1,12) ~= "secretstuff:" then
@ -68,11 +69,14 @@ craftguide.add_progressive_filter("Hide secretstuff", function(recipes)
end)
```
#### `craftguide.set_progressive_filter(name, function(recipes, player))`
#### `craftguide.remove_recipe_filter(name)`
This function sets an unique recipe filter when progressive mode is enabled.
The default `craftguide` progressive filter will be overridden.
Removes the recipe filter with the given name.
#### `craftguide.get_progressive_filters()`
#### `craftguide.remove_all_filters()`
This function returns all progressive filters that are applied to recipes in progressive mode.
Removes all recipe filters.
#### `craftguide.get_recipe_filters()`
Returns a map of recipe filters, indexed by name.

246
init.lua
View File

@ -107,6 +107,51 @@ craftguide.register_craft({
items = {"default:stone"},
})
local recipe_filters = {}
function craftguide.add_recipe_filter(name, func)
recipe_filters[#recipe_filters + 1] = {name = name, func = func}
end
function craftguide.remove_recipe_filter(name)
recipe_filters[name] = nil
end
function craftguide.remove_all_filters()
recipe_filters = {}
end
function craftguide.get_recipe_filters()
return recipe_filters
end
local function apply_recipe_filters(recipes, player)
for i = 1, #recipe_filters do
local func = recipe_filters[i].func
recipes = func(recipes, player)
end
return recipes
end
local function get_filtered_items(player)
local items = {}
for i = 1, #init_items do
local item = init_items[i]
local recipes = recipes_cache[item]
if recipes then
recipes = apply_recipe_filters(recipes, player)
if #recipes > 0 then
items[#items + 1] = item
end
end
end
return items
end
local function cache_recipes(output)
local recipes = mt.get_all_craft_recipes(output) or {}
for i = 1, #craftguide.custom_crafts do
@ -427,24 +472,21 @@ local show_fs = function(player, name)
if sfinv_only then
sfinv.set_player_inventory_formspec(player)
else
local data = player_data[name]
data.formspec = make_formspec(name)
show_formspec(name, "craftguide", data.formspec)
show_formspec(name, "craftguide", make_formspec(name))
end
end
local function filter_items(data)
local function exec_search(data)
local filter = data.filter
if searches[filter] then
data.items = searches[filter]
return
end
local items_list = progressive_mode and data.p_items or init_items
local filtered_list, c = {}, 0
for i = 1, #items_list do
local item = items_list[i]
for i = 1, #data.items_unsearched do
local item = data.items_unsearched[i]
local item_desc = reg_items[item].description:lower()
if item:find(filter, 1, true) or item_desc:find(filter, 1, true) then
@ -453,7 +495,7 @@ local function filter_items(data)
end
end
if not progressive_mode then
if #recipe_filters == 0 then
-- Cache the results only if searched 2 times
if searches[filter] == nil then
searches[filter] = false
@ -499,9 +541,7 @@ end
local function get_inv_items(player)
local inv = player:get_inventory()
local stacks = inv:get_list("main")
local craftlist = inv:get_list("craft")
stacks = table_merge(stacks, craftlist)
local stacks = table_merge(inv:get_list("main"), inv:get_list("craft"))
local inv_items = {}
for i = 1, #stacks do
@ -536,104 +576,14 @@ local function item_in_inv(item, inv_items)
end
end
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)
if data.inv_items then
inv_items = table_merge(data.inv_items, inv_items)
end
if #inv_items == 0 then
return {}
end
data.inv_items = inv_items
local filtered = {}
for i = 1, #recipes do
local recipe = recipes[i]
local recipe_in_inv = true
for _, item in pairs(recipe.items) do
if not item_in_inv(item, inv_items) then
recipe_in_inv = false
end
end
if recipe_in_inv then
filtered[#filtered + 1] = recipe
end
end
return filtered
end
local progressive_filters = {{
name = "Default filter",
func = progressive_default_filter,
}}
function craftguide.add_progressive_filter(name, func)
progressive_filters[#progressive_filters + 1] = {
name = name,
func = func,
}
end
function craftguide.set_progressive_filter(name, func)
progressive_filters = {{
name = name,
func = func,
}}
end
function craftguide.get_progressive_filters()
return progressive_filters
end
local function apply_progressive_filters(recipes, player)
for i = 1, #progressive_filters do
local func = progressive_filters[i].func
recipes = func(recipes, player)
end
return recipes
end
local function get_progressive_items(player, name)
local data = player_data[name]
local items = data and data.p_items or {}
for i = 1, #init_items do
local item = init_items[i]
local recipes = recipes_cache[item]
if recipes then
recipes = apply_progressive_filters(recipes, player)
if #recipes > 0 then
items[#items + 1] = item
end
end
end
items = table_clean(items)
return items
end
local function init_data(player, name)
player_data[name] = {
filter = "",
pagenum = 1,
iX = sfinv_only and 8 or DEFAULT_SIZE,
items = init_items,
items_unsearched = init_items,
}
if progressive_mode then
local meta = player:get_meta()
player_data[name].inv_items = deserialize(meta:get_string("inv_items"))
end
end
local function reset_data(data)
@ -642,7 +592,7 @@ local function reset_data(data)
data.query_item = nil
data.show_usages = nil
data.recipes = nil
data.items = progressive_mode and data.p_items or init_items
data.items = data.items_unsearched
end
local function get_init_items()
@ -681,13 +631,13 @@ local function on_receive_fields(player, fields)
elseif (fields.key_enter_field == "filter" or fields.search) and
fields.filter ~= "" then
local fltr = fields.filter:lower()
if not progressive_mode and data.filter == fltr then
if data.filter == fltr then
return
end
data.filter = fltr
data.pagenum = 1
filter_items(data)
exec_search(data)
show_fs(player, name)
elseif fields.prev or fields.next then
@ -728,8 +678,8 @@ local function on_receive_fields(player, fields)
local is_fuel = fuel_cache[item]
local recipes = recipes_cache[item]
if progressive_mode and recipes then
recipes = apply_progressive_filters(recipes, player)
if recipes then
recipes = apply_recipe_filters(recipes, player)
end
local no_recipes = not recipes or #recipes == 0
@ -748,11 +698,7 @@ local function on_receive_fields(player, fields)
end
if data.show_usages then
recipes = get_item_usages(item)
if progressive_mode then
recipes = apply_progressive_filters(recipes, player)
end
recipes = apply_recipe_filters(get_item_usages(item), player)
if #recipes == 0 then
return
@ -782,9 +728,9 @@ if sfinv_only then
local name = player:get_player_name()
local data = player_data[name]
if progressive_mode then
data.p_items = get_progressive_items(player, name)
filter_items(data)
if #recipe_filters > 0 then
data.items_unsearched = get_filtered_items(player)
exec_search(data)
end
end,
@ -803,13 +749,12 @@ else
local name = user:get_player_name()
local data = player_data[name]
if progressive_mode then
data.p_items = get_progressive_items(user, name)
filter_items(data)
if #recipe_filters > 0 then
data.items_unsearched = get_filtered_items(user)
exec_search(data)
end
data.formspec = make_formspec(name)
show_formspec(name, "craftguide", data.formspec)
show_formspec(name, "craftguide", make_formspec(name))
end
mt.register_craftitem("craftguide:book", {
@ -886,7 +831,7 @@ else
end
end
if not progressive_mode then
if #recipe_filters == 0 then
mt.register_chatcommand("craft", {
description = S("Show recipe(s) of the pointed node"),
func = function(name)
@ -947,29 +892,60 @@ mt.register_on_joinplayer(function(player)
init_data(player, name)
end)
local function save_meta(player, data)
local meta = player:get_meta()
meta:set_string("inv_items", serialize(data.inv_items))
end
mt.register_on_leaveplayer(function(player)
local name = player:get_player_name()
if progressive_mode then
save_meta(player, player_data[name])
end
player_data[name] = nil
end)
if progressive_mode then
craftguide.add_recipe_filter("Progressive filter", function(recipes, player)
local name = player:get_player_name()
local discovered = player_data[name].inv_items
local inv_items = get_inv_items(player)
discovered = table_clean(table_merge(discovered, inv_items))
if #discovered == 0 then
return {}
end
local filtered = {}
for i = 1, #recipes do
local recipe = recipes[i]
local recipe_in_inv = true
for _, item in pairs(recipe.items) do
if not item_in_inv(item, discovered) then
recipe_in_inv = false
end
end
if recipe_in_inv then
filtered[#filtered + 1] = recipe
end
end
return filtered
end)
mt.register_on_joinplayer(function(player)
local meta = player:get_meta()
local inv_items = deserialize(meta:get_string("inv_items")) or {}
local name = player:get_player_name()
player_data[name].inv_items = inv_items
end)
local function save_meta(player)
local meta = player:get_meta()
local name = player:get_player_name()
meta:set_string("inv_items", serialize(player_data[name].inv_items))
end
mt.register_on_leaveplayer(save_meta)
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
save_meta(players[i])
end
end)
end