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:
{{DISPLAYTITLE:PatchOperations}}
 
 
{{BackToTutorials}}
 
{{BackToTutorials}}
  
Line 21: Line 20:
 
</source>
 
</source>
  
Just as with XML Defs, folder and file names do not matter and you can freely name and organize your patch files in whatever manner you wish. Individual patches themselves are a standard XML file with <tt><Patch></tt> as the root tag:
+
Just as with XML Defs, folder and file names do not matter and you can freely name and organize your patche files in whatever manner you wish. Individual patches themselves are a standard XML file with <tt><Patch></tt> as the root tag:
  
 
<source lang="xml">
 
<source lang="xml">
Line 41: Line 40:
 
* The first segment of any XPath targeting an XML Def will be <code>Defs/</code> as all XML Defs use the <code><Defs></code> root tag.
 
* The first segment of any XPath targeting an XML Def will be <code>Defs/</code> as all XML Defs use the <code><Defs></code> root tag.
 
* The square brackets denote a predicate, or conditional match. In this case, we are looking for <code>ThingDef</code>s that have a child tag <code>defName</code> equal to "Wall".
 
* The square brackets denote a predicate, or conditional match. In this case, we are looking for <code>ThingDef</code>s that have a child tag <code>defName</code> equal to "Wall".
 
=== Targeting Attributes ===
 
  
 
You can target Defs that do not have a <code>defName</code> (such as abstract bases) by targeting their identifying attributes. For example, if you wanted to add another Stuff category to the abstract base Def for all shelves, you might use the following xpath:
 
You can target Defs that do not have a <code>defName</code> (such as abstract bases) by targeting their identifying attributes. For example, if you wanted to add another Stuff category to the abstract base Def for all shelves, you might use the following xpath:
Line 48: Line 45:
 
<code>Defs/ThingDef[@Name="ShelfBase"]/stuffCategories</code>
 
<code>Defs/ThingDef[@Name="ShelfBase"]/stuffCategories</code>
  
You can use the same technique to target all Defs that inherit from a common base. For example, you could use the following xpath to target all <code>ThingDef</code>s that inherit from <code>ApparelBase</code>:
+
Additional XPath resources:
 
 
<code>Defs/ThingDef[@ParentName="ApparelBase"]</code>
 
 
 
