Ludeon Forums

RimWorld => Mods => Help => Topic started by: minimurgle on May 24, 2017, 08:27:11 PM

Title: A quick tutorial of xpathing and patching
Post by: minimurgle on May 24, 2017, 08:27:11 PM
With the A17 update we have a wonderful new patching feature to help with mod compatability. It looks to be a brilliant idea, but it requires xpathing. This may be a new idea to some people. I know it was to me.

https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782 (https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782) Zhentar's guide on patching is helpful, but it doesn't tell us how xpathing works and only gives us a few examples. So I'll give a few more examples here, and explain xpathing.

If you are like me you had no idea what xpathing was. Well I have good news, it's actually pretty simple! You can think of it like selecting a path for a texture, or any other folder path. Here's an example:

If you wanted to use a custom texture for your custom gun you would do:
Code: [Select]
<texPath>Weapons/Ranged/CustomGun</texPath>Well that's how you'd do it for selecting a texture, but what about xpaths?

Let's say you wanted to change the warm up of the pistol from 0.3 to 5.2. We shouldn't be editing the defs if we can patch it in, so how would we do it? Well if we want to change the warm up of the pistol we can use the class "PatchOperationReplace". Which as the name suggests we can use to replace something, it looks like this
Code: [Select]
<Patch>
<Operation Class="PatchOperationReplace">
    <xpath>/ThingDefs/ThingDef[defName = "Gun_Pistol"]/verbs/li/warmupTime</xpath>
    <value>
                <WarmupTime>5.2</WarmupTime>
    </value>
</Operation>
</Patch>
This code goes down the designated xpath until it finds the pistols warm up time. It then replaces it with the set value.

Now let me explain exactly how the xpath works. First of all, everything in the xml could be described as a node.
<ThingDef> is a node and so is <defName>, <warmupTime>, <verbs>, and <description>. Every different tag you see is a node. All xpathing is, is just inputting the correct sequence of nodes.



We start with /ThingDefs, you may be wondering what the slash at the beginning means. This selects all root nodes with that name. It is the beginning of the thingdefs for the gun so it is the beginning of our xpath

Next is /Thingdef. This specifies what we want to grab from the thingdefs. But /ThingDef is grabbing every <ThingDef> it can find. This is why we narrow it down with the next part.

Alternitively we could have done //ThingDef, but this is less optimized and slows down the patching process because it selects the root node and all it's children.

After /ThingDef we attach the defname, so it looks like this /ThingDef[defName = "Gun_Pistol". Now instead of trying to search everything with the <ThingDef> tag, it will only look for the one with the <defName> tag of Gun_Pistol.

We have now told the code to look for the correct ThingDef, but it doesn't know where warmupTime is. So we add more nodes to the xpath, now it's /ThingDef[defName = "Gun_Pistol"]/verbs.

The single slash here looks for all the children of our ThingDef for the pistol named "verbs".

If you look at the code for the pistol you'll see that <warmupTime> is indeed under the verbs, but it's nestled in the <li> tag. Our xpath doesn't know this, so we'll just get errors or replace the verbs tag with <warmupTime>, which will cause errors.

So now we add "li" to our path so it looks like this //ThingDef[defName = "Gun_Pistol"]/verbs/li. You might think this is the end, but we still haven't directed it to the correct place. Now it's gonna replace "li" which will cause errors.

So we want to go one step further and make it /ThingDef[defName = "Gun_Pistol"]/verbs/li/warmupTime. Now our code is looking for the ThingDef named Gun_Pistol, then it looks for any children of that def called verbs. After that any children of verbs called "li", and then any children of li called "warmupTime".

That will finally replace the pistols warm up time.


But what if there were more than one child named "li", like in the hediff for blood loss. Then we could do this
Code: [Select]
<Patch>
<Operation Class="PatchOperationReplace">
   <xpath>/Defs/HediffDef[defName = "BloodLoss"]/stages/li[2]/capMods/li/offset</xpath>
   <value>
               <offset>-0.15</offset>
   </value>
</Operation>
</Patch>


This code will look for the HediffDef named "BloodLoss", it'll then look for a child named stages. Stages has multiple <li> children so I've specified that I want it to look for the second <li> tag. Then once its found the second <li> tag it'll follow the path just like it did with the pistol.


Of course you can have multiple operations in the same patch too. There's also more PatchOperations than just replace. You should check out Zhentar's Guide for those.

If you want more information about the xpath syntax I'd recommend going here: https://www.w3schools.com/xml/xpath_syntax.asp
Here's a tool to help you figure out the xpath: http://xmltoolbox.appspot.com/xpath_generator.html



I hope this helps anyone who had trouble with it.



Thanks to Shinzy and kaptain_kavern for pointing out some optimizations, and thanks to NoImageAvalible for showing the right way to use the optmizations.
Title: Re: A quick tutorial of xpathing and patching
Post by: 123nick on May 24, 2017, 08:51:03 PM
this is a GREAT Guide! now so many people can use the absolutely LIMITLESS power of xpathing and patching to make their mods amazing! thanks minimurgs  :-*
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on May 24, 2017, 09:13:35 PM
Many thanks for writing this
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on May 24, 2017, 09:20:16 PM
Many thanks forme writing this

Of course. I figured I couldn't be the only one who didn't know how xpath worked and wanted to make it easier for anyone to learn.
Title: Re: A quick tutorial of xpathing and patching
Post by: Ramsis on May 24, 2017, 11:03:38 PM
I stickied the thread. This is just the kind of thing that makes our community amazing.
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on May 25, 2017, 12:50:29 AM
thank you Ramsis  8)
Title: Re: A quick tutorial of xpathing and patching
Post by: Shinzy on May 26, 2017, 11:47:59 AM
As of very recent findings (Skully will possibly clarify) but when you use xpath and start from the very root of a def,
instead of //blahblah/blah/bluhh use /blahblah/blah/bluhh

as this is much faster when loading the patching stuff, okay? okay!
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on May 26, 2017, 11:55:50 AM

USEFUL TOOL :


http://xmltoolbox.appspot.com/xpath_generator.html
Title: Re: A quick tutorial of xpathing and patching
Post by: Shinzy on May 26, 2017, 12:01:09 PM

LESS USEFUL TOOL :


https://ludeon.com/forums/index.php?action=profile;u=13346 (https://ludeon.com/forums/index.php?action=profile;u=13346)
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on May 26, 2017, 12:02:58 PM
;D ;D ;D ;D


When targeting particular node you should always try to be the most precise as possible. Imagine your doing a google search or search for a file in your computer. The more you are precise, the more the search will be quick and efficient.

Here it is the same.

Code: [Select]
<xpath>//ThingDef[defName = "Gun_Pistol"]</xpath>is searching in every nodes! Even child nodes !
So it will be longer and take more computer resources

Whereas
Code: [Select]
<xpath>/ThingDefs/ThingDef[defName = "Gun_Pistol"]</xpath> is searching only in parents nodes


