Merge Directory

Wed, 11/05/2008 - 19:56

Like the override directory, files inside the merge directory are relative to the World of Goo installation directory. However that's where the similarity ends. Files in the merge directory are not replaced, they are merged with the 2dboy originals (and possibly also merged with the results of lower-priority mods). Consequently the merge directory only operates on XML files.

The format of files in this directory are XSLT stylesheets, enabling full control of the produced XML. For each file that you want to merge, GooTool decrypts the 2dboy original, merges in your changes, and encrypts it back. (It also makes a backup of the original; it always merges from the 2dboy original and doesn't do incremental merging as that would have unexpected results when enabling and disabling addins).

The filenames end with the .xsl extension instead of .bin. An example of a full filename relative to your goomod root would be merge/res/levels/GoingUp/GoingUp.level.xsl. Note that the .bin suffix is replaced with .xsl.

Some knowledge of XSLT and XPath will help create complex merging rules, but the rest of this page contains some examples. You may also find davidc's XML Diff tool helpful - you give it the original XML file and your modified XML file, and it gives you back an XSL file that will make the changes.

Default rule

You need a default rule to copy across anything not matched by any other rules. Here it is:

Modify existing elements

You can modify existing elements by selecting them with your XPath. Remember to copy @* to preserve the other attributes, and to apply-templates to copy their child elements. The follow example selects all BallInstance elements, copies their attributes, and then overrides their type attribute:

Remember that the most specific rule matches, so here we select the balls where their id attribute is less than 4, and copy them unchanged. In this example, we're changing to UglyProduct balls, which don't have strands defined, so we don't want to touch the first 4 balls which are already connected.

<!-- But we must leave the first 4 balls alone, since --><!-- Ugly balls don't have strand definitions --><xsl:templatematch="/level/BallInstance[@id < 4]"><xsl:copy><xsl:copy-ofselect="@*"/><xsl:apply-templates/></xsl:copy></xsl:template>

In this example we modify the visualdebug attribute of the level element to enable graphical display of the level scene structure.

<xsl:templatematch="/level"><xsl:copy><xsl:copy-ofselect="@*"/><!-- set visual debug. set attributes after copying them, so we can overwrite --><xsl:attributename="visualdebug">true</xsl:attribute><xsl:apply-templates/></xsl:copy></xsl:template>

Deleting and inserting elements

Here we match all strand elements and delete them simply by not copying them at all.

Or, because WoG doesn't validate against a DTD, we could just add them to the end of the level element. This is probably preferable in case comments are removed or changed by another addin or by 2dboy in a future release.

Note that the new stuff is inside the <xsl:copy> - if outside it would append after the level is already closed!

Full example

This example modifies the EconomicDivide (displayed name: Small Divide) level using the above examples. The first template copies everything that isn't matched by another template untouched. The second template removes all balls. The third inserts balls where the old balls were (after the Balls comment). The fourth deletes all strands. The fifth modifies the level element by enabling visualdebug, and adds new Strands to the end of the file (demonstrating the second method of adding elements).

<?xmlversion="1.0"encoding="ISO-8859-1"?><xsl:transformversion="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><!-- Copy everything not matched by another rule --><xsl:templatematch="* | comment()"><xsl:copy><xsl:copy-ofselect="@*"/><xsl:apply-templates/></xsl:copy></xsl:template><!-- Delete existing ball instances --><xsl:templatematch="/level/BallInstance"/><!-- insert drip balls into the place where the previous balls were --><xsl:templatematch="/level/comment()[contains(., 'Balls')]"><xsl:copy/><BallInstancetype="water"x="-459.69"y="262.68"id="0"angle="0"/><BallInstancetype="water"x="-341.64"y="279.34"id="1"angle="0"/><BallInstancetype="water"x="-232.63"y="284.03"id="2"angle="0"/><BallInstancetype="water"x="-122.63"y="284.03"id="3"angle="0"/><BallInstancetype="water"x="-122.63"y="184.03"id="4"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="5"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="6"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="7"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="8"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="9"angle="0"/><BallInstancetype="water"x="-329.74"y="411.84"id="10"angle="0"/></xsl:template><!-- Delete existing strand instances --><xsl:templatematch="/level/Strand"/><!-- Set visual debug and insert new Strands --><xsl:templatematch="/level"><xsl:copy><xsl:copy-ofselect="@*"/><!-- set visual debug. set attributes after copying them, so we can overwrite --><xsl:attributename="visualdebug">true</xsl:attribute><xsl:apply-templates/><!-- Here is where we can insert nodes at the end of the file --><!-- As a demo, just insert the new strands at the end --><Strandgb1="0"gb2="1"/><Strandgb1="1"gb2="2"/><Strandgb1="2"gb2="3"/><Strandgb1="3"gb2="4"/></xsl:copy></xsl:template></xsl:transform>