forked from your-land-mirror/minetest-flow
feat: Add set_as_inventory_for
API function (#2)
Adds the `Form:set_as_inventory_for(player, [ctx])` API. Also includes: • `Form:unset_as_inventory_for(player)` • Extends private `show_form` to account for inv edge cases • Extends private `on_fs_input` to account for inv edge cases • Adds several abstraction functions • Add feature to `on_leaveplayer` to delete the inv formspec state as well • Add a few unit tests for related features
This commit is contained in:
parent
45e61e34c9
commit
bba30cc267
35
README.md
35
README.md
@ -399,3 +399,38 @@ end)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Using a form as an inventory
|
||||
|
||||
A form can be set as the player inventory. Flow internally generates the
|
||||
formspec and passes it to `player:set_inventory_formspec()`. This will
|
||||
completely replace your inventory and isn't compatible with inventory mods like
|
||||
sfinv.
|
||||
|
||||
```lua
|
||||
local example_inventory = flow.make_gui(function (player, context)
|
||||
return gui.Label{ label = "Inventory goes here!" }
|
||||
end)
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
example_inventory:set_as_inventory_for(player)
|
||||
end)
|
||||
```
|
||||
|
||||
Like with the `show_hud` function, `update*` functions don't do anything, so to
|
||||
update it, call `set_as_inventory_for` again with the new context. If the
|
||||
context is not provided, it will reuse the existing context.
|
||||
|
||||
```lua
|
||||
example_inventory:set_as_inventory_for(player, new_context)
|
||||
```
|
||||
|
||||
While the form will of course be cleared when the player leaves, if you'd like
|
||||
to unset the inventory manually, call `:unset_as_inventory_for(player)`,
|
||||
analogue to `close_hud`:
|
||||
|
||||
```lua
|
||||
example_inventory:unset_as_inventory_for(player)
|
||||
```
|
||||
|
||||
This will set the inventory formspec string to `""` and stop flow from
|
||||
processing inventory formspec input.
|
||||
|
84
init.lua
84
init.lua
@ -720,10 +720,12 @@ function Form:_render(player, ctx, formspec_version, id1)
|
||||
"Changing the value of ctx.form is not supported!")
|
||||
ctx.form = orig_form
|
||||
|
||||
-- The numbering of automatically named elements is continued from previous
|
||||
-- iterations of the form to work around race conditions
|
||||
if not id1 or id1 > 1e6 then id1 = 0 end
|
||||
|
||||
local tree = render_ast(box)
|
||||
local callbacks, saved_fields, id2 = parse_callbacks(
|
||||
tree, orig_form, id1 or 0
|
||||
)
|
||||
local callbacks, saved_fields, id2 = parse_callbacks(tree, orig_form, id1)
|
||||
|
||||
local redraw_if_changed = {}
|
||||
for var in pairs(used_ctx_vars) do
|
||||
@ -744,8 +746,7 @@ function Form:_render(player, ctx, formspec_version, id1)
|
||||
}
|
||||
end
|
||||
|
||||
local open_formspecs = {}
|
||||
local function show_form(self, player, formname, ctx, auto_name_id)
|
||||
local function prepare_form(self, player, formname, ctx, auto_name_id)
|
||||
local name = player:get_player_name()
|
||||
-- local t = DEBUG_MODE and minetest.get_us_time()
|
||||
local info = minetest.get_player_information(name)
|
||||
@ -757,10 +758,19 @@ local function show_form(self, player, formname, ctx, auto_name_id)
|
||||
-- local t3 = DEBUG_MODE and minetest.get_us_time()
|
||||
|
||||
form_info.formname = formname
|
||||
open_formspecs[name] = form_info
|
||||
-- if DEBUG_MODE then
|
||||
-- print(t3 - t, t2 - t, t3 - t2)
|
||||
-- end
|
||||
return fs, form_info
|
||||
end
|
||||
|
||||
local open_formspecs = {}
|
||||
local function show_form(self, player, formname, ctx, auto_name_id)
|
||||
local name = player:get_player_name()
|
||||
local fs, form_info = prepare_form(self, player, formname, ctx,
|
||||
auto_name_id)
|
||||
|
||||
open_formspecs[name] = form_info
|
||||
minetest.show_formspec(name, formname, fs)
|
||||
end
|
||||
|
||||
@ -786,6 +796,22 @@ function Form:show_hud(player, ctx)
|
||||
hud_fs.show_hud(player, self, tree)
|
||||
end
|
||||
|
||||
local open_inv_formspecs = {}
|
||||
function Form:set_as_inventory_for(player, ctx)
|
||||
local name = player:get_player_name()
|
||||
local old_form_info = open_inv_formspecs[name]
|
||||
if not ctx and old_form_info and old_form_info.self == self then
|
||||
ctx = old_form_info.ctx
|
||||
end
|
||||
|
||||
-- Formname of "" is inventory
|
||||
local fs, form_info = prepare_form(self, player, "", ctx or {},
|
||||
old_form_info and old_form_info.auto_name_id)
|
||||
|
||||
open_inv_formspecs[name] = form_info
|
||||
player:set_inventory_formspec(fs)
|
||||
end
|
||||
|
||||
function Form:close(player)
|
||||
local name = player:get_player_name()
|
||||
local form_info = open_formspecs[name]
|
||||
@ -799,15 +825,20 @@ function Form:close_hud(player)
|
||||
hud_fs.close_hud(player, self)
|
||||
end
|
||||
|
||||
local function update_form(self, player, form_info)
|
||||
-- The numbering of automatically named elements is continued from previous
|
||||
-- iterations of the form to work around race conditions
|
||||
local auto_name_id
|
||||
if form_info.auto_name_id < 1e6 then
|
||||
auto_name_id = form_info.auto_name_id
|
||||
function Form:unset_as_inventory_for(player)
|
||||
local name = player:get_player_name()
|
||||
local form_info = open_inv_formspecs[name]
|
||||
if form_info and form_info.self == self then
|
||||
open_inv_formspecs[name] = nil
|
||||
player:set_inventory_formspec("")
|
||||
end
|
||||
end
|
||||
|
||||
show_form(self, player, form_info.formname, form_info.ctx, auto_name_id)
|
||||
-- This function may eventually call minetest.update_formspec if/when it gets
|
||||
-- added (https://github.com/minetest/minetest/issues/13142)
|
||||
local function update_form(self, player, form_info)
|
||||
show_form(self, player, form_info.formname, form_info.ctx,
|
||||
form_info.auto_name_id)
|
||||
end
|
||||
|
||||
function Form:update(player)
|
||||
@ -835,7 +866,8 @@ end
|
||||
|
||||
local function on_fs_input(player, formname, fields)
|
||||
local name = player:get_player_name()
|
||||
local form_info = open_formspecs[name]
|
||||
local form_infos = formname == "" and open_inv_formspecs or open_formspecs
|
||||
local form_info = form_infos[name]
|
||||
if not form_info or formname ~= form_info.formname then return end
|
||||
|
||||
local callbacks = form_info.callbacks
|
||||
@ -848,12 +880,13 @@ local function on_fs_input(player, formname, fields)
|
||||
for field, transformer in pairs(form_info.saved_fields) do
|
||||
if fields[field] then
|
||||
local new_value = transformer(fields[field])
|
||||
if redraw_if_changed[field] and ctx_form[field] ~= new_value then
|
||||
if DEBUG_MODE then
|
||||
print('Modified:', dump(field), dump(ctx_form[field]),
|
||||
'->', dump(new_value))
|
||||
if ctx_form[field] ~= new_value then
|
||||
if redraw_if_changed[field] then
|
||||
redraw_fs = true
|
||||
elseif formname == "" then
|
||||
-- Update the inventory when the player closes it next
|
||||
form_info.ctx_form_modified = true
|
||||
end
|
||||
redraw_fs = true
|
||||
end
|
||||
ctx_form[field] = new_value
|
||||
end
|
||||
@ -866,9 +899,14 @@ local function on_fs_input(player, formname, fields)
|
||||
end
|
||||
end
|
||||
|
||||
if open_formspecs[name] ~= form_info then return true end
|
||||
if form_infos[name] ~= form_info then return true end
|
||||
|
||||
if fields.quit then
|
||||
if formname == "" then
|
||||
-- Special case for inventory forms
|
||||
if redraw_fs or (fields.quit and form_info.ctx_form_modified) then
|
||||
form_info.self:set_as_inventory_for(player)
|
||||
end
|
||||
elseif fields.quit then
|
||||
open_formspecs[name] = nil
|
||||
elseif redraw_fs then
|
||||
update_form(form_info.self, player, form_info)
|
||||
@ -877,7 +915,9 @@ local function on_fs_input(player, formname, fields)
|
||||
end
|
||||
|
||||
local function on_leaveplayer(player)
|
||||
open_formspecs[player:get_player_name()] = nil
|
||||
local name = player:get_player_name()
|
||||
open_formspecs[name] = nil
|
||||
open_inv_formspecs[name] = nil
|
||||
end
|
||||
|
||||
if DEBUG_MODE then
|
||||
|
56
test.lua
56
test.lua
@ -22,6 +22,27 @@ local function dummy() end
|
||||
minetest.register_on_leaveplayer = dummy
|
||||
minetest.get_modpath = dummy
|
||||
minetest.is_singleplayer = dummy
|
||||
minetest.get_player_information = dummy
|
||||
minetest.show_formspec = dummy
|
||||
|
||||
-- Stub minetest player api
|
||||
local function stub_player(name)
|
||||
assert(type(name) == "string")
|
||||
local self = {}
|
||||
function self:get_player_name()
|
||||
return name
|
||||
end
|
||||
function self:get_inventory_formspec()
|
||||
return ""
|
||||
end
|
||||
function self:set_inventory_formspec(formspec)
|
||||
assert(formspec ~= nil)
|
||||
function self:get_inventory_formspec()
|
||||
return formspec
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
table.indexof = table.indexof or function(list, value)
|
||||
for i, item in ipairs(list) do
|
||||
@ -258,4 +279,39 @@ describe("Flow", function()
|
||||
style[test;prop=value]
|
||||
]])
|
||||
end)
|
||||
|
||||
it("registers inventory formspecs", function ()
|
||||
local stupid_simple_inv_expected =
|
||||
"formspec_version[5]" ..
|
||||
"size[10.35,5.35]" ..
|
||||
"list[current_player;main;0.3,0.3;8,4]"
|
||||
local stupid_simple_inv = flow.make_gui(function (p, c)
|
||||
return gui.List{
|
||||
inventory_location = "current_player",
|
||||
list_name = "main",
|
||||
w = 8,
|
||||
h = 4,
|
||||
}
|
||||
end)
|
||||
local player = stub_player("test_player")
|
||||
assert(player:get_inventory_formspec() == "")
|
||||
stupid_simple_inv:set_as_inventory_for(player)
|
||||
assert(player:get_inventory_formspec() == stupid_simple_inv_expected)
|
||||
end)
|
||||
|
||||
it("can still show a form when an inventory formspec is shown", function ()
|
||||
local expected_one = "formspec_version[5]size[1.6,1.6]box[0.3,0.3;1,1;]"
|
||||
local one = flow.make_gui(function (p, c)
|
||||
return gui.Box{ w = 1, h = 1 }
|
||||
end)
|
||||
local blue = flow.make_gui(function (p, c)
|
||||
return gui.Box{ w = 1, h = 4, color = "blue" }
|
||||
end)
|
||||
local player = stub_player("test_player")
|
||||
assert(player:get_inventory_formspec() == "")
|
||||
one:set_as_inventory_for(player)
|
||||
assert(player:get_inventory_formspec() == expected_one)
|
||||
blue:show(player)
|
||||
assert(player:get_inventory_formspec() == expected_one)
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user