PDA

View Full Version : Problem with player notes feature introduced with 2.4, node ownership



cscase
September 2nd, 2013, 00:58
Doing some testing here with the ruleset I've been working on, and I am running into a problem. I started from the CoC ruleset to make my modifications, and I find that updating the base.xml version to 2.4+ breaks the notes feature for the players.

When a player tries to create a new note, the following error message is produced:

Script Error: [string "notesmall"]:1: attempt to index upvalue 'ownernode' (a nil value)

This error can be replicated by doing nothing other than changing the version # in the CoC ruleset. Note, though, that it only affects players creating notes, not the GM.

Here's the change that I suspect is the origin of this difficulty:
- Players can no longer create database nodes within database trees they do not own.

I don't fully understand how the notes code here is working, but I suspect that maybe the old ruleset created notes all in the same node or something? I'm wondering if moonwizard, having recently worked with this code, might know off the top of his head what is necessary to resolve this issue? Is it a quick fix, like changing a node reference? Or can I make ownership of a particular node public, thereby resolving the permissions problems?

Dakadin
September 2nd, 2013, 01:46
You need to use the addHolder function to give them access or ownership to the database node. You can find it in the library here: https://www.fantasygrounds.com/refdoc/DB.xcp#addHolder.

cscase
September 2nd, 2013, 05:37
Thanks, Dakadin! That makes sense. I'm doing some digging around and I see there is a file called notemanager.lua, and near the top it has this function:

function onInit()
if User.isHost() then
notenode = DB.createNode("note");
notenode.onChildUpdate = refreshOwner;
hostuser = User.getUsername();
notenode.addHolder(hostuser,true);
User.onLogin = onLogin;
end
end

I'm thinking maybe this is where I need to do this addHoldering. Maybe if I just take away the "if" from this and make it unconditional, regardless of whether the user is the host? Am I on the right track with this at all?

This may be entirely unrelated, but I also notice that, as the GM, if I delete a note that is in an open window, I get the error:
Script Error: [strong "scripts/notelist.lua"]:67: attempt to call field 'close' (a nil value)

Code referenced by this one is:


-- remove any windows for nodes no longer needed
for path,note in pairs(notes) do
if note.win then
if note.needed then
note.win.refresh();
else
note.win.close();
note.win = nil;
end
end

Dakadin
September 2nd, 2013, 06:44
For the first issue, it would probably work best when the players are selecting their characters. It happens in the characterlist.lua onLogin function. Here is the code from 4E that you can use as an example:

function addUserAccess(sNode, username)
local node = DB.createNode(sNode);
if node then
node.addHolder(username);
end
end

function onLogin(username, bActivated)
if bActivated then
addUserAccess("options", username);
addUserAccess("partysheet", username);
addUserAccess("calendar.current", username);
addUserAccess("calendar.data", username);
addUserAccess("calendar.log", username);
addUserAccess("combattracker", username);
addUserAccess("combattracker_props", username);
addUserAccess("modifiers", username);
addUserAccess("effects", username);
end
end

function onClose()
-- Remove holder information from shared nodes to reduce DB clutter
if User.isHost() then
DB.removeAllHolders("options", false);
DB.removeAllHolders("partysheet", false);
DB.removeAllHolders("calendar", false);
DB.removeAllHolders("combattracker", false);
DB.removeAllHolders("combattracker_props", false);
DB.removeAllHolders("modifiers", false);
DB.removeAllHolders("effects", false);
end
end

It is adding users to the nodes when the characters login and removing the references when they logout.

For the second issue, try changing the code to this:

-- remove any windows for nodes no longer needed
for path,note in pairs(notes) do
if note.win then
if note.needed then
note.win.refresh();
else
if note.win.close then
note.win.close();
end
note.win = nil;
end
end

I just added a check to see if the function exists before calling the function. Those issue come up fairly regularly so you will get in the habit of checking for certain things to make sure they exist before acting on them.

cscase
September 3rd, 2013, 03:25
Alright, hmmm. On the second issue there, which I guess was entirely separate, your "if" seems to have completely resolved that little problem. Thank you! Also, thank you for taking time out of your life to lend a hand with this. I think I would long ago have given up if not for the help of you and Trenloe.

On the db node ownership thing, I tried something, but it didn't work. And I found some potentially interesting things that look screwy in the DB.

