PDA

View Full Version : Anyone else using copyNode()?



MeepoSose
October 8th, 2009, 15:55
This is mostly for Foen I suppose. I am crashing and getting a corrupt db.xml after using it.

I plugged in your CopyNode() function into a global utility file and used it successfully (at first) to copy items from the item screen to the character sheet inventory screen. I've customized the items fairly heavily, but at first glance it seems to work. When the campaigns saves, however, the program crashes and the db.xml file gets corrupted. It just ends abruptly somewhere in the middle of the character record.

Here is the latest version I am using (with comments and console print statements added in for debug purposes):


-- provided courtesy of Foen on the Fantasy Grounds Forums
function copyNode(source, targetlist, rename)
-- creates a copy of the source node in the target list
print("copyNode() called");

local nodeType = source.getType();

if nodeType=="number" or nodeType=="string" or nodeType=="image" or nodeType=="dice" or nodeType=="windowreference" then
local newnode = targetlist.createChild(source.getName(),nodeType). setValue(source.getValue());
return newnode;
end

-- copying formattedtext isn't supported
if nodeType=="formattedtext" then
print("copyNode: formattedtext");
-- create the node but don't bother trying to populate it
local newnode = targetlist.createChild(source.getName(),nodeType);
return newnode;
end

-- unknown value?
if nodeType~="node" then
-- don't create anything. Should perhaps throw an error
return nil;
end

-- must be a complex node, we need to repeat the process on all child nodes.
local newlist;

if rename then
print("copyNode: rename");
newlist = targetlist.createChild();
else
print("copyNode: rename = false");
newlist = targetlist.createChild(source.getName());
end

for k,subnode in pairs(source.getChildren()) do
print("copyNode: copying children (with rename)");
copyNode(subnode,newlist,true);
end

return newlist;
-- done

end


Before the save occurs, the items copy over and I can click on the shortcut to open it up and modify any fields. I can copy several items without problems and the items are true copies. They update independently from that point on -- exactly like I want.

Here is the code which calls it from charsheet_inventorylist.lua. The type is "shortcut".



function addItem(source)
-- Parameter validation
if not source then
return nil;
end

local list = window.getDatabaseNode().createChild("inventorylist");
local newnode = Utility.copyNode(source,list,true);
if newnode then
newnode.createChild("shortcut","windowreference").setValue("item");
end
return true;

end

function onDrop(x, y, draginfo)
if draginfo.isType("item") then
print("item");

local source = draginfo.getDatabaseNode();

local newentry = addItem(source);

return true;
elseif draginfo.isType("shortcut") then
print("item shortcut");
local class, datasource = draginfo.getShortcutData();
local source = draginfo.getDatabaseNode();

if class == "item" then
local newentry = addItem(source);
print("shortcut to item class type dropped");
end
return true;
else
print(draginfo.getType());

end

end


The problem is reproducible. I can create new items manually in the character inventory and call a /save with no problems. It is only after dragging and dropping one or more items and calling /save (or allowing it to occur on the timer) that I get the crashes.

Foen
October 8th, 2009, 17:43
You will get crashes if the source datatypes don't match the target datatypes (so perhaps there is a field called 'cost' and it is a string in the source, but the target list expects a number for the 'cost' field).

Also the behaviour of createChild has changed a bit, it isn't always guaranteed to return a valid node (when called on a client which doesn't own the parent node), so it is wise to check that createChild has returned a valid node.

Other than that, I can't think what else may have gone awry.

Stuart

MeepoSose
October 8th, 2009, 18:44
Thanks Foen. Some fields don't write to the DB when there is no data filled out, but with the exception of three fields: "carried", "location" and "showonminisheet", they can each have the same exact data.



<!-- Manual Item on Charsheet -->
<id-00001>
<armorBonus type="number">6</armorBonus>
<armorType type="string">Medium Armor</armorType>
<attackbonus type="number">0</attackbonus>
<carried type="number">0</carried>
<checkPenalty type="number">-5</checkPenalty>
<cl type="number">0</cl>
<cost type="string">120 gp</cost>
<count type="number">0</count>
<criticalmultiplier type="number">0</criticalmultiplier>
<isidentified type="number">0</isidentified>
<itemtype type="string">Armor</itemtype>
<magicBonus type="number">0</magicBonus>
<maxDex type="number">1</maxDex>
<maxSpeed type="string">30 ft./20 ft.</maxSpeed>
<name type="string">Chainmail, Blackened</name>
<primarydamage type="dice"></primarydamage>
<primarydamagebonus type="number">0</primarydamagebonus>
<secondarydamage type="dice"></secondarydamage>
<secondarydamagebonus type="number">0</secondarydamagebonus>
<shieldBonus type="number">0</shieldBonus>
<showonminisheet type="number">0</showonminisheet>
<spellFailure type="string">30%</spellFailure>
<text type="formattedtext">
<p></p>
</text>
<weaponrange type="number">0</weaponrange>
<weight type="number">40</weight>
</id-00001>




