I just started modding the other day (A17b has already been out for some time) and discovered a peculiarity when working with another mod - core def's being re-declared inside the mod itself. Apparently this was how you had to do it before A17 (or possibly older). Oh, the horror! Apparently a lot of modders are not aware that they can directly reference def's from other "packages" now. The benefits of doing so are obvious.
So, I may be a brand new modder but after looking through some prominent mods, I feel it very necessary to raise awareness of two important things...
1) XML inheritance is a new fantastic thing. Don't copy-paste Core (or other mod) Def's into your own mods - you can set your ParentName attribute to any other Def with a Name attribute and it will inherit (copy) all of it's nodes as a base (as long as your mod is loaded after whatever mod the parent is from).
You then only need to (re)define the nodes that you want to change, add or remove (FYI, you can remove with empty nodes e.g. <nutrition/>).
Also remember that you can inherit from *any* named def, it does NOT have to be abstract.
Aside: It would be great if Ludeon made a change so that every *Def with a defName childnode could be loaded with a runtime-generated Name attribute that matches it's defName (if not already taken) - this would make inheritance even more powerful.2) Patching and xpath criteria. I don't think a lot of people understand how the xpath stuff works, they just copy-paste other stuff and hack it with a vague understanding. As mentioned in the thread that warns about xpath performance, I feel I need to first reiterate that:
- //ThingDef[defName="someDefName"]
Recursively searches an unlimited number of child nodes for ThingDef nodes containing <defName>someDefName</defName>. Very slow and completely unnecessary. This is like searching a lot of text for a relatively common string. - */ThingDef[defName="someDefName"]
Will search child nodes that are nested ONE level ONLY named ThingDef and containing <defName>someDefName</defName>. The * is a wildcard, meaning match any single node. Very fast and how it should be done.
Now, about the "wildcard-like xpath patching" I mention. I see a lot of mods xpathing partially, but in a round-about way. Example:
<Operation Class="PatchOperationInsert">
<xpath>//ThingDef[defName = "FueledGenerator"]/comps/li[@Class = "CompProperties_Refuelable"]/fuelFilter/thingDefs/li</xpath>
<value>
<li>Coal</li>
</value>
</Operation>
In case it wasn't obvious, the intention here is to inject an additional fuel source of Coal (sorry and no offense to the modder who did this - many modders seem to do it this way so I don't blame you) which is repeated similarly a few more times for other machines that use WoodLog as a fuel source. This is not optimal - why not just find every ThingDef that already uses WoodLog as a fuel source, and then inject upon them? There's no reason why you'd not want Coal to be a fuel source for everything! Here's how you'd do that:
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationTest">
<!-- Only add if this is a machine that has WoodLog as a fuel source already -->
<xpath>*/ThingDef/comps/li[@Class = "CompProperties_Refuelable"]/fuelFilter/thingDefs/li[text() = "WoodLog"]</xpath>
</li>
<li Class="PatchOperationTest">
<!-- Skip if already patched -->
<xpath>*/ThingDef/comps/li[@Class = "CompProperties_Refuelable"]/fuelFilter/thingDefs/li[text() = "Coal"]</xpath>
<success>Invert</success>
</li>
<li Class="PatchOperationAdd">
<!-- Inject Coal fuel source alongside WoodLog -->
<xpath>*/ThingDef/comps/li[@Class = "CompProperties_Refuelable" and fuelFilter/thingDefs/li[text() = "WoodLog"]]/fuelFilter/thingDefs</xpath>
<value>
<li>Coal</li>
</value>
</li>
</operations>
</Operation>
Comments should make that pretty self-explanatory. Simples! To everyone who hasn't learned about XPathing, I highly suggest the
W3CSchools tutorial at least (although it doesn't seem to mention text() and other node tests which is curious, info about them can be found
here).
Aside: Regarding the Coal, I'm working on a mod which makes Coal and Charcoal three-time as potent a fuel source as Wood Logs, among many other things (I only just started learning C# yesterday, and coming from Java + ASM for Minecraft modding, this .NET and Harmony library is an absolutely beautiful change and I can't get over how easy this game is to mod... just look at it <3).
I hope this thread gets some exposure so we can see modders making their work as compatible and optimized as possible
