KATA 2 OF 8 · XML LAYER
In Kata 1 you used <set> to change one value. That is one of eleven XML modification commands the game exposes (the same eleven on every build from V1.4 to V3.3, read from the game's own patcher). Learn them and the XPath that aims them, and you can change, add, or remove anything in the game's XML - which is the entire job for the next two katas. This is the reference you will come back to most.
| You want to | Command | Shape |
|---|---|---|
| Change a value that already exists | <set> | <set xpath="/items/item[@name='resourceWood']/property[@name='Stacknumber']/@value">6000</set> |
| Add or change an attribute on a node | <setattribute> | <setattribute xpath="/items/item[@name='resourceWood']" name="tag">wood</setattribute> |
| Add a new child node inside a node | <append> | <append xpath="/items"> ...new <item>... </append> |
| Insert a node next to an existing one | <insertBefore> / <insertAfter> | <insertAfter xpath="/items/item[@name='resourceWood']"> ...new <item>... </insertAfter> |
| Delete a node | <remove> | <remove xpath="/items/item[@name='resourceWood']/property[@name='Stacknumber']"/> |
| Delete an attribute | <removeattribute> | <removeattribute xpath="/items/item[@name='resourceWood']/@tag"/> |
| Add a new child node at the start of a node | <prepend> | <prepend xpath="/items"> ...new <item>... </prepend> |
| Add to or remove from a comma-separated value | <csv> | <csv xpath="/items/item[@name='resourceWood']/property[@name='Tags']/@value" delim="," op="add">myTag</csv> |
| Apply a block only on some game or mod versions | <conditional> | <conditional><if cond="game_version() >= version(3,0)"> ... </if><else> ... </else></conditional> |
| Pull in another patch file | <include> | <include filename="items_part2.xml" /> |
Every command lives inside <configs> ... </configs> in a file under your modlet's Config/ folder named after the vanilla file it patches. The rest of this page walks each command with a working example and the XPath selectors that aim them; the same commands drive XUi interface mods. Not sure what to write? The Server Tweak Mod Generator writes a complete server-settings modlet for you; open its Config/ files and you will find exactly these commands.
No single mod this time - this kata is the toolkit itself, with a verified example of each command, then a small combined modlet at the end that uses three of them together.
Nine take an xpath attribute that points at a node or attribute; conditional and include wrap other commands and take none. The seven below were introduced in Alpha 17; prepend, csv, conditional and include are in the game too, on every build from V1.4 to V3.3. A command the game does not know is logged as Patch type (name) unknown and skipped; a command whose xpath matches nothing is logged as XML patch for "file" from mod "Name" did not apply and skipped, and the mod still loads.
set - change an existing attributeChanges a value that already exists. If the target attribute does not exist, it does not create it - it logs a warning. This is the Kata 1 command.
<set xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='DegradationMax']/@value">500</set>
setattribute - add or change a named attributeUnlike set, this can create an attribute on a node that did not have it. You give the node in xpath and the attribute in name.
<setattribute xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='Weight']" name="measure">kilograms</setattribute>
append - add new nodes (or extend an attribute)The workhorse for adding content. Point at a parent node and the content inside the tag becomes a new child. (Point at an attribute instead and the text is appended to that attribute's value - handy for adding a tag.)
<!-- add a whole new property to an item -->
<append xpath="/items/item[@name='gunHandgunT1Pistol']">
<property name="MyCustomProp" value="1" />
</append>
<!-- or append to an attribute value (note the leading comma) -->
<append xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']/@value">,myNewTag</append>
insertAfter / insertBefore - place a sibling nodeWhere append adds a child inside a node, these add a sibling directly after or before the targeted node - useful when order matters (recipes, progression, UI elements).
<insertAfter xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']">
<property name="AddedAfterTags" value="a,b,c" />
</insertAfter>
remove - delete a nodeDeletes the node(s) the xpath selects. Self-closing - there is no content.
<remove xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='UnlockedBy']" />
removeattribute - delete one attributeDeletes a single attribute, leaving the node in place.
<removeattribute xpath="/items/item[@name='meleeToolStoneAxe']/@category" />
prepend - add new nodes at the startLike append, but the new content goes in first inside the targeted node (or at the start of an attribute value), which matters when the game reads a list in order.
<prepend xpath="/items/item[@name='gunHandgunT1Pistol']">
<property name="MyFirstProp" value="1" />
</prepend>
csv - add to or remove from a comma-separated valueMany attributes are lists (Tags, Groups, loot and spawn lists). csv edits one entry of such a list without rewriting the whole value, so two mods can touch the same list. op is add or remove; delim changes the separator (one character, or \n), and remove accepts * at the start or end of an entry as a wildcard. The target must be an attribute or a text node.
<csv xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']/@value" delim="," op="add">myNewTag</csv>
<csv xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']/@value" op="remove">weapon,ranged*</csv>
conditional - apply a block only when a test passesWraps if branches and an optional else. The cond expression can test the game version, whether another mod is loaded, and that mod's version, so one modlet can carry a 2.6 branch and a 3.x branch. conditional and include are the two commands that take no xpath of their own.
<conditional>
<if cond="game_version() >= version(3,0)">
<set xpath="/items/item[@name='resourceWood']/property[@name='Stacknumber']/@value">6000</set>
</if>
<else>
<set xpath="/items/item[@name='resourceWood']/property[@name='Stacknumber']/@value">3000</set>
</else>
</conditional>
The functions the evaluator knows, from the game's own code: game_version(), version(major, minor, ...) to build a value to compare against, mod_loaded("ModName"), mod_version("ModName") (the Version from that mod's ModInfo.xml), gamepref("Name"), game_loaded(), serverinfo(...) (only once a game is loaded), time_minutes(), has_entitlement(...), xpath(...) and event(...). An expression the game cannot evaluate stops the rest of that patch file (the log says XML loader: Patching 'file' from mod 'Name' failed), so test a conditional on a throwaway server first.
include - split a patch filePulls in another patch file, named relative to the file that contains the include, and applies its commands in place. Useful to keep a large items.xml patch in readable pieces.
<include filename="items_weapons.xml" />
The command is the verb; the XPath is the address. Ninety percent of modding is writing an XPath that selects exactly the node you mean and nothing else. The pieces:
| Pattern | Selects |
|---|---|
/items/item | every <item> directly under <items> |
/items/item//property | <property> at any depth under an item (note the double slash) |
/items/item/@name | the name attribute of those items |
[@name='resourceWood'] | only the node whose name equals that (a predicate) |
[@value > 2] / [@value < 4] | numeric comparison - write > / < inside the XML |
[@name='x' or @name='y'] | logical OR; and and not(...) work too |
[starts-with(@name,'gun')] | string match - also ends-with and contains |
[1] / [last()] | the first / last matching sibling by position |
[@category] | nodes that simply have a category attribute |
/.. | step up to the parent node |
Combine them freely: /items/item[contains(@name,'gun') and not(@name='gunHandgunT1Pistol')]/property[@name='Magazine_size']/@value selects the magazine size of every gun except that one pistol.
Here is a single Config/items.xml that uses three commands together - the kind of small, real modlet you will write constantly:
<configs>
<!-- bump every stone tool's durability -->
<set xpath="/items/item[starts-with(@name,'meleeToolStone')]/property[@name='DegradationMax']/@value">1000</set>
<!-- give the stone axe a new tag -->
<append xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='Tags']/@value">,reinforced</append>
<!-- strip the perk requirement off the wrench -->
<remove xpath="/items/item[@name='meleeToolRepairT1Wrench']/property[@name='UnlockedBy']" />
</configs>
You do not have to relaunch and play to verify XPath. Two faster loops:
set) or a clear error; a malformed file logs a red XML error with the line number. Watch the startup log first, every time.Data/Config/items.xml (and blocks.xml, recipes.xml...) and search for the exact name before you write the xpath. Most "my mod did nothing" cases are a misremembered name, and these files are the only source of truth.set vs setattribute. set only edits attributes that already exist; to create a new attribute use setattribute, to add a whole node use append.< or > inside an xpath breaks the XML. Always write < and >./items/item hits every item in the game. Add a predicate, or you will edit thousands of things and wonder why balance feels off. Test broad selectors against vanilla first.Patch type (naem) unknown, skips that command and loads the rest, so read the log after every restart rather than trusting the mod list.set the same attribute, the one that loads later wins. Kata 8 covers controlling that.Next: Kata 3 - Add an Item, Recipe & Localization. You can now edit, add, and remove. Next you combine append across items.xml and recipes.xml with a Localization entry to ship a genuinely new, craftable, properly-named item.