Editing Modding Tutorials/PatchOperations
Jump to navigation
Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
− | |||
{{BackToTutorials}} | {{BackToTutorials}} | ||
+ | {{stub}} | ||
− | + | RimWorld Alpha 17 added a new modding feature: '''XML PatchOperations'''. Using these allows mods to edit specific elements of XML defs, rather than simply overwriting the old def with a new one, which was the required approach until A17. This greatly reduces mod conflicts, because mods that make separate changes to the same def won't necessarily overwrite one another's changes. Mods using PatchOperations can avoid requiring special compatibility mods, and can even add special features conditional on other mods being loaded. | |
− | + | Here's a simple example of replacing the texture path for deep water: | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
<source lang="xml"> | <source lang="xml"> | ||
− | <?xml version="1.0" encoding="utf-8"?> | + | <?xml version="1.0" encoding="utf-8" ?> |
<Patch> | <Patch> | ||
− | + | <Operation Class="PatchOperationReplace"> | |
− | < | + | <xpath>Defs/TerrainDef[defName="WaterDeep"]/texturePath</xpath> |
− | + | <value> | |
+ | <texturePath>Your/Texture/Path/Here</texturePath> | ||
+ | </value> | ||
+ | </Operation> | ||
</Patch> | </Patch> | ||
</source> | </source> | ||
+ | This xml file simply goes inside YourMod/Patches/ and you're done. | ||
− | == | + | == Overview of available PatchOperations == |
− | + | These are the available PatchOperation types: | |
− | + | * Four do basic operations on XML nodes: | |
+ | ** '''[[#PatchOperationAdd|PatchOperationAdd]]''' adds a provided child node to the selected node | ||
+ | ** '''[[#PatchOperationInsert|PatchOperationInsert]]''' adds a provided sibling node to the selected node | ||
+ | ** '''[[#PatchOperationRemove|PatchOperationRemove]]''' deletes the selected node | ||
+ | ** '''[[#PatchOperationReplace|PatchOperationReplace]]''' replaces the selected node with the provided node | ||
+ | * Three do basic operations on XML attributes: | ||
+ | ** '''[[#PatchOperationAttributeAdd|PatchOperationAttributeAdd]]''' adds a provided attribute to the selected node if and only if the attribute name is not already present | ||
+ | ** '''[[#PatchOperationAttributeSet|PatchOperationAttributeSet]]''' sets a provided attribute for the selected node, overwriting the attribute value if the attribute name is already present | ||
+ | ** '''[[#PatchOperationAttributeRemove|PatchOperationAttributeRemove]]''' removes an attribute for the selected node | ||
+ | * Three allow for more complex operations: | ||
+ | ** '''[[#PatchOperationAddModExtension|PatchOperationAddModExtension]]''' adds a ModExtension. | ||
+ | ** '''[[#PatchOperationSetName|PatchOperationSetName]]''' changes the name of a node. | ||
+ | ** '''[[#PatchOperationSequence|PatchOperationSequence]]''' contains a set of other PatchOperations, and aborts upon any operation failing | ||
+ | * Three allow for conditional operations | ||
+ | ** '''[[#PatchOperationTest|PatchOperationTest]]''' tests nodes, which is useful inside a PatchOperationSequence | ||
+ | ** '''[[#PatchOperationConditional|PatchOperationConditional]]''' tests nodes, and can do different operations depending on the result. | ||
+ | ** '''[[#PatchOperationFindMod|PatchOperationFindMod]]''' tests for the presence of another mod, and can do different operations depending on the result. | ||
− | + | ==XPath syntax== | |
+ | Each PatchOperation must specify an XML node to modify. It uses XPaths to specify them. An XPath is a "path" for the patch to follow when trying to find XML nodes matching the description. It will follow each part of the path from left to right. Note that these "paths" have zero relation to the file path or folder structure: They follow the structure of the XML nodes. | ||
− | + | XPaths start at the root node. Since the root node of all Defs is enforced to be <Defs>, so <code>Defs/</code> is the start of our xpath. <code>*/</code> is also valid, as it uses the <code>*</code> wildcard: <code>*</code> matches any element, so it'll match the root (the top level) of the XML tree. <code>//</code> is technically also valid, but because that construct selects ''all'' the elements in the XML tree, it's an expensive operation that makes game loading exponentially slower. | |
− | |||
− | + | Once the root is selected, the XPath lets the system walk down specific branches of the tree. If we use the example from the lead, we get a specific path: | |
− | + | <code>Defs/TerrainDef[defName="WaterDeep"]/texturePath</code> | |
− | + | # The root node is selected | |
+ | # All child nodes of the root node called "TerrainDef" are selected | ||
+ | # We narrow down from "all TerrainDefs" to only those with the child "defName" node whose value is "WaterDeep", which should give us exactly one node because defNames must be unique | ||
+ | # We select the child node "texturePath" from this node | ||
− | + | ==Overview of individual PatchOperations== | |
+ | (to do) | ||
+ | ===PatchOperationAdd=== | ||
− | + | {| class="wikitable" style="margin-left: auto; margin-right: auto;" | |
− | + | ! Def before patch !! Patch operation !! Def after patch | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | | <source lang="xml"> | + | | style="vertical-align: top;" |<source lang="xml"> |
− | <ExampleDef> | + | <Defs> |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | </ExampleDef> | + | <exampleNode>Some text</exampleNode> |
+ | <exampleList /> | ||
+ | </ExampleDef> | ||
+ | </Defs> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
<Operation Class="PatchOperationAdd"> | <Operation Class="PatchOperationAdd"> | ||
− | + | <xpath>*/ExampleDef[defName="Example"]/exampleList</xpath> | |
− | + | <value> | |
− | + | <li>Foo</li> | |
− | + | <li>Bar</li> | |
− | </Operation> | + | </value> |
+ | </Operation> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
− | + | <Defs> | |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <exampleNode>Some text</exampleNode> | |
− | + | <exampleList> | |
− | + | <li>Foo</li> | |
− | + | <li>Bar</li> | |
− | | <source lang="xml"> | + | </exampleList> |
− | < | + | </ExampleDef> |
− | + | </Defs> | |
− | |||
− | < | ||
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
|- | |- | ||
|} | |} | ||
− | |||
− | ==PatchOperationInsert== | + | ===PatchOperationInsert=== |
− | |||
− | + | {| class="wikitable" style="margin-left: auto; margin-right: auto;" | |
− | + | ! Def before patch !! Patch operation !! Def after patch | |
− | ! | ||
|- | |- | ||
− | | <source lang="xml"> | + | | style="vertical-align: top;" |<source lang="xml"> |
− | < | + | <Defs> |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | < | + | <exampleNode>Some text</exampleNode> |
− | + | <exampleList /> | |
− | + | </ExampleDef> | |
− | + | </Defs> | |
− | |||
− | |||
− | </ | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
<Operation Class="PatchOperationInsert"> | <Operation Class="PatchOperationInsert"> | ||
− | + | <xpath>*/ExampleDef[defName="Example"]/exampleNode</xpath> | |
− | + | <value> | |
− | + | <anotherExample>A new sibling</anotherExample> | |
− | + | </value> | |
</Operation> | </Operation> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
− | + | <Defs> | |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <exampleNode>Some text</exampleNode> | |
− | + | <anotherExample>A new sibling</anotherExample> | |
− | + | <exampleList /> | |
− | + | </ExampleDef> | |
− | + | </Defs> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | <ExampleDef> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
|- | |- | ||
|} | |} | ||
− | |||
− | |||
− | |||
− | + | ===PatchOperationRemove=== | |
− | {| class=" | + | |
− | ! | + | {| class="wikitable" style="margin-left: auto; margin-right: auto;" |
+ | ! Def before patch !! Patch operation !! Def after patch | ||
|- | |- | ||
− | | <source lang="xml"> | + | | style="vertical-align: top;" |<source lang="xml"> |
− | <ExampleDef> | + | <Defs> |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <exampleNode>Some text</exampleNode> | |
− | + | <exampleList /> | |
− | </ | + | </ExampleDef> |
+ | </Defs> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
<Operation Class="PatchOperationRemove"> | <Operation Class="PatchOperationRemove"> | ||
− | + | <xpath>*/ExampleDef[defName="Example"]/exampleNode</xpath> | |
</Operation> | </Operation> | ||
</source> | </source> | ||
− | | <source lang="xml"> | + | | style="vertical-align: top;" |<source lang="xml"> |
− | <ExampleDef> | + | <Defs> |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <exampleList /> | |
− | </ | + | </ExampleDef> |
+ | </Defs> | ||
</source> | </source> | ||
|- | |- | ||
|} | |} | ||
− | |||
− | ==PatchOperationReplace== | + | ===PatchOperationReplace=== |
− | |||
− | + | {| class="wikitable" style="margin-left: auto; margin-right: auto;" | |
− | + | ! Def before patch !! Patch operation !! Def after patch | |
− | ! | ||
|- | |- | ||
− | | <source lang="xml"> | + | | style="vertical-align: top;" |<source lang="xml"> |
− | <ExampleDef> | + | <Defs> |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <exampleNode>Some text</exampleNode> | |
− | + | <exampleList /> | |
− | </ | + | </ExampleDef> |
+ | </Defs> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
<Operation Class="PatchOperationReplace"> | <Operation Class="PatchOperationReplace"> | ||
− | + | <xpath>*/ExampleDef[defName="Example"]/exampleNode</xpath> | |
− | + | <value> | |
− | < | + | <anotherExample>An alternate node</anotherExample> |
− | + | </value> | |
− | < | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</Operation> | </Operation> | ||
</source> | </source> | ||
− | | | + | | style="vertical-align: top;" |<source lang="xml"> |
− | + | <Defs> | |
− | + | <ExampleDef> | |
− | + | <defName>Example</defName> | |
− | + | <anotherExample>An alternate node</anotherExample> | |
− | + | <exampleList /> | |
− | + | </ExampleDef> | |
− | + | </Defs> | |
− | |||
− | |||
− | | <source lang="xml"> | ||
− | < | ||
− | |||
− | |||
− | |||
− | < | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
|- | |- | ||
|} | |} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ===PatchOperationAttributeAdd=== | |
− | + | ===PatchOperationAttributeSet=== | |
− | + | ===PatchOperationAttributeRemove=== | |
− | + | ===PatchOperationAddModExtension=== | |
− | + | ===PatchOperationSetName=== | |
− | == | + | ===PatchOperationSequence=== |
− | + | ===PatchOperationTest=== | |
− | + | ===PatchOperationConditional=== | |
− | + | ===PatchOperationFindMod=== | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | == Resources == |
− | + | The best tutorial on PatchOperations created by Zhentar: [https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782 Introduction to PatchOperation] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | You can also learn about XPaths here: [https://www.w3schools.com/xml/xpath_intro.asp XPath tutorial] | |
− | + | There is also an [https://github.com/roxxploxx/RimWorldModGuide/wiki/SHORTTUTORIAL:-DefPatches Overview of PatchOperations] on the [https://github.com/roxxploxx/RimWorldModGuide/wiki RimWorldModGuide]. | |
− | |||
[[Category:Modding]] | [[Category:Modding]] | ||
− |