PDA

View Full Version : Merge Rules



Bidmaron
March 8th, 2014, 19:09
I have done a search and found the 3.0 announcing join, but I am confused in the difference between join and merge. I presume join is valid in templates regardless of whether layering is being done for rulesets (i.e Extensions)?

Bidmaron
March 8th, 2014, 21:22
Suppose there is a window class in the ruleset, let's call it ReferenceFeat, and I want to override that so it refers to a new template. In this template, the only new functionality that I want to add is a set of scripts. The question is, will the new declaration of ReferenceFeat in my Extension merge all the fields from the existing ReferenceFeat and also inherit the script functionality from the template the new ReferenceFeat is now using?

Here is the existing ReferenceFeat in the 3.5 ruleset:

<windowclass name="referencefeat">
<frame>referencepage</frame>
<placement>
<size width="400" height="350" />
</placement>
<sizelimits>
<dynamic />
</sizelimits>
<minimize>minimized_reference</minimize>
<tooltip field="name" />
<nodelete />
<sheetdata>
<sub_ref_header name="header">
<class>ref_feat_header</class>
</sub_ref_header>

<sub_ref_content name="content">
<class>ref_feat_stats</class>
</sub_ref_content>
<scrollbar_ref_content />

<resize_referencepage />
<close_referencepage />
</sheetdata>
</windowclass>

Here is the reference feat that I want to override with in my Extension:

<togglelocker name="referencefeat">
</togglelocker>


Here is my template in the Extension:

<template name="togglelocker">
<script>
--[[code in here]]
</script>
</template>


So, will this logically merge so that the effective reference feat will look like the following:

<windowclass name="referencefeat">
<script>
--[[code in here]]
</script>
<frame>referencepage</frame>
<placement>
<size width="400" height="350" />
</placement>
<sizelimits>
<dynamic />
</sizelimits>
<minimize>minimized_reference</minimize>
<tooltip field="name" />
<nodelete />
<sheetdata>
<sub_ref_header name="header">
<class>ref_feat_header</class>
</sub_ref_header>

<sub_ref_content name="content">
<class>ref_feat_stats</class>
</sub_ref_content>
<scrollbar_ref_content />

<resize_referencepage />
<close_referencepage />
</sheetdata>
</windowclass>

Trenloe
March 9th, 2014, 00:48
Merge rules only operate against an identical XML tag *AND* name attribute.

Therefore, from your code above <togglelocker name="referencefeat"> will not merge with <windowclass name="referencefeat"> because the XML tag is not the same.

Some more info here: www.fantasygrounds.com/forums/showthread.php?19530-Ruleset-layering-summary

All you should need in your extension is:

<windowclass name="referencefeat" merge="join">
<script>
--[[code in here]]
</script>
</windowclass>
This will match the <windowclass name="referencefeat"> in the 3.5e ruleset and will "join" this <script> tag section to the XML in the 3.5e ruleset, giving you what you showed in the last section of code.

Bidmaron
March 9th, 2014, 03:01
Well, I'd like to reuse the code, as it will be the same for many window classes in the ruleset, but I suppose I could just put the code into a lua file and simply insert it into all the window classes. The question then becomes does the script block (when there is one) in the ruleset window class get merged with the script block in the extension?

Nickademus
March 9th, 2014, 03:07
Scripts in FG do not have the ability to be merged. You have to copy the entire thing you are replacing and place your new code in it.

Bidmaron
March 9th, 2014, 03:34
Thanks, Nickademus.

But, as my first post asks, what is the difference between join and merge?

Nickademus
March 9th, 2014, 03:52
Merge is the xml tag. Join is a type of merge, as is replace.

Bidmaron
March 9th, 2014, 04:03
The Templates page of the Ruleset Documentation says:

Simply merging is not sufficient for some uses in templates. Therefore, any tag in a template may contain a "mergerule" attribute taking one of the following values. When a tag in the definition contains multiple children with the same name (i.e. a list of similar child tags), only the topmost is checked when looking for a merge rule.

"merge": Synonymous with the default operation
"replace": If the implementing control contains a tag in the same position as this one, removes the tag in the template and all its children. This is useful if a tag in the definition should contain values for e.g. multiple states as children of a parent tag, and an override should replace the child values as well as the main tag.
"add": Instead of replacing a value as a result of a merge, a tag in the same position as this one is instead created as another similar tag in the result. This is useful if a template presents a default list of states or values, but the implementing control is allowed to add new values to the list.
"resetandadd": This is similar to "replace", but after one replace, reverts to "add" mode. The result is that a set of similar tags in an implementing control will override a similar set in the template.
So, merge is a type of merge, and join was added with the 3.0 revision, or so I believe. There is no documentation yet on join.