=== Additional XPath Resources ===
 
 
 
 
* [https://developer.mozilla.org/en-US/docs/Web/XPath Mozilla Developer Network]
 
* [https://developer.mozilla.org/en-US/docs/Web/XPath Mozilla Developer Network]
 
* [https://www.w3schools.com/xml/xml_xpath.asp W3Schools XPath Tutorial]
 
* [https://www.w3schools.com/xml/xml_xpath.asp W3Schools XPath Tutorial]
Line 100: Line 92:
  
 
==PatchOperationAdd==
 
==PatchOperationAdd==
Inserts the specified <code>value</code>s as a child node of the XML nodes targeted by the operation's <code>xpath</code>. By default, the new nodes will be inserted after any existing child nodes (<code>Append</code>). You can use <code><order>Prepend</order></code> in the patch operation to insert them before existing child nodes instead.
+
Inserts the specified <code>value</code>s as a child node of the XML nodes targeted by the operation's <code>xpath</code>. By default, the new nodes will be inserted after (appended to) any existing child nodes. You can use <code><order>Prepend</order></code> in the patch operation (order is Append by default).
  
 
Note: PatchOperationAdd will not overwrite any existing tags. If one of your <code>value</code>s overlaps with an existing node and you are not targeting a list node, then it will cause an error on game load.
 
Note: PatchOperationAdd will not overwrite any existing tags. If one of your <code>value</code>s overlaps with an existing node and you are not targeting a list node, then it will cause an error on game load.
Line 423: Line 415:
 
   <value>
 
   <value>
 
     <li Class="MyNamespace.MyModExtension">
 
     <li Class="MyNamespace.MyModExtension">
       <key>Value</key>
+
       <key>Value</exampleValue>
 
     </li>
 
     </li>
 
   </value>
 
   </value>
Line 436: Line 428:
 
   <modExtensions>
 
   <modExtensions>
 
     <li Class="MyNamespace.MyModExtension">
 
     <li Class="MyNamespace.MyModExtension">
       <key>Value</key>
+
       <key>Value</exampleValue>
 
     </li>
 
     </li>
 
   </modExtensions>
 
   </modExtensions>
Line 528: Line 520:
 
</source>
 
</source>
  
As mentioned, you can use [[Modding_Tutorials/MayRequire|MayRequire]] on child operations of a PatchOperationSequence, but you should test them individually before adding them to said Sequence:
+
As mentioned, you can use {{Modding_Tutorials/MayRequire}} on child operations of a PatchOperationSequence, but you should test them individually before adding them to said Sequence:
  
 
<source lang="xml">
 
<source lang="xml">
Line 534: Line 526:
 
   <operations>
 
   <operations>
 
     <li Class="PatchOperationAdd" MayRequire="Ludeon.Rimworld.Biotech"> <!-- Only runs if Biotech is active -->
 
     <li Class="PatchOperationAdd" MayRequire="Ludeon.Rimworld.Biotech"> <!-- Only runs if Biotech is active -->
       <xpath>Defs/ThingDef[defName="MechGestator"]/recipes</xpath>
+
       <xpath>Defs/ThingDef[defName="MechGestator"]/recipes<xpath>
 
       <value>
 
       <value>
 
         <li>MyCustomMech</li>
 
         <li>MyCustomMech</li>
Line 554: Line 546:
  
 
'''WARNING''': Unlike all other mod-compatibility features in RimWorld, PatchOperationFindMod uses the mod ''name'' and not its <code>packageId</code>.
 
'''WARNING''': Unlike all other mod-compatibility features in RimWorld, PatchOperationFindMod uses the mod ''name'' and not its <code>packageId</code>.
 
'''NOTE''': For expansions, PatchOperationFindMod uses the <code>label</code> value defined in the <code>ExpansionDef</code> for the DLC.  At present, this means they are identified by just their single word names: Royalty, Ideology, Biotech, Anomaly.
 
 
'''NOTE''': PatchOperationFindMod should only be used if you are implementing ''optional'' compatibility for the target mod, i.e. if your mod can work with or without the mod in question. If you are creating a compatibility mod specifically for a target mod that would be meaningless without that mod present, then it's better to simply specify that mod in your About.xml as a dependency and forgo the use of PatchOperationFindMod and avoid the potential issues introduced by using PatchOperationSequence.
 
  
 
The following example adds a mod extension to the targeted Defs if RimQuest is loaded ([https://github.com/Mehni/MoreFactionInteraction/blob/ab3ab2a22ee529ee4e38a471fe150fd48fd07ce9/Patches/MoreFactionInteraction.xml#L64 See original]):
 
The following example adds a mod extension to the targeted Defs if RimQuest is loaded ([https://github.com/Mehni/MoreFactionInteraction/blob/ab3ab2a22ee529ee4e38a471fe150fd48fd07ce9/Patches/MoreFactionInteraction.xml#L64 See original]):
Line 661: Line 649:
  
 
A tutorial for this process does not exist yet, but you can check out the following references of custom PatchOperations:
 
A tutorial for this process does not exist yet, but you can check out the following references of custom PatchOperations:
* [https://github.com/15adhami/XmlExtensions XML Extensions] - An entire framework mod containing many useful custom PatchOperations.
+
9 [https://github.com/15adhami/XmlExtensions XML Extensions] - An entire framework mod containing many useful custom PatchOperations.
* [https://github.com/CombatExtended-Continued/CombatExtended/blob/Development/Source/CombatExtended/CombatExtended/PatchOperationMakeGunCECompatible.cs PatchOperationMakeGunCECompatible] - Used by Combat Extended to automatically apply multiple changes to a single firearm for compatibility.
+
- [https://github.com/CombatExtended-Continued/CombatExtended/blob/Development/Source/CombatExtended/CombatExtended/PatchOperationMakeGunCECompatible.cs PatchOperationMakeGunCECompatible] - Used by Combat Extended to automatically apply multiple changes to a single firearm for compatibility.
* [https://gist.github.com/Lanilor/e326e33e268e78f68a2f5cd3cdbbe8c0 PatchOperationAddOrReplace] - An example of a custom variant of PatchOperationAdd that replaces an existing value.</br>
+
- [https://gist.github.com/Lanilor/e326e33e268e78f68a2f5cd3cdbbe8c0 PatchOperationAddOrReplace] - An example of a custom variant of PatchOperationAdd that replaces an existing value.</br>
  
 
== "Success" Option ==
 
== "Success" Option ==
Line 674: Line 662:
 
* Always - This patch operation always succeeds, i.e. it suppresses all errors that might have occurred. This used to be used in PatchOperationSequence along with PatchOperationTest in order to conditionally run patches, but is now obsolete.
 
* Always - This patch operation always succeeds, i.e. it suppresses all errors that might have occurred. This used to be used in PatchOperationSequence along with PatchOperationTest in order to conditionally run patches, but is now obsolete.
 
* Normal - Errors are handled normally
 
* Normal - Errors are handled normally
* Invert - Errors are considered a success and success is considered a failure. This used to be used in PatchOperationSequences to test the negative of a PatchOperationTest; you should now use <code><nomatch></code> on PatchOperationConditional.
+
* Invert - Errors are considered a success and success is considered a failure. This used to be used in PatchOperationSequences to test the negative of a PatchOperationTest; you should now use <code><nomatch></code> on PatchOperationConditional
 
* Never - This patch operation always fails. Generally only used in testing to see if a Sequence is working correctly, should never be used in published mods.
 
* Never - This patch operation always fails. Generally only used in testing to see if a Sequence is working correctly, should never be used in published mods.
 
=== Extenuating circumstances for "Success" ===
 
There are, in very specific circumstances, a valid reason to use a <code><success>Always</success></code> statement.
 
 
For instance, consider the following opening lines for a Patch: <code>
 
<Operation Class="PatchOperationConditional">
 
<xpath>/Defs/JoyKindDef[defName="Sierra_Drinking_Milkshake"]</xpath>
 
<match Class="PatchOperationReplace">
 
<success">Always</success>
 
<xpath>/Defs/ThingDef[defName = "Laban" or defName = "AmbrosiaLaban" or defName = "ChocolateLaban" or defName = "StrawberryLaban" or defName = "MedicinalLaban"]/ingestible/joyKind</xpath>
 
<value>
 
<joyKind>Sierra_Drinking_Milkshake</joyKind>
 
</value>
 
</match>
 
</Operation>
 
</code>
 
 
This Patch detects if a specific Mod's Joy Kind Def exists and, if it does, changes the Recreation Type received by consuming a Thing Def from another Mod; the Patch exists in neither Mod's folder, coming from a third-party Mod that is completely separate.
 
 
"Sierra Drinking Milkshake" (<code>"Sierra_Drinking_Milkshake"</code>) is added by the [https://steamcommunity.com/sharedfiles/filedetails/?id=2595980371 Milkshake Digital Deluxe Mod], and Laban (<code>"Laban"</code>) is added by the [https://steamcommunity.com/sharedfiles/filedetails/?id=2595938070 Laban Mod].
 
 
Now, imagine that neither the author of the Laban Mod or the Milkshake Mod created this Patch. Instead, a fan of both Mods included this in a compilation of Patches that alters dozens of Mods.
 
 
This Patch is in a third-party Mod that is neither of the constituent Mods that it patches. If a player had the Milkshake Mod loaded loaded, but ''did not'' have the Laban Mod, this Patch would attempt to to change the Joy Kind Def of consuming Laban to something that does not exist, and would cause the Laban Thing Def to cause errors when consumed, ''and'' cause the Patch to fail.
 
 
Therefore, because a large third-party Patch has to patch two Mods that it is not integrated with directly, and uploading a single Patch as a single Mod versus a compilation is inefficient, then it must be concluded that using "<code><success>Always</success></code>" '''''is acceptable in this extenuating circumstance'''''.
 
 
Outside of situations like this, using the "Success" statement is still not recommended.
 
  
 
== Tips and Tricks ==
 
== Tips and Tricks ==
Line 728: Line 688:
 
* It's very easy to confuse Insert vs Add; Insert will "add" the <code>value</code> as a ''sibling'' of the target node(s), while Add will "insert" the <code>value</code> as a ''child'' of the target node(s).
 
* It's very easy to confuse Insert vs Add; Insert will "add" the <code>value</code> as a ''sibling'' of the target node(s), while Add will "insert" the <code>value</code> as a ''child'' of the target node(s).
 
* Remember that XPath targets the XML data structure, not the file path.
 
* Remember that XPath targets the XML data structure, not the file path.
* Nodes in XML other than <code>li</code> list items must be unique at each level. If you Add or Insert a duplicate node, that will generate a red error on load and cause that Def to fail to load.
 
 
* If you're still stumped, feel free to join the [https://discord.gg/RimWorld RimWorld Discord server] and ask questions in the <code>#mod-development</code> channel.
 
* If you're still stumped, feel free to join the [https://discord.gg/RimWorld RimWorld Discord server] and ask questions in the <code>#mod-development</code> channel.
  

Please note that all contributions to RimWorld Wiki are considered to be released under the CC BY-SA 3.0 (see RimWorld Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

Cancel Editing help (opens in new window)