<!-- Manual Item on Items screen -->
<id-00002>
<armorBonus type="number">6</armorBonus>
<armorType type="string">Medium Armor</armorType>
<attackbonus type="number">0</attackbonus>
<checkPenalty type="number">-5</checkPenalty>
<cl type="number">0</cl>
<cost type="string">150 gp</cost>
<criticalmultiplier type="number">0</criticalmultiplier>
<description type="string">shiny new chainmail.</description>
<isidentified type="number">0</isidentified>
<itemtype type="string">Item</itemtype>
<magicBonus type="number">0</magicBonus>
<maxDex type="number">2</maxDex>
<maxSpeed type="string">20 ft/15 ft.</maxSpeed>
<name type="string">Chainmail</name>
<primarydamage type="dice"></primarydamage>
<primarydamagebonus type="number">0</primarydamagebonus>
<secondarydamage type="dice"></secondarydamage>
<secondarydamagebonus type="number">0</secondarydamagebonus>
<shieldBonus type="number">0</shieldBonus>
<spellFailure type="string">30%</spellFailure>
<text type="formattedtext">
<p> </p>
</text>
<weaponrange type="number">0</weaponrange>
<weight type="number">40</weight>
</id-00002>


I also note that if I drag a manually created item on the charsheet inventory and drop it on the same charsheet inventory, it crashes again.

This is how the charsheet's inventory XML looks after that copy attempt (it just cuts off in the middle):


<inventorylist idcounter="3">
<id-00001>
<armorBonus type="number">6</armorBonus>
<armorType type="string">Medium Armor</armorType>
<attackbonus type="number">0</attackbonus>
<carried type="number">0</carried>
<checkPenalty type="number">-5</checkPenalty>
<cl type="number">0</cl>
<cost type="string">120 gp</cost>
<count type="number">0</count>
<criticalmultiplier type="number">0</criticalmultiplier>
<isidentified type="number">0</isidentified>
<itemtype type="string">Armor</itemtype>
<magicBonus type="number">0</magicBonus>
<maxDex type="number">1</maxDex>
<maxSpeed type="string">30 ft./20 ft.</maxSpeed>
<name type="string">Chainmail, Blackened</name>
<primarydamage type="dice"></primarydamage>
<primarydamagebonus type="number">0</primarydamagebonus>
<secondarydamage type="dice"></secondarydamage>
<secondarydamagebonus type="number">0</secondarydamagebonus>
<shieldBonus type="number">0</shieldBonus>
<showonminisheet type="number">0</showonminisheet>
<spellFailure type="string">30%</spellFailure>
<text type="formattedtext">
<p></p>
</text>
<weaponrange type="number">0</weaponrange>
<weight type="number">40</weight>
</id-00001>
<id-00002>
<armorBonus type="number">6</armorBonus>
<armorType type="string">Medium Armor</armorType>
<attackbonus type="number">0</attackbonus>
<carried type="number">0</carried>
<checkPenalty



Also, do I need to add an <acceptdrop /> to the windowlist if I'm handling it within an onDrop() function? Currently, that isn't specified on this screen.

Foen
October 8th, 2009, 22:11
Hmm, I can't see what is wrong here.

The copyNode routine is handy if you don't know the source datastructure for sure, otherwise I'd suggest you use acceptdrop, but you'll need to combine it with some code (acceptdrop handles formatted text, but not die fields).

Stuart

MeepoSose
October 9th, 2009, 20:15
Thanks Foen. I wasn't able to track down the specific issue, but I was finally able to get a derivative version going. I manually create the target node first and then call a non-recursive version like this:



-- Derived from copyNode code provided by Foen on the FantasyGrounds development forum
function copyNodeChildren(source, target)
for k,subnode in pairs(source.getChildren()) do
local subnodeType = subnode.getType();

if subnodeType=="number" or subnodeType=="string" or subnodeType=="image" or subnodeType=="dice" or subnodeType=="windowreference" then
target.createChild(subnode.getName(),subnodeType). setValue(subnode.getValue());
end

-- copying formattedtext isn't supported
if subnodeType=="formattedtext" then
-- create the node but don't bother trying to populate it
target.createChild(subnode.getName(),subnodeType);
end
end
end



I suspect it had more to do with creating the target node first, so I may circle back and put the recursion back in later if I find myself needing to do a deep clone. Either way, I really like the basic idea of an node cloning function.