Bidmaron
March 9th, 2014, 04:07
The other thing I want to ask you Nickademus is why is the type of feat "[Class]" rather than simply "Class?" In fact, the reference feat class goes to the trouble to have an onInit to add the brackets. Do you know why these brackets are necessary? I'm trying to write the code to permit editing a feat, and this extra layer of abstraction is making things really fun.(as in NOT)

Trenloe
March 9th, 2014, 04:35
So, merge is a type of merge, and join was added with the 3.0 revision, or so I believe. There is no documentation yet on join.
Merge is the same as join - see post #2 of the thread I linked above - here is that link again: https://www.fantasygrounds.com/forums/showthread.php?19530-Ruleset-layering-summary

Also see the "Developer - Ruleset Layering" section of the FG release notes: https://www.fantasygrounds.com/filelibrary/patchnotes.html

I'm not aware of the merge functionality being in operation before FG 3.0.

Also, regarding using merge with <script> blocks in <windowclass> objects:

When using the "merge" attribute for windowclass objects, there are two tags with special behaviors (script and sheetdata). The "sheetdata" tag will always "merge" based on the child control tag and name combination. Scripts will be nested with the top-most script able to call deeper scripts using the "super" tag. The "self" tag can be used to access the top-most script from a deeper level.

Bidmaron
March 9th, 2014, 05:01
OK, I studied that material, Trenloe. So, in my extension, if I want to cover the case of extending a class with scripts and not inadvertently killing functionality, I can use the "super" tag in functions I put in my extension. So, if I add an onInit and the original class already has an onInit, I can add a call to super.onInit at the start of my onInit (of course, that doesn't handle all possible conflicts, but I think that is the safest). How can I test for the presence of super.onInit before I call it to prevent an error?

Trenloe, do you know the reason the reference feat class encapsulates the feat type in brackets?

Nickademus
March 9th, 2014, 05:06
The other thing I want to ask you Nickademus is why is the type of feat "[Class]" rather than simply "Class?" In fact, the reference feat class goes to the trouble to have an onInit to add the brackets. Do you know why these brackets are necessary? I'm trying to write the code to permit editing a feat, and this extra layer of abstraction is making things really fun.(as in NOT)

I don't know the specific class you are referring to but one thing I've noticed while working with the manager scripts is that FG is run mostly on strings. A lot of times an object with values will be formed into a single string with brackets used as delimiters and then passed to the GM client to be broken down and reconstituted into an object with values. So if you're seeing a place in the code where brackets are purposely being placed in a string, it is probably prepping it for parsing later on.

Trenloe
March 9th, 2014, 05:24
Trenloe, do you know the reason the reference feat class encapsulates the feat type in brackets?
It's not actually changing the data, all it is doing is changing the "type_label" control value to have square brackets around it - so just what is displayed in the GUI.

I would imagine it is just to make feat entries look a little bit like the entries in the rulebook and PRD where the feat type is listed in brackets: https://paizo.com/pathfinderRPG/prd/feats.html

Bidmaron
March 9th, 2014, 05:53
Thanks, Trenloe. I realize it isn't changing the data, but I think I'm going to eliminate them in my extension, as letting the user edit something with brackets added then raises a host of implementation issues (what happens if the user deletes one or both brackets, e.g.?)

The core rulebook has the type in parentheses, so not even Paizo is consistent.

Moon Wizard
March 9th, 2014, 21:15
To check for existence of functions you are overriding, you can check directly. (I.e. if super.onInit then super.onInit() end)

The merge attribute is new, and applies at the level above; similar to the mergerule attribute which works from the layer below. The merge and mergerule attribute both support the "merge" value, which is the default for templates. The "join" value is equivalent to "merge". For windowclasses, the default merge value is "replace".

There is no concept copying or inheriting from windowclasses, only replacing or extending existing windowclasses.

Cheers,
JPG

Bidmaron
March 10th, 2014, 02:56
Thanks, JPG.
I am trying to test the Module.export call, but I'm running into an error. I don't want a picture and no token exports. This is my code:

local expTokens={};
local expNodes={"reference.favored.dwarfalchemist@PFRPG Classes"};
Debug.chat("before export");
Module.export("Test", "Test", "someone", "Test", "",expNodes,expTokens);
Debug.chat("exported");

The first debug is printing out, and I am getting the following error:

Script Error: invalid key to 'next'

What am I doing wrong?

Bidmaron
March 10th, 2014, 05:06
JPG, I looked through several 3.5 and CoreRPG files and could not find an example of this ruleset overriding in use. What is the syntax for using the merge attribute? I presume if I am overriding a window class, it would be <merge>join</merge> or whatever mode you wanted, and it would be in the tags for the window class in my extension file. If I want to delete a field in the original window class, and add a new field, I cannot see how to do that. I presume I'd do <merge>delete</merge> in the otherwise empty tag for the field in my new window class, along with proving the new control.

Trenloe
March 10th, 2014, 05:34
JPG, I looked through several 3.5 and CoreRPG files and could not find an example of this ruleset overriding in use. What is the syntax for using the merge attribute?
You won't find many "merge" references in CoreRPG as this is the first ruleset to load so merging will usually be done by subsequent rulesets - but there are 3 merge="delete" examples in the CoreRPG ruleset.

Do a "find in files" in the 3.5e ruleset for merge=" and you will find a lot more references.


If I want to delete a field in the original window class, and add a new field, I cannot see how to do that.

You need to specify the tag and any name (if it exists) to be able to delete a field - and it has to be in exactly the same position within the XML structure. For example, if you wanted to delete the control "portraitbase" from the following windowclass:

<windowclass name="charselect_host_entry">
<frame>charselectentry</frame>
<sizelimits>
<maximum width="265" />
</sizelimits>
<script file="campaign/scripts/charselect_host_entry.lua" />
<sheetdata>
<genericcontrol name="portraitbase">
<bounds>10,10,72,72</bounds>
<disabled />
<icon>charlist_base</icon>
</genericcontrol>
You would use the following code in your extension:

<windowclass name="charselect_host_entry">
<sheetdata>
<genericcontrol name="portraitbase" merge="delete" />
Note that you have to include the whole XML hierarchy to where the control is that you want to delete.

Similarly, if you wanted to add a control to the same windowclass sheetdata:

<windowclass name="charselect_host_entry">
<sheetdata>
<stringcontrol name="newcontrol" merge="add" / >

Bidmaron
March 11th, 2014, 00:47
Thanks, Trenloe! I thought I was searching 3.5 for 'merge' and 'join,' but it turns out that I friggin' left the directory of CoreRPG. I knew there wouldn't be any in CoreRPG.

Bidmaron
March 12th, 2014, 03:38
Nudge please on post #16?

Trenloe
March 12th, 2014, 03:49
Thanks, JPG.
I am trying to test the Module.export call, but I'm running into an error. I don't want a picture and no token exports. This is my code:

local expTokens={};
local expNodes={"reference.favored.dwarfalchemist@PFRPG Classes"};
Debug.chat("before export");
Module.export("Test", "Test", "someone", "Test", "",expNodes,expTokens);
Debug.chat("exported");

The first debug is printing out, and I am getting the following error:

Script Error: invalid key to 'next'

What am I doing wrong?
EDIT: Updated with correct info on the script references.

It looks like your expNodes is not a valid table entry that Module.export expects.

See addExportNode(node) in \utility\scripts\export.lua on how to set the correct table entry when using the Module.export command - the performExport function in the same file gives an example of the format needed for Module.export.

"node" in addExportNode(node) needs to be a DB node object, not a string name representation of a node - you could use DB.findNode("reference.favored.dwarfalchemist@PFRPG Classes") to get the database node.

Bidmaron
March 12th, 2014, 04:07
Thanks, Trenloe. It looks like it's a data structure indexed by the node name that has a field called "import" that is the node name again, another field called category that itself has subfields that are the category name and a mergeid field with the merged. Wow.

Bidmaron
April 4th, 2014, 03:56
JPG, on your terminology here: above and below. If I have a window in the ruleset, awindow, and I want to override script functionality in an extension, do I use merge or merge rule in the extension?

Once I have that (and use the merge value for whichever tag I'm supposed to use), I can then invoke the ruleset's code by using 'super.'. So, if I have the onInit in my extension, I can invoke the ruleset's onInit by the following:

if super and super.onInit then
super.onInit();
end

Right?

Moon Wizard
April 4th, 2014, 20:04
Yes. That's how it should work for control templates and any windowclass definitions using merge="join".

Cheers,
JPG

Bidmaron
April 27th, 2014, 02:14
Here's the template definition in CoreRPG:

<template name="button_checkbox">
<buttonfield>
<state icon="button_checkoff" />
<state icon="button_checkon" />
</buttonfield>
</template>

I want to replace the state_icons for the control in an inheriting template several layers later. Is this the right way to do that?

<template name="button_checkbox2">
<button_inheriting_button_checkbox>
<state merge="resetandadd" icon="button_checkoff2" />
<state merge="add" icon="button_checkon2" />
</button_inheriting_button_checkbox>
</template>

Bidmaron
April 28th, 2014, 21:17
After testing, it appears that this is exactly how to do it. Works well! Really liking the new merge features, JPG.