Here's what I did:
First I looked in the characterlist.lua that you mentioned.
I pasted in the addUserAccess function from the 4e example you posted, above.
I found that there is an onLogin() function there, but previously, it didn't have anything in it at all. It listed "activated" instead of bActivated as a parameter, so I did this:

function onLogin(username, activated)
if activated then
addUserAccess("note", username);
end
end

I'm still getting the same error message, though. Here is the code that I think is hitting the error:

local initialised = false;
local ownernode = nil;
local publicnode = nil;
function onInit()
ownernode = getDatabaseNode().createChild("owner","string");
publicnode = getDatabaseNode().createChild("ispublic","number");
ownernode.onUpdate = refresh;
initialised = true;
refresh();
end
function onMenuSelection(entry)
if entry and entry==6 then
windowlist.deleteNote(self);
return true;
end
end
function refresh()
local locked = true;
if not initialised then
return;
end
if ownernode then
locked = (ownernode.getValue()~=User.getUsername());
end
if User.isHost() then
locked = false;
end
...there's more, but it looks less relevant
I'm looking in the database, and seeing some weird stuff, too. The username of the player attempting to create the note is "Cara." But in the interface, it shows the owner as "Car." And here's what the note nodes in the DB are looking like...
A note created by the player first, then one made by the GM:

<note idcounter="6">
<holder name="GM" owner="true" />
<holder name="Cara" />
<id-00001>
<holder name="GM" />
<holder name="Cara" />
<holder name="Car" owner="true" />
<ispublic type="number">0</ispublic>
<owner type="string">Car</owner>
</id-00001>
...
<id-00003>
<holder name="GM" owner="true" />
<holder name="Cara" />
<ispublic type="number">0</ispublic>
<name type="string">test note</name>
<owner type="string">GM</owner>
<text type="string">test text\r</text>
</id-00003>

When the player brings up the notes box, there are never any notes listed, but each time the player clicks "New," a new blank note is created in the list on the GM screen.

So, I'm no longer sure what exactly is going on here. Is it some kind of string-handling problem truncating the username? I tried it with a different user name, too, thinking maybe it was some weird unknowable thing like "car" is a keyword or something, but with the other name as well, it chopped off the last character in the same way, in some places here.

Dakadin
September 5th, 2013, 04:50
I would check the database node in the db.xml to verify that the node is actually "note" like in this line of code:

addUserAccess("note", username);

I would guess that it needs to be changed to "notes" in your code.

cscase
September 5th, 2013, 05:23
Yeah, I did check that. I actually started off with it as "notes" - which makes more sense to me, too - but after checking the db.xml changed it to "note" to match what is in there.

Also, I found this in the notelist.lua: there are some global variables defined, one of which is "notenode." It's set here, and I added a Debug.chat to let me see its contents.


local notenode = nil;
local notes = {};
local norepeat = true;
local inprogress = false;


function onInit()
-- fetch the note db node
notenode = DB.findNode("note");
Debug.chat(notenode);
if notenode then
-- catch any changes to the list
notenode.onChildUpdate = childUpdate;
-- request a reshare, if needed
NoteManager.reshare();
-- refresh the list
childUpdate();
end
-- add a menu option to create new notes
registerMenuItem("New Note","insert",5);
end

So, when I open the notelist, it sends me this in the chat window: databasenode = { note }

I'm picking my way through the notelist.lua, trying to understand how it works but not having tremendous success or seeing any obvious problems.

Moon Wizard
September 5th, 2013, 05:43
On a related note, the CoreRPG base layer ruleset in the v3.0 alpha (see Laboratory forum) supports player shared notes without having to write any ruleset code in addition to supporting a lot of other built-in features.

Cheers,
JPG

cscase
September 5th, 2013, 15:07
I'm definitely looking forward to that! Sounds like it will greatly speed development for new rulesets.

And although that makes what I am currently doing seem futile, to some degree, I am hoping to start running a game in the next few weeks or month or so, and it's my impression that 3.0's release is still some months away at a the very least, right? I've got more hours than I can count invested in this project, so I'm very keen to get the last wrinkles ironed out.

I tried doing just a wholesale yoink of the notes feature from 3.5e last night, but the initial result of that was a console screen full top to bottom of various errors, so I'm not sure if it'll be easier to fix the existing CoC notes, or to steal working code from another ruleset and try to get it working in here, but I'm desperate to figure something out.

Dakadin
September 5th, 2013, 17:03
I sent you a private message to see if we can get this resolved for you.