From here (https://www.w3schools.com/xml/xpath_syntax.asp)
(http://i.imgur.com/XQ9BDyT.png?1)

There also is a nice quick tuto (https://www.w3schools.com/xml/xpath_intro.asp)
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on May 26, 2017, 12:46:01 PM
Thanks for all the info. I'll update all the information above to reflect this.
Title: Re: A quick tutorial of xpathing and patching
Post by: NoImageAvailable on May 26, 2017, 02:21:31 PM
Whereas
Code: [Select]
<xpath>/ThingDef[defName = "Gun_Pistol"]</xpath> is searching only in parents nodes

The above code would actually return an error. You need to target the root node of the file, which for Weapons_Guns.xml is <ThingDefs>. So you'd need to use either
Code: [Select]
<xpath>/ThingDefs/ThingDef[defName = "Gun_Pistol"]</xpath>or
Code: [Select]
<xpath>*/ThingDef[defName = "Gun_Pistol"]</xpath>
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on May 26, 2017, 02:24:48 PM
I was going back here to correct after testing my wrong assertion. I'll correct it ASAP It is corrected above.

Thanks for taking the time for correcting me.
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on May 26, 2017, 02:42:50 PM
Oh fun more corrections
Title: Re: A quick tutorial of xpathing and patching
Post by: benniii on May 27, 2017, 12:34:23 PM
Hi,

Is it possible to use the patching-method to change things added from other mods? I did read somewhere that this process is used before adding the mods.

Just for clarification
Title: Re: A quick tutorial of xpathing and patching
Post by: Shinzy on May 27, 2017, 01:00:23 PM
Hi,

Is it possible to use the patching-method to change things added from other mods? I did read somewhere that this process is used before adding the mods.

Just for clarification

It is possible yes, all the defs are loaded first (including mods), then the xpath patching happens after all that

so yes you can modify modded defs too. Works really well for things like compatibility patches etc
Title: Re: A quick tutorial of xpathing and patching
Post by: benniii on May 27, 2017, 01:17:31 PM
Hm, so it is. Is there an example out there? It might be possible that i do something wrong. I tried like several hours yesterday and just came to the conclusion that this might not work, lol.

If i change the defName here to "HorseshoesPin" the description would change, but with added items from mods it does not. And i'm loading my mod at the very end after them. So where would be the secret behind that? Thanks for answering and sorry if it doesn't fit in this topic.

Code: [Select]
<Patch>
  <Operation Class="PatchOperationReplace">
    <xpath>*/ThingDef[defName = "PowerConduitInvisible"]/description</xpath>
    <value>
      <description>This is just a test.</description>
    </value>
  </Operation>
</Patch>
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on May 27, 2017, 01:59:02 PM
Hi Benni. While it is possible to use this process to change other mods you should have permission from the mod author first unless it's for your own personal use. If it is uploaded and you got permission from the author of the mod that your changing you should make it very clear that you've changed stuff from the other mod.

The only other things I can tell you from my experience is that your mod needs to be loaded after the other mod. You can also put <success>Always</success> to suppress errors if the other mod isn't present. (that could be wrong but it's something like that)

Just a warning it would appear that people are having trouble getting this to work all the time.
Title: Re: A quick tutorial of xpathing and patching
Post by: benniii on May 27, 2017, 04:05:23 PM
Hey.

Thanks for your concern but don't worry that's for personal use only. I'm more the introvert lurking guy here, i don't plan to publish anything. ^^

I just did some other testings and it does indeed work with other values. Replacing description or label doesn't work so far. I did start testing with these thats why i was questioning it. Kinda wondering why though. But im set now, so thanks for the tip and answering. :)

Edit: I figured out why i couldn't replace description or label. It is because of the provided languages files.
Title: Re: A quick tutorial of xpathing and patching
Post by: Vindar on May 27, 2017, 06:31:19 PM
Lmao, I gotta be honest, I started learning it yesterday and I'm already falling in love w/ xpathing.

some of the things ive learned that might be helpful for people just starting it here w/ the intent to use in rimworld.

1) not all things start w/ ThingDefs, some items start w/ Buildings, ect

2) be very specific and check both the spelling and the capitalization, if its capitalized differently in the core xml, xpath wont read it and will spit out a fail.

3) start the document with the XML header:

<?xml version="1.0" encoding="utf-8" ?>

Save as an XML

Use:

<Patch>   and </Patch> to open and close the document (placed after the header)

3 might seem simple but it was the first question i asked myself anyways

====================================================
 
to help people along ill post some examples of operations that i have working in my mod(still being worked on):

================Simple replace operation=============================

<!-- Change Basic Shirt Worn Graphic -->
   <Operation Class="PatchOperationReplace">
      <xpath>/ThingDefs/ThingDef[defName = "Apparel_BasicShirt"]/apparel/worngraphicPath</xpath>
      <value>
         <worngraphicPath>Things/Pawn/Humanlike/Apparel/Bodywear_Clothing/TeeShirt/TeeShirt</worngraphicPath>
      </value>
   </Operation>

=======================Simple Add Operation====================================

<!-- Change Basic Pants Worn Graphic -->
   <Operation Class="PatchOperationAdd">
      <xpath>/ThingDefs/ThingDef[defName = "Apparel_Pants"]/apparel</xpath>
      <value>
         <worngraphicPath>Things/Pawn/Humanlike/Apparel/Bodywear_Clothing/Pants/Pants</worngraphicPath>   
      </value>
   </Operation>

==================A replace Operation which starts at Buildings as opposed to ThingDefs=========

<!-- Coal to Fueled Generator -->
   <Operation Class="PatchOperationReplace">
      <xpath>/Buildings/ThingDef[defName = "FueledGenerator"]/description</xpath>
      <value>
         <description>Produces power by consuming wood fuel or coal. Must be fueled by hand.</description>   
      </value>
   </Operation>

==========An operation that had me confused for a while. (needs DefName as oppsed to defName)======
==============Note i also used: li[@Class = "CompProperties_Refuelable"] =========

<!-- Coal to Fueled Smithy -->   
   <Operation Class="PatchOperationAdd">
       <xpath>/ThingDefs/ThingDef[DefName = "FueledSmithy"]/comps/li[@Class = "CompProperties_Refuelable"]/fuelFilter/thingDefs</xpath>
       <value>
             <li>MedTimes_Resource_Coal</li>
       </value>
   </Operation>   

=================and finally one that adds alot of values to a trader:======================

<!-- Adding Goods to Neolithic Base -->
   <Operation Class="PatchOperationAdd">
       <xpath>/DefPackage-TraderKindDef/TraderKindDef[defName = "Base_Neolithic_Standard"]/stockGenerators</xpath>
       <value>
         <li Class="StockGenerator_SingleDef">
            <thingDef>MedTimes_Resource_IceBlocks</thingDef>
            <price>Expensive</price>
         </li>      
         <li Class="StockGenerator_Category">
            <categoryDef>TradeGoods</categoryDef>
            <price>Expensive</price>            
            <thingDefCountRange>
               <min>2</min>
               <max>5</max>
            </thingDefCountRange>
         </li>
         <li Class="StockGenerator_Tag">
            <tradeTag>MedTimes_Weapons</tradeTag>
            <price>Expensive</price>
            <thingDefCountRange>
               <min>2</min>
               <max>5</max>
            </thingDefCountRange>         
         </li>            
         <li Class="StockGenerator_Tag">
            <tradeTag>MedTimes_Armour</tradeTag>
            <price>Expensive</price>
            <thingDefCountRange>
               <min>2</min>
               <max>5</max>
            </thingDefCountRange>            
         </li>            
         <li Class="StockGenerator_Tag">
            <tradeTag>MedTimes_Artifact</tradeTag>
               <thingDefCountRange>
                  <min>1</min>
                  <max>3</max>
               </thingDefCountRange>               
         </li>   
         <li Class="StockGenerator_Tag">
            <tradeTag>MedTimes_Legendary</tradeTag>
         </li>         
       </value>
   </Operation>



 
