Modding Tutorials/Compatibility with defs
In this tutorial you will learn different ways to make XML mods compatible and how to link existing and modded recipes, facilities and buildings with eachother.
What you'll learn
You'll learn how to implement your mods into existing defs, how to fix compatibility between XML mods and how to make modded recipes, facilities and buildings interact with eachother without overwriting the base game.
The least elegant way to go about compatibility is to have a modified copy of a core def in your mod file. You have to rely on load order to make the mod work, let's say you want to change the damage of a pistol:
Core/ Defs/ ThingDefs/ Weapons_Guns.xml YourModName/ Defs/ ThingDefs/ YourFileName.xml
.. and contents:
<?xml version="1.0" encoding="utf-8"?> <Defs> <!-- base parent <Def>'s --> <ThingDef ParentName="BaseBullet"> <defName>Bullet_Pistol</defName> <projectile> <DamageAmountBase>9</DamageAmountBase> </projectile> <!-- more tags --> </ThingDef> <!-- more <Def>'s --> </Defs>
The above code adds something that already exists on the /Core/ mod - to make it overwrite the core mod, this mod has to be loaded after it. Practically every mod is loaded after the core mod, so this shouldn't be a problem.
The problem arises when multiple mods edit Bullet_Pistol, and as a rule of thumb the last loaded version of a defName is kept.
|I modify..||What do?|
|..Core..||..Def values||Add the defs you want to overwrite to your mod and load the mod after Core|
|..Class references||Add the defs you want to overwrite to your mod and load the mod after Core, use C# to modify def classes.|
|..a mod's..||..Def changes..||..directly||Make a choice which value to keep (merge them if possible) - if it's the only difference in the core def overwrites between the mods, simply loading one after the other will fix the compatibility, if that's not possible make a merged patch|
|..collaterally||The easiest way to fix this is by making a patch, including the same def with both modifications applied to them - this def can then be loaded after both of the mods2|
|(both of the above)||Make a compatibility patch: take the def from both mods and try to merge as many values as you can, compare it to the core def, see if you can figure it out through XML only|
|..Class reference changes..||..directly||E.g <thingClass> added twice: create a DLL patch3|
|..not directly||E.g Mod A <ThingDef> and Mod B <projectile> Class changes: this will work fine with an XML patch3|
|..Def values..||..intentionally||Add the defs you want to overwrite to your mod and load it after their mod1|
|..unintentionally||Rename your defs, try to figure the compatibility out through contacting the author, make a compatibility patch|
|..Class references||E.g <ThingDef Class="namespace.class"> added twice: create a DLL patch3|
- If your mod requires another mod to function and you want to change something about their mod, let's say CustomShotgun should do 20 damage instead of 25, your mod has to include CustomShotgun's def and be loaded after their mod.
- Mod A changes CoreDef's label to "hunting shotgun", mod B changes CoreDef's soundInteract to "InteractPistol", patch AB does both to fix their compatibility issues.
- When mod A adds Class="ModANamespace.ModAClass" to a defName's ThingDef and mod B adds Class="ModBNamespace.ModBClass" this is a non XML-patchable incompatibility. This means that if A adds a Class to the <projectile> tag and B adds a Class to the <thingDef> tag you're perfectly fine. This tutorial won't cover creating DLL patches because it's more in-depth, but create a DLL patch and C# injection will.
In case your mod adds a new recipe for the Cook stove, you might think it's necessary to overwrite part of its thingDef. This is however completely unnecessary - the C# code base contains a tag which allows you to make your recipe choose which building to attach to (instead of the other way round):
<?xml version="1.0" encoding="utf-8"?> <Defs> <RecipeDef> <defName>BakeBread</defName> <recipeUsers> <li>CookStove</li> </recipeUsers> <!-- more tags --> <!-- more tags --> </RecipeDef> </Defs>
If you want your building to choose which recipes to display, you do the following:
<?xml version="1.0" encoding="utf-8"?> <Defs> <ThingDef> <defName>BakeryOven</defName> <recipes> <li>BakeBread</li> </recipes> <!-- more tags --> </ThingDef> </Defs>
The BakeBread recipe will now show up in both the BakeryOven and CookStove, without the mod having to modify CookStove's <recipes> list.
Buildings with the "CompAffectedByFacilities" compClass can choose which facilities should link to them. In the base game it isn't used the other way round - facilities don't do this - but the C# code base has a tag for it:
<?xml version="1.0" encoding="utf-8"?> <Defs> <ThingDef> <defName>BadIdeaShredder</defName> <comps> <li> <compClass>CompFacility</compClass> <statOffsets> <ResearchSpeedFactor>0.05</ResearchSpeedFactor> </statOffsets> <linkableBuildings> <li>ResearchBench</li> </linkableBuildings> </li> </comps> <!-- more tags --> </ThingDef> </Defs>
Linking existing facilities to modded buildings is also possible by doing what existing buildings already do:
<?xml version="1.0" encoding="utf-8"?> <Defs> <ThingDef> <defName>MyFirstWorkshop</defName> <comps> <li> <compClass>CompAffectedByFacilities</compClass> <linkableFacilities> <li>ToolCabinet</li> </linkableFacilities> </li> </comps> <!-- more tags --> </ThingDef> </Defs>
BadIdeaShredder can now be attached to the vanilla ResearchBench, and the vanilla ToolCabinet can now be attached to MyFirstWorkshop.