Starfinder Playlist
Page 1 of 2 12 Last
  1. #1
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075

    Not sure why not finding "children" for a node I see has "children"

    [SOLVED - rather I was misusing "#" there was never anything wrong - # isn't used on non integer tables]

    This is the output from console, as you see it counts there to be no nods - under what I THINK should be a node (classes) having 1 child (class)
    I am confused, the original code obviously works, it is from 5E and in (modified) AD&D Core as well. I made very small changes but nothing substantial - I don't see what I did wrong. But then I am really stumped at times by the xml interactions

    The most likely culprit is the XML does not say what I think it does or the definition of "children" has a requirement nuance?


    Code:
    ...
    Runtime Notice: s'n=id-00003, class=reference_class, rec=reference.classes.fighter@Swords & Wizardry Complete - PHB'
    Runtime Notice: s'sRecord: reference.classes.fighter@Swords & Wizardry Complete - PHB'
    Runtime Notice: s'create or get from: id-00003'
    Runtime Notice: s'nodeList: classes'
    Runtime Notice: s'resource = ' | s'char_abilities_message_classadd'
    Runtime Notice: s'#nodes=0'
    Script Error: [string "campaign/scripts/manager_char.lua"]:187: attempt to call field 'findNode' (a nil value)
    The snippet from "addClassRef" method, novelist for the char sheet in question who not have 0 children (if I understand what qualifies as children and likely THAT is my mistake.)
    Code:
    	-- Get the list we are going to add to. If "classes" did not exist, it would be created.
    	Debug.console("create or get from: " .. nodeChar.getName());
    	local nodeList = nodeChar.createChild("classes");
    		Debug.console("nodeList: " .. nodeList.getName());
    	
    	if not nodeList then
    		-- I cannot imagine what error could occur here, but as the API mentions nil
    		-- as a possibility in case of error, I'll leave the check.
    		Output.chatMessage("** ALERT DEV: nodeChar.createChild(\"classes\" returned nil");
    		return;
    	end
    
      -- New class name.  
      local sClassName = DB.getValue(nodeSource, "name", "");
    
      -- Notify
      Output.chatMessageFormatted("char_abilities_message_classadd", sClassName, DB.getValue(nodeChar, "name", ""))
    
    
      -- Check to see if the character already has this class
      local nodeClass = nil;
      local sRecordSansModule = StringManager.split(sRecord, "@")[1];
      local sRecordSourceModule = StringManager.split(sRecord, "@")[2];
      
      local aCharClassNodes = nodeList.getChildren();
      Debug.console("#nodes=" .. #aCharClassNodes);
     local xxx = nodeList.findNode(".class");  <<<------- LINE 187 which above indicates null, was trying different ways to "grab" class
     Debug.console("num xxx: ", #xxx);
    XML being looked at in code above:
    Code:
    				</wisdom>
    			</abilities>
    			<classes>
    				<class>
    					<active type="number">1</active>
    					<level type="number">2</level>
    					<name type="string">fighter</name>
    					<xp type="number">2100</xp>
    					<xpactive type="number">1</xpactive>
    				</class>
    			</classes>
    			<defenses>
    				<ac>
    Last edited by Varsuuk; March 28th, 2019 at 21:27.

  2. #2
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    To test my creation (because I had already hand-edited to the XML prior to coding the add class ref method to be able to list classes in the "Class/Level" control) after the nodeList=createChild("classes"), I added nodelist2=nodeList.createChild("foo") and then looked in XML and sure enough foo was a sibling. But getChildren on nodeList STILL shows 0?

  3. #3
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    What is the nodeList=createChild("classes")?

    Don't you want nodeList = parent.createChild("classes"), where parent is the node that you want to hold the "classes" element?

  4. #4
    ddavison's Avatar
    Join Date
    Sep 2008
    Posts
    6,134
    Blog Entries
    21
    class is a child of classes. There are not special or unique XML nuances there. It's a standard parent/child relationship.

    Here is code from manager_char.lua in 5E that iterates through classes. In this case, nodeList is already pointed to the classes element.
    Code:
    	-- Get the list we are going to add to
    	local nodeList = nodeChar.createChild("classes");
    	if not nodeList then
    		return;
    	end
    Code:
    	for _,v in pairs(nodeList.getChildren()) do
    		local _,sExistingClassPath = DB.getValue(v, "shortcut", "", "");
    		if sExistingClassPath == "" then
    			local sExistingClassName = StringManager.trim(DB.getValue(v, "name", "")):lower();
    			if sExistingClassName ~= "" and (sExistingClassName == sClassNameLower) then
    				nodeClass = v;
    				break;
    			end
    		else
    			local sExistingClassPathSansModule = StringManager.split(sExistingClassPath, "@")[1];
    			if sExistingClassPathSansModule == sRecordSansModule then
    				nodeClass = v;
    				break;
    			end
    		end
    	end
    Code:
    	-- If class already exists, then add a level; otherwise, create a new class entry
    	local nLevel = 1;
    	local bExistingClass = false;
    	if nodeClass then
    		bExistingClass = true;
    		nLevel = DB.getValue(nodeClass, "level", 1) + 1;
    	else
    		nodeClass = nodeList.createChild();
    	end
    
    	-- Any way you get here, overwrite or set the class reference link with the most current
    	DB.setValue(nodeClass, "shortcut", "windowreference", sClass, sRecord);
    Last edited by ddavison; March 28th, 2019 at 15:01.

  5. #5
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    Quote Originally Posted by ddavison View Post
    What is the nodeList=createChild("classes")?

    Don't you want nodeList = parent.createChild("classes"), where parent is the node that you want to hold the "classes" element?
    Sorry Doug, that was me quickly typing in an afterthought of something I tested real quick.
    The actual code was in first message and it did have the "parent." portion: local nodeList = nodeChar.createChild("classes");

    I just figured, I had MANUALLY created the <class> ... </class> entry for that character (chicken and egg thing) so I thought I typed or something. Then I added the: nodelist2=nodeList.createChild("foo") to ensure that the lua code ITSELF added a node so of course it should find it with "getChildren()"

    Like I said, I know it works in 5E so I know I am making a mistake somewhere
    Last edited by Varsuuk; March 28th, 2019 at 15:47.

  6. #6
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    See inline <<VARSUUK>>> comments where I try to line up my code vs what you gave me from 5E:

    Quote Originally Posted by ddavison View Post
    class is a child of classes. There are not special or unique XML nuances there. It's a standard parent/child relationship.

    Here is code from manager_char.lua in 5E that iterates through classes. In this case, nodeList is already pointed to the classes element.
    Code:
    	-- Get the list we are going to add to
    	local nodeList = nodeChar.createChild("classes");
    	if not nodeList then
    		return;
    	end
    Code:
    <<VARSUUK>>
    	-- Get the list we are going to add to. If "classes" did not exist, it would be created.
    	Debug.console("create or get from: " .. nodeChar.getName());
    	local nodeList = nodeChar.createChild("classes");
    		Debug.console("nodeList: " .. nodeList.getName());
    Code:
    	for _,v in pairs(nodeList.getChildren()) do
    		local _,sExistingClassPath = DB.getValue(v, "shortcut", "", "");
    		if sExistingClassPath == "" then
    			local sExistingClassName = StringManager.trim(DB.getValue(v, "name", "")):lower();
    			if sExistingClassName ~= "" and (sExistingClassName == sClassNameLower) then
    				nodeClass = v;
    				break;
    			end
    		else
    			local sExistingClassPathSansModule = StringManager.split(sExistingClassPath, "@")[1];
    			if sExistingClassPathSansModule == sRecordSansModule then
    				nodeClass = v;
    				break;
    			end
    		end
    	end
    Code:
    <<<VARSUUK>>>
     local aCharClassNodes = nodeList.getChildren();
      Debug.console("#nodes=" .. #aCharClassNodes);   ---> This says "# notes=0" in console.
    <<< Varsuuk I didn't continue with your third code snip since I already failed in one just before this... >>>

    Code:
    	-- If class already exists, then add a level; otherwise, create a new class entry
    	local nLevel = 1;
    	local bExistingClass = false;
    	if nodeClass then
    		bExistingClass = true;
    		nLevel = DB.getValue(nodeClass, "level", 1) + 1;
    	else
    		nodeClass = nodeList.createChild();
    	end
    
    	-- Any way you get here, overwrite or set the class reference link with the most current
    	DB.setValue(nodeClass, "shortcut", "windowreference", sClass, sRecord);

  7. #7
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    AHA!

    I AM misunderstanding something...

    I went into 5E code to add debug statements to trace how it differs and perhaps jar my mind into looking at the problem correctly.
    I added the Debug.log() below (only change were the console log lines
    Code:
    	-- Check to see if the character already has this class; or create a new class entry
    	local nodeClass = nil;
    	local sRecordSansModule = StringManager.split(sRecord, "@")[1];
    	local aCharClassNodes = nodeList.getChildren();
    Debug.console("# of aCharClassNodes = " .. #aCharClassNodes);
    	for _,v in pairs(aCharClassNodes) do
    Debug.console("HERE1");	
    		local _,sExistingClassPath = DB.getValue(v, "shortcut", "", "");
    		local sExistingClassPathSansModule = StringManager.split(sExistingClassPath, "@")[1];
    		if sExistingClassPathSansModule == sRecordSansModule then
    			nodeClass = v;
    			break;
    		end
    	end
    	if not nodeClass then
    		for _,v in pairs(aCharClassNodes) do
    Debug.console("HERE2");
    			local sExistingClassName = StringManager.trim(DB.getValue(v, "name", "")):lower();
    			if (sExistingClassName == sClassNameLower) and (sExistingClassName ~= "") then
    				nodeClass = v;
    				break;
    			end
    		end
    	end
    	local bExistingClass = false;
    	if nodeClass then
    		bExistingClass = true;
    	else
    		nodeClass = nodeList.createChild();
    	end
    This is what I see in the log (note no HERE):
    Code:
    Runtime Notice: Reloading ruleset
    Ruleset Warning: Font (windowtitle): Windows replaced specified font face (Alegreya Sans SC Bold) with (Alegreya Sans SC)
    >> Here I drag Fighter to new char:
    Runtime Notice: s'# of aCharClassNodes = 0'
    >> Here I drag Fighter to Lvl 1 Fighter Char above:
    Runtime Notice: s'# of aCharClassNodes = 0'
    Runtime Notice: s'HERE1'
    >> Here I drag Cleric to Lvl 2 Fighter Char above:
    Runtime Notice: s'# of aCharClassNodes = 0'
    Runtime Notice: s'HERE1'
    Runtime Notice: s'HERE2'
    And this is the XML post my 2nd attempt at copying Fighter and 1 of Cleric to the character's Class in 5E Ruleset:

    Code:
    			</backgroundlink>
    			<classes>
    				<id-00001>
    					<casterlevelinvmult type="number">0</casterlevelinvmult>
    					<casterpactmagic type="number">0</casterpactmagic>
    					<hddie type="dice">d10</hddie>
    					<hdused type="number">0</hdused>
    					<level type="number">3</level>
    					<name type="string">Fighter</name>
    					<shortcut type="windowreference">
    						<class>reference_class</class>
    						<recordname>reference.classdata.fighter@DD PHB Deluxe</recordname>
    					</shortcut>
    				</id-00001>
    				<id-00002>
    					<casterlevelinvmult type="number">1</casterlevelinvmult>
    					<hddie type="dice">d8</hddie>
    					<hdused type="number">0</hdused>
    					<level type="number">1</level>
    					<name type="string">Cleric</name>
    					<shortcut type="windowreference">
    						<class>reference_class</class>
    						<recordname>reference.classdata.cleric@DD PHB Deluxe</recordname>
    					</shortcut>
    				</id-00002>
    			</classes>
    			<coins>
    So yes, I guess I am not understanding what the # code should be expecting to do with the result of getChildren
    Probably the length thing doesn't work because it is a dictionary table not a normal integer indexed table?

    Going to do a similar set of prints in mine next - but guessing that "#" wasn't applicable then.

  8. #8
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    So - adding the same "HERE" prints shows me that both 5E and my S&W hit same code.
    So, now my next step is the continuation of the "class module" work (vs my hardcoded before) - I fell for a trap of my own making because I usually test iteratively as I develop. I checked to make sure I got the expected number of entries with what I thought was the LENGTH operator on the table, "#" instead of printing.

    So, next when not working from home I will do some reading to see in Lua docs why doesn't work for this sort of textkey-value table returned.

    Sorry for the confusion!

  9. #9
    Varsuuk's Avatar
    Join Date
    Dec 2015
    Location
    New York
    Posts
    2,075
    BTW - if anyone can clue me into why the first log line prints "0" and yet "HERE" is printed because the loop finds entries to loop over:

    ...
    local aCharClassNodes = nodeList.getChildren();
    Debug.console("# of aCharClassNodes = " .. #aCharClassNodes);

    for _,v in pairs(aCharClassNodes) do
    Debug.console("HERE1");
    ...

  10. #10
    That's because # operator only works with tables that have integer keys starting at zero, similar to the way that ipairs() only works with tables that have integer keys starting at zero.

    Since getChildren() returns a table of entries with the database child name as the key and the database child node object as the value, it will always return "0" in the first debug statement (i.e. doesn't use integer keys). In the second debug statement, the pairs() will iterate over any table (as opposed to ipairs()), not just integer-based tables.

    If you need to count the number of nodes in a table that doesn't use integer-based keys, you have to use a for ... in pairs(...) do ... end to count manually.

    Regards,
    JPG

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
5E Product Walkthrough Playlist

Log in

Log in