Title: Re: A quick tutorial of xpathing and patching
Post by: skullywag on June 01, 2017, 08:58:50 AM
Ive just seen someone (i think) telling people that patching things like the min/max valules in the biomedefs for soil types isnt possible without patching the whole set, just wanted to state that sibling values are xpathable very simply using something like:

/thingdef/whatever[text()="thename"]/following-sibling::value[1]/text()

Hope that makes sense, the examples bad but it should give you the bits you need.
Title: Re: A quick tutorial of xpathing and patching
Post by: skullywag on June 02, 2017, 04:11:09 AM
Also heres a good list of the functions available to us in xpath 1.0 (we arent using 2.0 in .net 3.5)

http://www.edankert.com/xpathfunctions.html


Shinzyedit:
And if all else fails here's Skully's Xpath hotline for help (https://ludeon.com/forums/index.php?topic=33186.msg338225#msg338225)

Skullyedit:
Did you just.....well....thats just rude....but thanks. :)

Shinzyedit:
Oh don't mention it, My pleasure!
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on June 02, 2017, 09:21:13 AM
If it can help, here my biggest patches files. It works and maybe can be used as helping material.

I use all basic syntax in it

https://github.com/kaptain-kavern/CK_AnimalPlant_Pack/blob/master/Patches/patches.xml
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on June 02, 2017, 01:00:06 PM
Thank you so much for adding in some examples Skully and Kaptain. Thanks for the hotline Shinzy?
Title: Re: A quick tutorial of xpathing and patching
Post by: sulusdacor on June 11, 2017, 03:05:15 AM
you should mention you can patch abstracts ;)
with
Code: [Select]
[@Name = "AbstractName"]
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on June 12, 2017, 06:00:17 PM
Hey it's me again with a little more info I found while playing with the new method.

Believe it or not, but most of the time when patch aren't working it's because of a wrong xpath of course. Asking for a fresh pair of eyes can help. But here is a bit more help ...
Following are 2 things that made me lost some hours, so if it can help anyone ... ;)

- Pay attention to Parent nodes! There is no full consistency in uses. Sometimes you'll find Defs, sometimes ThingDefs for instance  8)  - Funpost with actual reply by Tynan (https://www.reddit.com/r/RimWorld/comments/6ecnyq/funpost_about_codewhy_tynan_why_you_do_this_to_me/)

