New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for nodemeta forms #12
Conversation
+some small enhancements and corrections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All looks mostly good.
In the docs you should mention that a node meta form is seen the same for all viewers, even after element changes (?) so to show different content, you'll need to open a different form from within the node form.
Also, feel free to clean up the code around your changes. The code style is pretty awful
* state.param - The parameters supplied by form:show. | ||
* state.def - The form definition. | ||
* state.is_inv - Boolean which is true if this form is being shown as an inventory. | ||
* state.nodepos - Node position if attached to node meta |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be better to depreciate state.player (but keep present for backwards compatibility) and instead use state.location
which is:
{
type = "singleplayer",
name = "player name"
}
or
{
type = "node",
pos = { x = 0, y = 1, z = 2 },
players = {
"hey",
"yo"
}
}
EDIT: state.location, as that's more consistent with the MT api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree partily. In case of type "node" there is no player relation. Therefore
{
type = "node",
pos = { x = 0, y = 1, z = 2 },
}
The viewers should be handled at other place (not static)
Because of less time the merging of "state.player" + "state.nodemeta" to "state.location" is low-prio for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any idea for is_inv handling at this place?
{
type = "part_of_players_inventory", --?? or just "inventory" ?
name = "player name"
}
PS: I don't like the type = "singleplayer" because of misleadingly. type="player" is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both inventory
and player
are good
@@ -99,13 +100,15 @@ function smartfs.add_to_inventory(form,icon,title) | |||
end | |||
end | |||
|
|||
function smartfs._makeState_(form,player,params,is_inv) | |||
function smartfs._makeState_(form,player,params,is_inv, nodepos) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please fix commas here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(form, player, params, is_inv, nodepos) or (form,player,params,is_inv,nodepos) ???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the former
@@ -251,7 +260,7 @@ end | |||
-- Show a formspec to a user | |||
function smartfs._show_(form, player, params, is_inv) | |||
local state = smartfs._makeState_(form, player, params, is_inv) | |||
state.show = state._show_ | |||
state.show = state._show_ --?? needed? is already defined in smartfs._fdef[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no idea. Haven't read this code in like a year
-- Receive fields from formspec | ||
local function _sfs_recieve_(state,name,fields) | ||
if (fields.quit == "true") then | ||
if not state.is_inv then | ||
if state.nodepos then | ||
state:close() --mark as closed for this user (will be reopened if other user is on the node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If multiple users are viewing with the same state, it will prematurely set closed to true
closed = true
A opens.
closed = false
B opens
closed = false
A closes
closed = true <--------------
B closes
closed = true
doing reference counting would be better
viewers = 0
A opens.
viewers = 1
B opens
viewers = 2
A closes
viewers = 1
B closes
viewers = 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a hack, in current implementation the "closed" is reset in smartfs.nodemeta_on_receive_fields after the call if other users are connected (line 368) state.closed = nil --not closed
You are right, the viewers count will be better. Or just reading of next(state.multiplayer)
Should I rename state.multiplayer to something other? My proposal to change the state.player from currently "playername" to players table and replace the multiplayer table
if state.closed then -- current user leave the node | ||
state.multiplayer[sender:get_player_name()] = nil | ||
if next(state.multiplayer) == nil then -- multiplayer table empty | ||
--update formspec on node to a initial one for the next usage (respecting param persistence |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing )
state.multiplayer[sender:get_player_name()] = nil | ||
if next(state.multiplayer) == nil then -- multiplayer table empty | ||
--update formspec on node to a initial one for the next usage (respecting param persistence | ||
state._ele = {} --reset the form |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add state:clear()? Would be nice as a public API, and there may be more things to clear in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I planned to implement clearing combined with form._reg(state) regeneration as refresh() method in next changes block (if I port the townchest to smartfs). The refresh() can be useful for semi-generic forms, if the smartfs.create( ,function()) build up different form specification each time depends on parameter content. In preparation the "state.param" is already persistant for nodes (saved/restored in node metadata).
end | ||
smartfs.opened[opened_id] = nil -- remove the old state | ||
else | ||
state.closed = nil --not closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The state.closed = nil is correct to revert the state:close() because before close there was not value (=nil). But this place will be reworked if I remove the hack above
A nodemeta formspec is the same for all viewers by Minetest design. The formspec is just written to the metadata without relation to user opens them. If 2 users have open the form at the same time and one of them update the form, the second user see instantly the change (maybe I write a chat-node as demo oO)
I did not understand, bad style or good style? |
You don't appear to modify show(), so any changes after the original create will be sent to users using minetest.send_formspec and not saved in node data
Yeah, I understand that - I'd just like a note like "Changes are saved in node meta data and visible to all players, to show only a single player info please show them another form using As for engine implementation details - If the formspec meta data changes whilst they are viewing a form, do they see the change? Or would you need to minetest.send_formspec to force them to see it?
Awful means really bad. This is quite old code so it's inconsistent and ugly in places |
I will add a small part "Formspec on nodes" to the README.md so the info about visibility will be at this place The show() is not used for nodes. The next lines updates the form in nodemeta after data update and force the update on screens of other viewers if not state.closed then
if state.nodepos then
state:_attach_nodemeta_()
else
state:_show_()
end
else If the last user leave the node, the smartfs.opened[opened_id] needs to be destroyed and the state is lost. Therefore there is a update the form with "initial" form because of no trigger if an user opens the form again. state._ele = {} --reset the form
if form._reg(state) then --regen the form
state:_attach_nodemeta_() --write form to node
end So the short answer to your question
yes, the other viewer see the change instantly, I tried it |
You did not meant my changes as I understand first oO. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good progress. I'd prefer if you didn't bundle all these changes together. When merging, I'll split them out into separate commits. But next time you should only do one feature per PR - so one to add an image element, one to add new methods to each element, one to do a clean up and add nodemeta forms. You've made a lot of code style errors, but I'll fix those on merge as well.
If you could fix the other things that's not code style:
- userdata vs. username
- show() and AttachNodeMeta() should be the same function
I'm planning on doing some clean ups after this as well
on_receive_fields = smartfs.nodemeta_on_receive_fields | ||
}) | ||
|
||
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the on_after_place (or whatever it's called) property of the node to do this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is an example, I prefer the on_placenode for nodes placed by player and on_construct for generated nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to change it but in documentation there is no "pos" parameter in the on_place function ??? (http://dev.minetest.net/minetest.register_node#on_place) I'l change it to on_construct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
local currentmod = minetest.get_current_modname() -- mod the file was loaded from | ||
local envroot = nil | ||
|
||
if not currentmod or currentmod == "" or --not minetest or something hacky |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should never return nil, so not currentmod
is unnecessary
|
||
-- obsolete api compatibility to previous versions | ||
if type(player) == "string" then | ||
player = minetest.get_player_by_name(player) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to store player user data here - a username is fine. The userdata is not used anywhere. It is also dangerous to store player objects in Lua memory across callbacks - you have to be very careful to delete them when the player leaves the game - it's just so much safer to just store usernames.
function smartfs._makeState_(form, newplayer, params, is_inv, nodepos) | ||
-- Create object for monitoring of connected players. If no one connected the state can be free'd | ||
local _make_players_ = function(form, newplayer) | ||
local this = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the lua idiom is self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In lua documentation both is mentioned, an I liked "this" more :/ anyway to be uniform to the rest of the code I changed it already in the "views" commit.
function smartfs._makeState_(form,player,params,is_inv) | ||
function smartfs._makeState_(form, newplayer, params, is_inv, nodepos) | ||
-- Create object for monitoring of connected players. If no one connected the state can be free'd | ||
local _make_players_ = function(form, newplayer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
local function _make_players_(form, newplayer)
function smartfs.nodemeta_on_receive_fields(nodepos, formname, fields, sender) | ||
|
||
-- get form info and check if it's a smartfs one | ||
local meta = minetest.env:get_meta(nodepos) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minetest.env is deprecated. Just use minetest.get_meta
|
||
-- get the currentsmartfs state | ||
local opened_id = minetest.pos_to_string(nodepos) | ||
local state = nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= nil
is redundant
local state = nil | ||
local form = smartfs:__call(nodeform) | ||
if not smartfs.opened[opened_id] or --if opened first time | ||
smartfs.opened[opened_id].def.name ~= nodeform then --or form is changed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be an extra indent here. Also, some spaces are used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A question about this indent. There should be a difference if the next line is the first command in the loop or if it is a part of the long condition. Or is there no visible difference in lua coding style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if A and B and
C and D and E then
statements in if loop
go here
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean 2x tab in case of long condition indent?
|
||
--persist parameter for later usage | ||
meta:set_string("smartfs_param", minetest.serialize(state.param)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only comment needed is one above this if statement saying:
If there are no players using this formspec, reset it
|
||
## Formspec on nodes | ||
SmartFS is able to attach a formspec to a node metadata. The attached form can be opened by any player and all players see the same. If a player enter information and take updates on the form, all users see the updated form instantly. All changes are saved in node meta data and visible to all players, to show only a single player info please show them another form using form:show. | ||
There is a "reset" implemented if all players leave the node formspec, the initial state is restored. The parameters are implemented persistant so if you need to store sometging to node just use state:setparam() / state:getparam(). But do not save sensitive data since the nodemeta is sent to all player clients. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something
Also, you should wrap the text manually (the lines shouldn't be longer than 80 characters)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other parts like "Inventory Support" are without manually wrapping too. Which viewer do you use? In github view there will be a narrow text strip in case of <80 characters. My default geany view display up to 200 characters in a line.
…lacenode in sample
…nt on close from client (like trough button_exit[])
I did the most requested changes. Please let me know about my "most misformatted things" so I can prepare the next pull request. I will try to split the next big change to multiple pull requests. But because of dependencies between enhancements this will consume time till all functionality is upstream. |
I removed the nodemeta persistance stuff because I see it is not always usable. It was a quick-dirty hack without a concept. If you see some other things that should be removed from this "Enhancement-pack-pull-request" let me know. |
+some small enhancements and corrections
Please review all changes before merging, because I am a newbie ;)