mirror of
https://gitlab.com/luk3yx/minetest-flow.git
synced 2025-09-21 14:16:30 +02:00
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!")
|
"Changing the value of ctx.form is not supported!")
|
||||||
ctx.form = orig_form
|
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 tree = render_ast(box)
|
||||||
local callbacks, saved_fields, id2 = parse_callbacks(
|
local callbacks, saved_fields, id2 = parse_callbacks(tree, orig_form, id1)
|
||||||
tree, orig_form, id1 or 0
|
|
||||||
)
|
|
||||||
|
|
||||||
local redraw_if_changed = {}
|
local redraw_if_changed = {}
|
||||||
for var in pairs(used_ctx_vars) do
|
for var in pairs(used_ctx_vars) do
|
||||||
@ -744,8 +746,7 @@ function Form:_render(player, ctx, formspec_version, id1)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local open_formspecs = {}
|
local function prepare_form(self, player, formname, ctx, auto_name_id)
|
||||||
local function show_form(self, player, formname, ctx, auto_name_id)
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
-- local t = DEBUG_MODE and minetest.get_us_time()
|
-- local t = DEBUG_MODE and minetest.get_us_time()
|
||||||
local info = minetest.get_player_information(name)
|
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()
|
-- local t3 = DEBUG_MODE and minetest.get_us_time()
|
||||||
|
|
||||||
form_info.formname = formname
|
form_info.formname = formname
|
||||||
open_formspecs[name] = form_info
|
|
||||||
-- if DEBUG_MODE then
|
-- if DEBUG_MODE then
|
||||||
-- print(t3 - t, t2 - t, t3 - t2)
|
-- print(t3 - t, t2 - t, t3 - t2)
|
||||||
-- end
|
-- 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)
|
minetest.show_formspec(name, formname, fs)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -786,6 +796,22 @@ function Form:show_hud(player, ctx)
|
|||||||
hud_fs.show_hud(player, self, tree)
|
hud_fs.show_hud(player, self, tree)
|
||||||
end
|
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)
|
function Form:close(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local form_info = open_formspecs[name]
|
local form_info = open_formspecs[name]
|
||||||
@ -799,15 +825,20 @@ function Form:close_hud(player)
|
|||||||
hud_fs.close_hud(player, self)
|
hud_fs.close_hud(player, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_form(self, player, form_info)
|
function Form:unset_as_inventory_for(player)
|
||||||
-- The numbering of automatically named elements is continued from previous
|
local name = player:get_player_name()
|
||||||
-- iterations of the form to work around race conditions
|
local form_info = open_inv_formspecs[name]
|
||||||
local auto_name_id
|
if form_info and form_info.self == self then
|
||||||
if form_info.auto_name_id < 1e6 then
|
open_inv_formspecs[name] = nil
|
||||||
auto_name_id = form_info.auto_name_id
|
player:set_inventory_formspec("")
|
||||||
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
function Form:update(player)
|
function Form:update(player)
|
||||||
@ -835,7 +866,8 @@ end
|
|||||||
|
|
||||||
local function on_fs_input(player, formname, fields)
|
local function on_fs_input(player, formname, fields)
|
||||||
local name = player:get_player_name()
|
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
|
if not form_info or formname ~= form_info.formname then return end
|
||||||
|
|
||||||
local callbacks = form_info.callbacks
|
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
|
for field, transformer in pairs(form_info.saved_fields) do
|
||||||
if fields[field] then
|
if fields[field] then
|
||||||
local new_value = transformer(fields[field])
|
local new_value = transformer(fields[field])
|
||||||
if redraw_if_changed[field] and ctx_form[field] ~= new_value then
|
if ctx_form[field] ~= new_value then
|
||||||
if DEBUG_MODE then
|
if redraw_if_changed[field] then
|
||||||
print('Modified:', dump(field), dump(ctx_form[field]),
|
|
||||||
'->', dump(new_value))
|
|
||||||
end
|
|
||||||
redraw_fs = true
|
redraw_fs = true
|
||||||
|
elseif formname == "" then
|
||||||
|
-- Update the inventory when the player closes it next
|
||||||
|
form_info.ctx_form_modified = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
ctx_form[field] = new_value
|
ctx_form[field] = new_value
|
||||||
end
|
end
|
||||||
@ -866,9 +899,14 @@ local function on_fs_input(player, formname, fields)
|
|||||||
end
|
end
|
||||||
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
|
open_formspecs[name] = nil
|
||||||
elseif redraw_fs then
|
elseif redraw_fs then
|
||||||
update_form(form_info.self, player, form_info)
|
update_form(form_info.self, player, form_info)
|
||||||
@ -877,7 +915,9 @@ local function on_fs_input(player, formname, fields)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function on_leaveplayer(player)
|
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
|
end
|
||||||
|
|
||||||
if DEBUG_MODE then
|
if DEBUG_MODE then
|
||||||
|
56
test.lua
56
test.lua
@ -22,6 +22,27 @@ local function dummy() end
|
|||||||
minetest.register_on_leaveplayer = dummy
|
minetest.register_on_leaveplayer = dummy
|
||||||
minetest.get_modpath = dummy
|
minetest.get_modpath = dummy
|
||||||
minetest.is_singleplayer = 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)
|
table.indexof = table.indexof or function(list, value)
|
||||||
for i, item in ipairs(list) do
|
for i, item in ipairs(list) do
|
||||||
@ -258,4 +279,39 @@ describe("Flow", function()
|
|||||||
style[test;prop=value]
|
style[test;prop=value]
|
||||||
]])
|
]])
|
||||||
end)
|
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)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user