(https://i.imgur.com/AY4bw24.png?2)

- Another one for the fun : I spotted that in 5 xml files <Defname> is used instead of <defname> (upcase D)

Concerned files :

EDIT
Bonus gift : if you are using SublimeText as a text editor, here's a link to a very useful plugin regarding xpath : https://github.com/rosshadden/sublime-xpath (https://github.com/rosshadden/sublime-xpath)


copy xpath of selected node to clipboard
(https://cloud.githubusercontent.com/assets/11882719/13170773/2dee3008-d6f7-11e5-9b93-b1c5da70cd5b.gif)
Title: Re: A quick tutorial of xpathing and patching
Post by: minimurgle on June 16, 2017, 09:21:56 AM
Thanks for pointing those things out Kaptain! I may be taking a looksy at that plugin too.
Title: Re: A quick tutorial of xpathing and patching
Post by: Kilroy232 on June 17, 2017, 01:38:18 PM
I have a question now that I have read through the original post and some of the comments. In my turrets mod I used this method to change specific values:
Code: [Select]
<researchMods>
      <li>
        <specialAction>TP.TPResearchMods.EnergyTurretOvercharge</specialAction>
      </li>
    </researchMods>

They have now removed the <researchMods> function but I would like to know if I can use patching in its place. I want to be able to have a research that will say increase a weapons range or damage. If anyone can help me out with that I would greatly appreciate it
Title: Re: A quick tutorial of xpathing and patching
Post by: Antaios on June 17, 2017, 11:14:15 PM
Reposting a discussion me and AngelWyrm are having over in mods, should be useful here.
This post (https://ludeon.com/forums/index.php?topic=33186.msg338985#msg338985) explains how to make an xpath statement that isn't going to generate duplicate field errors. Quick recap:

<Operation Class="PatchOperationSequence">
  <success>Always</success>
  <operations>
    <li Class="PatchOperationTest">
      <xpath>*/ThingDef[defName = "ChosenThingy"]/elementThatIWannaAdd</xpath>
      <success>Invert</success>
    </li>
    <li Class="PatchOperationAdd">
      <xpath>*/ThingDef[defName = "ChosenThingy"]</xpath>
      <value>
        <elementThatIWannaAdd> someValue </elementThatIWannaAdd>
      </value>
    </li>
  </operations>
</Operation>

I've used this test to do the same thing (https://github.com/AngleWyrm/TuningFork/blob/master/Patches/Tweaks.xml#L30): Add a sub-element if it doesn't exist.

The error messages are saying that two separate attempts (by two different mods) were made to add a specific element, and so it failed the second time because that element already exists.

This test checks to see if the element already exists (maybe because some other mod created it), and if it doesn't then there's a spot in there to add the element. And if it does already exist, then the check quietly bails out of it's sequence without spilling big red oops onto the user's screen.
Do take note that PatchSequenceTest operates per file, not global and not per def.

So if for example you're editing ThingDefs and looking to add RandomProperty1 if it doesn't exist in any of them, you need to be sure that no single file contains both ThingDefs which are missing RandomProperty1 and ThingDefs which include RandomProperty1 already.

It's why when I did that (https://github.com/Antaios/TableDiner/blob/master/TableDiner/Patches/Patches_TableDiner.xml), I use a placeholder tag and some gymnastics with '../' in xpath, rather than PatchOperationTest.
There should be no connection between xpath data searches and the underlying physical storage of that data.

The assertion that there is implies a defect in the implementation of the PatchSequenceTest function. Can you construct a test case that fails if the test draws values from different files, but succeeds if those values are drawn from the same file?
It is evident in the code, if you take a look at ModContentPack.LoadDefs(IEnumerable<PatchOperation> patches), PatchOperation, PatchOperationSequence and PatchOperationTest.
But a simple test is to take tuning fork, and in the core defs of Rimworld, add a blank abstract in Core\Defs\ThingDefs_Items.xml which has an ingestible/chairSearchRadius. You'll notice the patch no longer works on core meals.
Title: Re: A quick tutorial of xpathing and patching
Post by: AngleWyrm on June 18, 2017, 12:50:23 AM
Quote
So if for example you're editing ThingDefs and looking to add RandomProperty1 if it doesn't exist in any of them, you need to be sure that no single file contains both ThingDefs which are missing RandomProperty1 and ThingDefs which include RandomProperty1 already.

I've attached a testing scaffold mod that contains three files: A patch file, and two defs files.

The first defs file contains two entries with <label> tags, and the second defs xml contains three entries, with one of them that does not contain a <label> tag. The two defs files look about like so:

<Defs>
    <ThingDef>
        <defName>thingy-1</defName>
        <label>one</label>
   </ThingDef>
    <ThingDef>
        <defName>thingy-2</defName>
        <lable>two</lable>
   </ThingDef>
</Defs>


For feedback on a success/failure test, I suggest changing some visible GUI text within the game if the test succeeds.
So: What patch test operation will best demonstrate a reliance on file structure?

[attachment deleted by admin due to age]
Title: Re: A quick tutorial of xpathing and patching
Post by: Antaios on June 18, 2017, 01:41:28 AM
For feedback on a success/failure test, I suggest changing some visible GUI text within the game if the test succeeds.
So: What patch test operation will best demonstrate a reliance on file structure?

attatched an example, uses this patch:
<Operation Class="PatchOperationSequence">
   <operations>
      <li Class="PatchOperationTest">
         <xpath>*/ThingDef/changeMyLabel</xpath>
      </li>
      <li Class="PatchOperationReplace">
         <xpath>*/ThingDef/label</xpath>
         <value>
            <label>Label Replaced</label>
         </value>
      </li>
   </operations>
</Operation>


You might assume that this patch would either:
if a ThingDef with a <changeMyLabel> tag exists at all, change all ThingDef/labels to "Label Replaced"
Or
If a ThingDef has a <changeMyLabel> tag, change that thingDef's label to "Label Replaced"

What It'll actually do is change the label of any thingDefs whose file includes a thingDef which has the <changeMyLabel> tag

you can test it by adding:

<ThingDef>
   <defName>thingy-1</defName>
   <changeMyLabel>IrrelevantValue</changeMyLabel>
</ThingDef>


to any core or mod xml file which defines thingDefs, then checking their label ingame.

It will error when loaded by the way, since the xml loader (which happens after patching) doesn't know what to do with <changeMyLabel> tags.
You can add a seperate PatchOperationRemove to get rid of <changeMyLabel> tags after the sequence to get rid of the error if you want.

[attachment deleted by admin due to age]
Title: Re: A quick tutorial of xpathing and patching
Post by: skullywag on June 19, 2017, 08:17:45 AM
The patcher runs against each individual def, one by one, so no i wouldnt have expected your xpath to do what you state.

however others might, so yeah, patcher runs 1 by 1 through defs, not the whole def db in one go. Its a start stop process.
Title: Re: A quick tutorial of xpathing and patching
Post by: Antaios on June 19, 2017, 08:32:33 AM
The patcher runs against each individual def, one by one, so no i wouldnt have expected your xpath to do what you state.

however others might, so yeah, patcher runs 1 by 1 through defs, not the whole def db in one go. Its a start stop process.
*did you mean 1 by one through files? tests and looking at the code show it's files not individual defs.

The posts were more specifically with regard to cautioning people when they use PatchOperationTest to avoid duplicating defs, they might not get the response they expect.

Searching/Testing/Replacing based on specific defNames is fine, since they're unique per def. but since the patcher operates per file patching files one by one, broader search/test/replace terms can lead to unexpected results.
Title: Re: A quick tutorial of xpathing and patching
Post by: faltonico on August 25, 2017, 07:08:28 AM
Can i use a test operation to find a def and then modify a def in another document?

e.g. i want to look for a specific def that would tell me that a particular mod is installed, and then i would modify another def from another mod knowing that the first one is present.

Thanks in advance for the help!
Title: Re: A quick tutorial of xpathing and patching
Post by: FauxGrim on August 25, 2017, 12:02:37 PM
Also useful tool for testing xpath expressions:

https://www.freeformatter.com/xpath-tester.html
Title: Re: A quick tutorial of xpathing and patching
Post by: gipothegip on September 09, 2017, 09:37:14 PM
Curious question on how this thing works; Why do we not have to specify a file path? Why do we just start with ThingDefs (or any other equivalent top level node)?

I know, not the most important information, but it had me confused at the start :P There isn't a file or folder named ThingDefs, after all (and I had thought the file path would be important).
Title: Re: A quick tutorial of xpathing and patching
Post by: SpaceDorf on September 18, 2017, 06:47:48 PM
Just for clarification :

XPathes are only able to edit existing definitions not adding new ones or replacing funtions ( methods .. whatever the hip name is today )
Title: Re: A quick tutorial of xpathing and patching
Post by: Varisha on November 04, 2017, 07:27:34 PM
Hello,

i am sure this question popped up somewhere already.

What if 2 different mods replace the same "class" with an XML-Patch-Operation.
Example:
Code: [Select]
<Operation Class="PatchOperationReplace">
  <xpath>//MainButtonDef[defName = "Inspect"]/tabWindowClass</xpath>
  <value>
    <tabWindowClass>ModA.NewClassA</tabWindowClass>
  </value>
</Operation>
Code: [Select]
<Operation Class="PatchOperationReplace">
  <xpath>//MainButtonDef[defName = "Inspect"]/tabWindowClass</xpath>
  <value>
    <tabWindowClass>ModB.NewClassB</tabWindowClass>
  </value>
</Operation>
Which class will be the winner or are both instantiated and executed according to mod order?
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on November 05, 2017, 07:57:38 PM
I'm pretty sure the last one in mod order will "win"
Title: Re: A quick tutorial of xpathing and patching
Post by: LOLKAT_KOMRAD_94 on November 13, 2017, 06:21:47 AM
Hi !

I just started modding on RimWorld yesterday and this was exactly one of the things I was wondering - how to modify Core defs without overwritting them completely. So thanks for the post! :D

I do have a question though. The addition I wanted to have new bills on the Body_Humanoid (or something like). From what I'm reading here, it's possible to replace / change an existing value, but is it possible to add to a list?

Cheers!
Title: Re: A quick tutorial of xpathing and patching
Post by: CannibarRechter on November 13, 2017, 08:32:37 AM
>  From what I'm reading here, it's possible to replace / change an existing value, but is it possible to add to a list?

Yes. PatchOperationAdd is what you are looking for.
Title: Re: A quick tutorial of xpathing and patching
Post by: LOLKAT_KOMRAD_94 on November 13, 2017, 10:06:07 AM
>  From what I'm reading here, it's possible to replace / change an existing value, but is it possible to add to a list?

Yes. PatchOperationAdd is what you are looking for.

Hum, yeah, that makes total sense. I feel stupid now ahah.

Anywhere with documentation on all PatchOperations available?
Title: Re: A quick tutorial of xpathing and patching
Post by: CannibarRechter on November 13, 2017, 10:11:04 AM
Zhentar's Patch Guide (https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782)

I'd advise against using the sequence operation until A18. The A17 release of it is missing a critical usability feature (if it fails, it doesn't explain which of your sequences is broken: not worth it). That's fixed for A18.
Title: Re: A quick tutorial of xpathing and patching
Post by: LOLKAT_KOMRAD_94 on November 13, 2017, 11:24:51 AM
Great link. Thanks for all the pointers!
Title: Re: A quick tutorial of xpathing and patching
Post by: DarkSnowi on November 18, 2017, 02:57:28 AM
Okay guys, I think I need some advice here.

I published the Vanilla Gun Name mod in A17 a while ago, now with patch A18 hitting today I wanted to update said mod.
Unfortunately simply changing the target version gives me a long list of debug errors saying that he couldn´t complete the xpathing replace action in every line.


Every error looks like this:
Code: [Select]
RimWorld 0.18.1722 rev1198
Verse.Log:Message(String)
RimWorld.VersionControl:LogVersionNumber()
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

[+DEV+ Real Vanilla Gun Names] Patch operation Verse.PatchOperationReplace(/ThingDefs/ThingDef[defName = "Gun_Pistol"]/label) failed
file: D:\Program Files (x86)\Steam\steamapps\common\RimWorld\Mods\DEV Real Vanilla Gun Names\Patches\patchedChanged_Weapons_Guns.xml
Verse.Log:Error(String)
Verse.PatchOperation:Complete(String)
Verse.LoadedModManager:LoadAllActiveMods()
Verse.PlayDataLoader:DoPlayLoad()
Verse.PlayDataLoader:LoadAllPlayData(Boolean)
Verse.Root:<Start>m__1()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__1()

Did something change?

(Original file is attached)



[attachment deleted by admin: too old]
Title: Re: A quick tutorial of xpathing and patching
Post by: DarkSnowi on November 18, 2017, 12:15:20 PM
Hey its me again.

It seems like I figured out what has changed.
Weapons are no longer in ThingDefs , the Tag is now called simply Defs . (Also there is a new Gun and naturally they renamed the Pistol in the tag logic)

So,
Code: [Select]
<xpath>/ThingDefs/ThingDef[defName = "Gun_PumpShotgun"]/label</xpath>
is now

Code: [Select]
<xpath>/Defs/ThingDef[defName = "Gun_PumpShotgun"]/label</xpath>
Title: Re: A quick tutorial of xpathing and patching
Post by: CannibarRechter on November 18, 2017, 07:26:38 PM
> Weapons are no longer in ThingDefs , the Tag is now called simply Defs

I see why I didn't notice. I use xpath notations that look like this:

Code: [Select]
<xpath>*/ThingDef[defName = "Beer"]/graphicData/texPath</xpath>

Title: Re: A quick tutorial of xpathing and patching
Post by: Manhunting Muffalo on November 27, 2017, 01:49:23 PM
So something has changed in 0.18 that I can't suss out, and the error I'm getting is unhelpful ("patching operation failed"). My code is very simple, just trying (for the sake of practice) to change the power consumption for a standing lamp to 15. This is what I have:

Code: [Select]
<?xml version="1.0" encoding="utf-8" ?>

<Patch>
<Operation Class="PatchOperationReplace">
<xpath>/Defs/ThingDef[defName="StandingLampBase"]/comps/li[@Class="CompProperties_Power"]/basePowerConsumption</xpath>
<value>
<basePowerConsumption>15</basePowerConsumption>
</value>
</Operation>

</Patch>

I can't seem to figure out what it can't find. Could someone point it out since I seem to be extra dumb today?
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on November 27, 2017, 02:12:49 PM
I too notice something like this lately as well.

Can't seems to be able to target an Abstract with the use of "@". I worked around this by targeting each child ThingDef by defName each time. In your case all the standing lamps: normal and each color version. But it's far than optimum IMHO.

By then I was just thinking I derped and moved on something else, but it was this exact same case as you described.
Title: Re: A quick tutorial of xpathing and patching
Post by: Manhunting Muffalo on November 27, 2017, 03:13:23 PM
But standing lamp sub-versions don't have a basePowerConsumption entry..?
Title: Re: A quick tutorial of xpathing and patching
Post by: kaptain_kavern on November 27, 2017, 03:56:31 PM
When the game uses abstract it "constructs" "normal" thingDef from the abstracted ones and then "discards" the abstract defs. That's what I've been told I really don't know how it works precisely but it works if you use PatchOperationAdd on a Def without it originally, because you then "just" overwrites tags in the "recreated" def, which were inherited from the Abstract

In this patch, I added tags to Spacer faction def (4th patch operation), for instance.
https://github.com/kaptain-kavern/Gun-Tech-Removal/blob/master/Patches/patches.xml


I'm lacking precise words (I'm not a native English speaker) and knowledge to explain better. Hope someone else will do ;-)
Title: Re: A quick tutorial of xpathing and patching
Post by: Manhunting Muffalo on November 27, 2017, 04:15:12 PM
Nope, still missing something, I guess I'm not smart enough to suss out what you're saying. God damnit, I wish the error message was a bit more informative. Very frustrating that I can't even do something this simple.
Title: Re: A quick tutorial of xpathing and patching
Post by: frenchiveruti on December 17, 2017, 08:32:25 PM
Oh my... Well this really needs to be updated because I kept patching ThingDefs and not Defs and that kept breaking my game.
I almost gave up on modding but decided to check out this page and found that it changed the name.
I have a new question, how do I check out if a patch operation went right?
I have HugsLibs in my modlist, is there a way to tell?
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on December 17, 2017, 09:07:16 PM
I have a new question, how do I check out if a patch operation went right?
Make a sequence like in this guide (https://github.com/Nightinggale/ModCheck/wiki/speed_patching). As the last item, put something in the list like isModLoaded and add both customMessageSuccess and customMessageFail. One of them will trigger and write the contents of the tag to the log.

I'm not done writing the guide, but it should be of interest to everybody writing patches.

I have HugsLibs in my modlist, is there a way to tell?
ModCheck.isModLoaded
Title: Re: A quick tutorial of xpathing and patching
Post by: frenchiveruti on December 17, 2017, 09:38:45 PM
I have a new question, how do I check out if a patch operation went right?
Make a sequence like in this guide (https://github.com/Nightinggale/ModCheck/wiki/speed_patching). As the last item, put something in the list like isModLoaded and add both customMessageSuccess and customMessageFail. One of them will trigger and write the contents of the tag to the log.

I'm not done writing the guide, but it should be of interest to everybody writing patches.

I have HugsLibs in my modlist, is there a way to tell?
ModCheck.isModLoaded

Ok, so that involves adding something extra. Cool.
I think, for the scope of my mod (https://ludeon.com/forums/index.php?topic=37719.0), that's really not necessary, right?
Title: Re: A quick tutorial of xpathing and patching
Post by: Jaxxa on December 17, 2017, 10:10:14 PM
Is it possible to write logic in C# to decide if an XML patch will be applied or not?
I want to conditionally execute an XML patch based on a value in mod settings.
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on December 18, 2017, 12:16:48 AM
Is it possible to write logic in C# to decide if an XML patch will be applied or not?
That's what ModCheck is all about. Adding C# code to add features to handle conditional xml patching. Well that, performance boosting and allowing patches to write to the log.

If you have more questions on how ModCheck works and if you want some specific feature, I would recommend using the ModCheck thread to do so.

I want to conditionally execute an XML patch based on a value in mod settings.
It depends. If the setting in question is loaded prior to xml loading, then it's easy to do. If not, then it could get complicated. I would encourage you to post about it in more detail in the ModCheck thread and I will see if I can make a PatchOperation to check the setting in question.
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on December 18, 2017, 12:36:19 AM
Ok, so that involves adding something extra. Cool.
I think, for the scope of my mod (https://ludeon.com/forums/index.php?topic=37719.0), that's really not necessary, right?
No. It's a minor addition. It's just adding two small DLL files (one is harmony) and you will be able to use everything it provides the added features. The most important one is ModCheck.FindFile where you tell which file to patch, which will ALWAYS be a massive performance boost compared to vanilla. Read the ModCheck thread. I used a modified ADS patch and applied it in 1.5 ms when the template use 115 ms. Even better if you double the number of xml files, FindFile will still use 1.5 ms (same due to rounding) while the template using vanilla would use around 230 ms. Now double again and multiply with the number of mods, which use patches and it's no longer talk of some ms while starting.

We can start RimWorld a lot faster when loading lots of mods, but only if the usage of ModCheck becomes widespread. Granted you only has one PatchOperationAdd, but it's still big enough to get a massive performance boost.
Title: Re: A quick tutorial of xpathing and patching
Post by: frenchiveruti on December 18, 2017, 07:43:18 AM
Ok, so that involves adding something extra. Cool.
I think, for the scope of my mod (https://ludeon.com/forums/index.php?topic=37719.0), that's really not necessary, right?
No. It's a minor addition. It's just adding two small DLL files (one is harmony) and you will be able to use everything it provides the added features. The most important one is ModCheck.FindFile where you tell which file to patch, which will ALWAYS be a massive performance boost compared to vanilla. Read the ModCheck thread. I used a modified ADS patch and applied it in 1.5 ms when the template use 115 ms. Even better if you double the number of xml files, FindFile will still use 1.5 ms (same due to rounding) while the template using vanilla would use around 230 ms. Now double again and multiply with the number of mods, which use patches and it's no longer talk of some ms while starting.

We can start RimWorld a lot faster when loading lots of mods, but only if the usage of ModCheck becomes widespread. Granted you only has one PatchOperationAdd, but it's still big enough to get a massive performance boost.
Ok I'll see if I can add it without blowing everything up haha.
Title: Re: A quick tutorial of xpathing and patching
Post by: frenchiveruti on December 18, 2017, 08:57:53 AM
Hello Nightinggale, I've made what you suggested on "speed_patching", there were a few issues on it as you placed the wrong tags on the wiki, but solved and reported it on the GitHub.
One thing though. "ModCheck.FindFile" doesn't allow custom messages, am I right?
I mean, I made it so it goes for the wildplants and well, it always succeeds, but I can't tell in the log if that was the case because is not supported by the Operation Class. Also "yourMod" tag isn't supported by that operation.
Is that correct? That's what I understood from the red warning yelling. :)
Title: Re: A quick tutorial of xpathing and patching: multiple tags per xpath
Post by: Alias on December 21, 2017, 12:30:35 PM
I have figured out how to xpath to a given tag, but is there a way to patch multiple tags for a given defName?
So for example if I wanted to change a gun's warmupTime and Mass, can this be done in one xpath  operation?
Title: Re: A quick tutorial of xpathing and patching: multiple tags per xpath
Post by: frenchiveruti on December 21, 2017, 02:49:11 PM
I have figured out how to xpath to a given tag, but is there a way to patch multiple tags for a given defName?
So for example if I wanted to change a gun's warmupTime and Mass, can this be done in one xpath  operation?
You have to do a Patch Sequence for that.
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on December 21, 2017, 02:50:06 PM
Is it possible to write logic in C# to decide if an XML patch will be applied or not?
I want to conditionally execute an XML patch based on a value in mod settings.
Looks like GetSettings<Settings>() is available when Verse.Mod is allocated, which is before running the patches. In other words it can be used. The approach to do so would be:

Code: [Select]
public class CheckSetting : PatchOperation
{
    public string someInfo;
    protected override bool ApplyWorker(XmlDocument xml)
    {
        try
        {
           // some code with GetSettings<Settings>(), which might return true
        }
        catch
        {
        }
        return false;
    }
}
If you return true, then the next operation in a sequence will be reached. If you return false, the rest of the operations will be ignored. Using try-catch prevents any possible issues with settings not existing and such. Better be safe than sorry.

The properties, like in this case someInfo is the tags in xml and they will be null if not filled out. You can skip those if you have nothing to use them for.

The PatchOperation can then be called from xml by using the class namespace.classname.

All files are patched by all patches, meaning you will get a performance hit if your code is slow. Putting your operation after ModCheck.FindFile will avoid that issue.
Title: Re: A quick tutorial of xpathing and patching
Post by: Shurp on February 25, 2018, 12:25:40 PM

Use:

<Patch>   and </Patch> to open and close the document (placed after the header)


OK, is any advice in this thread still useable?  Because when I start a document with <Patch> Rimworld immediately complains "root element named Patch; should be named Defs".  And if I use <Defs><Patch> it simply complains "Found no useable data when trying to get defs".  So I have no idea what I'm doing wrong here.

Here's my entire file; what do I need to do so that this actually works?

<?xml version="1.0" encoding="utf-8" ?>

<Defs>
<Patch>
   <Operation Class="PathOperationReplace">
      <xpath>/Defs/ThingDef[defName = "Apparel_Pants"]/description</xpath>
      <value>
         <description>Super Pants</description>
      </value>
   </Operation>
</Patch>
</Defs>
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on February 25, 2018, 12:36:28 PM
OK, is any advice in this thread still useable?  Because when I start a document with <Patch> Rimworld immediately complains "root element named Patch; should be named Defs".
Yes it still applies, but you seem to have mixed up Defs and Patches.

There are two different directories to place xml files in. They are called Defs and Patches. All files in Defs needs to have Defs as root. All files in Patches needs to have Patch as root. On load, the game will load the Defs one by one and each time a Def is read, all the patches are applied to that one.
Title: Re: A quick tutorial of xpathing and patching
Post by: Shurp on February 25, 2018, 01:27:19 PM
"Patches go in xml files in a subfolder named "Patches" in your mod folder (So "MyMod\Patches", just like you might have "MyMod\Defs" or "MyMod\Textures"). "

Ahhh, so it's not that this thread is inaccurate... it's just seriously incomplete.  Reading https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782 is a necessary prerequisite.

Thanks for clarifying Nightinggale, I will give that a try!
Title: Re: A quick tutorial of xpathing and patching
Post by: Shurp on February 25, 2018, 01:38:07 PM
Woo hoo!  It worked!

So, for anyone else still reading this thread, here's a list of all the corrections I needed to make it work:
1) Move the file to ./Mods/[MyMod]/Patches where it belongs
2) Get rid of the "<Defs>" silliness
2) Spell "PatchOperationReplace" correctly

And now all my colonists are wearing Super Pants.  Yay!

Now I just have to figure out how to use sequences...

--------------------------[edit]----------------------------

And here is the complete code for a working patch mod:

<Patch>
   <Operation Class="PatchOperationSequence">
      <success>Always</success>
      <operations>
      <li Class="PatchOperationReplace">
         <xpath>/Defs/ThingDef[defName = "Apparel_Pants"]/description</xpath>
         <value>
            <description>Super Pants</description>
         </value>
      </li>
      <li Class="PatchOperationReplace">
         <xpath>/Defs/ThingDef[defName = "Apparel_Pants"]/statBases/ArmorRating_Blunt</xpath>
         <value>
            <ArmorRating_Blunt>1.00</ArmorRating_Blunt>
         </value>
      </li>
      <li Class="PatchOperationReplace">
         <xpath>/Defs/ThingDef[defName = "Apparel_Pants"]/statBases/ArmorRating_Sharp</xpath>
         <value>
            <ArmorRating_Sharp>0.90</ArmorRating_Sharp>
         </value>
      </li>
      </operations>
   </Operation>
</Patch>

But I have a question: what does the "<success>" flag do?
Title: Re: A quick tutorial of xpathing and patching
Post by: Takashi Yonezawa on March 27, 2018, 03:44:05 PM
Thanks for writing this. This is awesomely useful!
May I translate this document into Japanese? There are many Japanese players and modders who need to know this.
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on March 27, 2018, 07:05:13 PM
May I translate this document into Japanese? There are many Japanese players and modders who need to know this.
Go ahead and translate. My only concern is about keeping it up to date with future releases. You should use a wiki to allow other people to update in the future, if needed. It would also be nice if you post a link here.

I have a half written update for ModCheck, which I will finish when I get time (whenever that is). You should include ModCheck in the translation because it adds some rather powerful modding options. It also adds much faster startup times, but only for mods actually using ModCheck.FindFile.
Title: Re: A quick tutorial of xpathing and patching
Post by: Takashi Yonezawa on March 29, 2018, 01:38:33 AM
Dear Nightinggale.
I've finished the translation. Thanks to your post and permission.
My translation is here.
https://github.com/oramu7524/Mods-for-RIMWORLD/blob/master/A_quick_tutorial_of_xpathing_and_patching_Japanese_translation.txt
Title: Re: A quick tutorial of xpathing and patching
Post by: Nightinggale on March 29, 2018, 10:16:55 AM
Dear Nightinggale.
I've finished the translation. Thanks to your post and permission.
My translation is here.
https://github.com/oramu7524/Mods-for-RIMWORLD/blob/master/A_quick_tutorial_of_xpathing_and_patching_Japanese_translation.txt
A minor, yet important correction: you credited me for writing the first post while it was actually written by minimurgle.
It could also be worth to translate the performance thread (https://ludeon.com/forums/index.php?topic=32874.0) or at least mention that // should not be used.
Title: Re: A quick tutorial of xpathing and patching
Post by: Takashi Yonezawa on March 29, 2018, 01:58:12 PM
Oh... I've misunderstood that you are the author of this thread. But thank you for your suggestion. And I've subscribed your ModCheck.FindFile. That's Powerful!
Title: Re: A quick tutorial of xpathing and patching
Post by: czpetr on August 31, 2018, 08:43:29 AM
Thanks, very helpful tutorial  :)
Title: Re: A quick tutorial of xpathing and patching
Post by: HalfdeadKiller on January 27, 2019, 02:46:29 PM
For anyone who may find this useful. If you need to edit a specific <li> you can do so with this sort of format.

Code: [Select]
<Patch>
<Operation Class="PatchOperationSequence">
<operations>
<li Class="PatchOperationTest">
<xpath>/StorytellerDefs/StorytellerDef[defName = "Phoebe-DoublePop"]</xpath>
</li>
<li Class="PatchOperationReplace">
<xpath>/StorytellerDefs/StorytellerDef[defName = "Phoebe-DoublePop"]/comps/li["StorytellerCompProperties_CategoryMTB"]/allowedTargetTypes</xpath>
<value>
<allowedTargetTypes>MapPlayerHome, MapMisc</allowedTargetTypes>
</value>
</li>
</operations>
</Operation>
</Patch>

This particular patch was for a mod for an older version of the game, but I think the format still works.
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on February 03, 2019, 11:00:40 PM
There are a lot of scattered "tutorials" people have written, but they all seem to be missing bits and pieces.  I have found a reference to PatchOperationFindMod on the wiki.  Not many people seem to be using the wiki.  Is it accurate?

No one else seems to mention PatchOperationFindMod.  Does it actually exist?  If so, can anyone explain/show how it's used?

Does anyone want to update the wiki, or is that not a place people use?

--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: Pelador on February 03, 2019, 11:54:14 PM
There are a lot of scattered "tutorials" people have written, but they all seem to be missing bits and pieces.  I have found a reference to PatchOperationFindMod on the wiki.  Not many people seem to be using the wiki.  Is it accurate?

No one else seems to mention PatchOperationFindMod.  Does it actually exist?  If so, can anyone explain/show how it's used?

Does anyone want to update the wiki, or is that not a place people use?

--LWM

Syntax is as follows:

Code: [Select]
<Operation Class="PatchOperationFindMod">
<mods>
    <li>{Name of Mod as per About.xml def}</li>
      </mods>
        <match Class="PatchOperation{…}">
                <xpath>{xpath details}</xpath>
<value>
{vals…}
</value>
        </match>
<nomatch Class=”Patchoperation{…}>
                <xpath>{xpath details}</xpath>
<value>
{vals…}
</value>
</nomatch>
</Operation>

The optional <match /> and <nomatch /> are operations you can apply to your “OWN” mod based on whether the named mod is found.

I’ve found you cannot apply these within a patch sequence or embed a patch sequence into the match and nomatch nodes, so you have to specify multiple patch definitions if you need to do multiple different kinds of changes.

E.g.
Code: [Select]
<Operation Class="PatchOperationFindMod">
<mods>
<li>VGP Vegetable Garden</li>
      </mods>
        <match Class="PatchOperationReplace">
            <xpath>*/RecipeDef[defName="MakeMSMultiVitamins"]/ingredients</xpath>
            <value>
                    <ingredients>
<li>
<filter>
<thingDefs>
<li>Neutroamine</li>
</thingDefs>
</filter>
<count>1</count>
</li>
<li>
<filter>
<categories>
            <li>FruitFoodRaw</li>
          </categories>
</filter>
<count>5</count>
</li>
</ingredients>
</value>
</match>
    </Operation>

<Operation Class="PatchOperationFindMod">
      <mods>
        <li>VGP Vegetable Garden</li>
      </mods>
        <match Class="PatchOperationReplace">
            <xpath>*/RecipeDef[defName="MakeMSMultiVitamins"]/fixedIngredientFilter</xpath>
            <value>
<fixedIngredientFilter>
<thingDefs>
<li>Neutroamine</li>
</thingDefs>
<categories>
        <li>FruitFoodRaw</li>
      </categories>
</fixedIngredientFilter>
            </value>
        </match>
    </Operation>
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on February 04, 2019, 01:11:04 AM
Thank you very much!

I’ve found you cannot apply these within a patch sequence or embed a patch sequence into the match and nomatch nodes, so you have to specify multiple patch definitions if you need to do multiple different kinds of changes.

Oh, that's dismaying...I have a handful of places to patch, and a sequence would have been much easier.  But forewarned is forearmed.  And some peoples' alien races have four arms, so it's best to be prepared.

--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on February 04, 2019, 12:03:04 PM
Syntax is as follows:[...]
I’ve found you cannot apply these within a patch sequence or embed a patch sequence into the match and nomatch nodes, so you have to specify multiple patch definitions if you need to do multiple different kinds of changes.

Woohoo - I got my test compatibility patch working!

I also tested using a Sequence, and it worked!  So maybe something has changed?

But this does actually patch:

Code: [Select]
<Patch>
  <Operation Class="PatchOperationFindMod">
    <mods>
      <li>LWM's Deep Storage</li>
    </mods>
    <match Class="PatchOperationSequence">
      <operations>
        <li Class="PatchOperationReplace">
          <xpath>/Defs/ThingDef[defName="LWM_WeaponsLockerLocker"]/label</xpath>
          <value><label>Testing this.</label></value>
        </li>
        <li Class="etc"><actual stuff />
        </li>
      </operations>
    </match>
  </Operation>
</Patch>

Thanks!  I'll go add this detail to the wiki.
--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on February 04, 2019, 12:34:57 PM
I note that https://www.w3schools.com/xml/xpath_syntax.asp specifies that the expression "Defs" in an xpath would 'Select all nodes with the name "[Defs]."'  So it sounds like all xpaths should start with "/Defs" to avoid searching for "Defs" in any depth - am I correct?

--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on April 29, 2019, 01:06:51 PM
I note that https://www.w3schools.com/xml/xpath_syntax.asp specifies that the expression "Defs" in an xpath would 'Select all nodes with the name "[Defs]."'  So it sounds like all xpaths should start with "/Defs" to avoid searching for "Defs" in any depth - am I correct?

Note: I found in testing that /Defs was *slightly* faster than Defs.  Methodology:  https://github.com/lilwhitemouse/RimWorld-PatchSpeedTest

--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: Nerdygamer on July 31, 2019, 10:07:18 PM
First time poster, so apologies if I'm out of line somewhere, but I'm having trouble xpathing into ThingDefs with parent names. I'm trying to adjust the blunt armor rating of marine helmets with a PatchOperationReplace. I have a rudimentary understanding of xpathing (thanks in part to this thread) and have a working patch to edit the values of room sizes. The following code works and is meant to serve as proof that I faintly know what I'm doing:
Code: [Select]
<Patch>
<Operation Class = "PatchOperationReplace">
<xpath>Defs/RoomStatDef[defName = "Space"]/scoreStages</xpath>
<value>
    <scoreStages>
[blah blah blah, snipped for space]
</scoreStages>
</value>
</Operation>
</Patch>

However, I cannot figure out how to use a replace command to change the value of a marine helmet's blunt protection. Everything I've tried just crashes the game immediately. I even used http://xmltoolbox.appspot.com/xpath_generator.html to "cheat" and write the code for me (you plug in the code, click on the line you wish to xpath to, and it spits out what you need), and even that doesn't work. My current code, which doesn't work, is as follows:
Code: [Select]
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationReplace">
    <xpath>Defs/ThingDef ParentName="ArmorHelmetMakeableBase"[defName = "Apparel_PowerArmorHelmet"]/statBases/ArmorRating_Blunt</xpath>
<value>
<ArmorRating_Blunt>0.4</ArmorRating_Blunt>
</value>
    </Operation>
</patch>

Help, please? I have no idea why my first example works and my second doesn't, but I've had trouble in the past when trying to xpath to an object that started with <ThingDef ParentName = blahblahblah>
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on July 31, 2019, 10:50:21 PM
You have an xpath of
Code: [Select]
<xpath>Defs/ThingDef ParentName="ArmorHelmetMakeableBase"[defName = "Apparel_PowerArmorHelmet"]/statBases/ArmorRating_Blunt</xpath>

But xpath operates on xml.  The node you are looking for is a "ThingDef" node which has an attribute of ParentName="blahblah".  But you don't care about that attribute - you're specifying the node based on the fact that it has a subnode of defName with value Apparel_PowerArmorHelmet.

So use this instead, and I think it will work:

Code: [Select]
<xpath>/Defs/ThingDef[defName = "Apparel_PowerArmorHelmet"]/statBases/ArmorRating_Blunt</xpath>

--LWM
PS - note that I put a "/" in front of the first Defs - it's sliiiightly faster to do it that way.
Title: Re: A quick tutorial of xpathing and patching
Post by: Nerdygamer on July 31, 2019, 11:23:08 PM
Unfortunately, that still doesn't work.  Just trying to enable Core and my mod results in the game throwing up the "recovered from incompatible or corrupted mods error".  I have the mod folder, which has an "About" folder and a "Patches" folder.  In the "About" folder, I have an About.xml, which is as follows:
Code: [Select]
<?xml version="1.0" encoding="utf-8"?>
<ModMetaData>
  <name>Better Marine Helmets</name>
  <author>Nerdygamer1</author>
  <targetVersion>1.0</targetVersion>
  <description>Makes marine helmets competitive when compared to plasteel advanced helmets. Previously, plasteel advanced helmets had more health and better protection against blunt damage (despite the description suggesting otherwise). Now, advanced helmets have been given a gentle increase in both health and blunt protection, at the cost of ten extra plasteel (for a total cost of 50 plasteel; the same cost as a plasteel advanced helmet). Component requirements have not been changed.</description>
</ModMetaData>

In the "Patches" folder is my "Patches_Helmets.xml" which is as follows:
Code: [Select]
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationReplace">
    <xpath>/Defs/ThingDef[defName = "Apparel_PowerArmorHelmet"]/statBases/ArmorRating_Blunt</xpath>
<value>
<ArmorRating_Blunt>0.4</ArmorRating_Blunt>
</value>
    </Operation>
</patch>

And that's literally everything. The game throws an absolute fit when trying to start up with the mod enabled - checking the box automatically restarts the game, and upon booting up, I immediately get the error message; it's not even the debug log.
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on August 01, 2019, 01:37:06 AM
Your XML isn't valid!

You have a lowercase "patch" as your close tag instead of an uppercase.

I use emacs to do my editing, and one of the things it does for me is validate my xml automatically ^.^  I pasted the file in and it told me "Invalid" and gave the "patch" a nice noticeable orange.   I highly recommend a good editor that does that sort of thing for you.

...we've all done stupid things, so don't feel bad there....having an editor that catches (some) stupid mistakes means we can make more subtle ones that drive us up a limestone wall!

--LWM
Title: Re: A quick tutorial of xpathing and patching
Post by: Nerdygamer on August 01, 2019, 01:34:00 PM
That worked!  Thank you so much for your help; you have no idea how long I spent googling, making minor changes, and testing last night.  I'm no stranger to formatting errors (and that was the first thing I double-checked - making sure I had all my brackets, my slashes, and making sure it was ThingDef), but my mistakes don't usually hang up the game so badly that I can't get a basic idea of what I did wrong from the debug log, and I didn't even think to check that my commands had the same casing :x

I'm looking into emacs right now.
Title: Re: A quick tutorial of xpathing and patching
Post by: LWM on August 01, 2019, 02:56:39 PM
Emacs has a steeper learning curve than a lot of editors, I am willing to admit, but it's awesome.  If you want something simpler in Windows, look into Notepad++ - I think it does XML?  I'm sure google is your friend ;)

If you really feel like learning something new, there's also vi - which is better is still a hotly contested holy war.   ;D;P

Glad it worked for you!