RimWorld Modding Resources

A community-collated hub for all things RimWorld Modding.


Project maintained by spdskatr Hosted on GitHub Pages — Theme by mattgraham

Abstracts and inheritance

Abstracts

Like programming languages, XML adheres to the DRY principle. DRY stands for Don’t Repeat Yourself, and I just broke the DRY principle. It implements this in two ways: Inheritence and Abstracts. Let’s use the example of ThingsDefs_Misc\Weapons_Base.xml. In there is a partial Def which contains the most basic and universally applicable entries required for a weapon. It doesn’t have a defName, but instead it is called:

<ThingDef Abstract="True" Name="BaseWeapon">

If you’ve got a weapon you’re pretty much guaranteed to need the things in there. This is an Abstract, meaning it’s not generated by the game but only used as a base for other XML entries to build upon. It’s not a complete entry either, which is why it needs to be an Abstract. You use abstracts for partial Defs, things you’d otherwise end up copy-pasting without modifying ten times over.

You can inherit from this, but DON’T copy it over in your mod or otherwise include it. If you inherit from it (use it as a parent) you use it. If you copy-paste that over in your mod, you cause incompatibilities with other mods. Why? Because other mods inherit from it, and when there are two versions of the Abstract to inherit from, things go bad.

Next step, the example of ThingDefs_Misc\Weapons_Guns.xml

Inheritance

So we have the building blocks for a Def, with the name of BaseWeapon. If we want to use that to build upon, we will need to inherit from it. We do this by creating another Abstract and using the BaseWeapon as a parent, like so:

<ThingDef Name="BaseGun" Abstract="True" ParentName="BaseWeapon">

This is another Abstract, meaning it’s not generated by the game. Note that the ParentName is BaseWeapon, which was defined in ThingDefs_Misc\Weapons_Base.xml - by inheriting from BaseWeapon, it includes all the values in there. We have effectively removed the need to copy-paste the same values in BaseWeapon for both the melee and the ranged weapons, by splitting off from the base and defining the category and tech level for our weapon. The flexibility of adding more building blocks as we go becomes apparent as we go down to

<ThingDef Name="BaseMakeableGun" ParentName="BaseGun" Abstract="True">

This Abstract includes everything from BaseGun and BaseWeapon, because BaseMakeableGun uses BaseGun as a parent, and BaseGun uses BaseWeapon as a parent. This Abstract simply adds the gun to the Machining Table, allowing players to make it. The last step is

<ThingDef ParentName="BaseHumanMakeableGun">
    <defName>Gun_Revolver</defName>

Note that this is the first time we include a defName. This is the eventual Thing that actually gets generated in the game. It contains all the basic information provided in the preceding Parents, and all the specific things that makes this Def unique.

If you make a mod, inherit from as far down the inheritence chain as possible. If you need to alter a single value, you can still inherit and overwrite that single value in your individual item - as long as it’s not in a list. If it is in a list, the inherited member appends to the list rather than replaces.

If you make a weapon or whatever that will require heavy altering, it’s advised to make your own abstract, again inheriting from as far down the chain as you can - mostly because that avoids duplicating and copy-pasting needless code. If you make an abstract, give it a unique name by using your mod name, initials, or whatever. It’s pretty much guaranteed that some other modder will have “BaseMakeableModGun” as an abstract, and that’ll cause you and your users headaches like no tomorrow.

Summary

A Def can have both a Name attribute and a defName.

The defName can be literally anything, and it just is a unique way to identify a specific def. All non-abstract defs have a <defName>NAME</defName> tag.

The Name is an attribute used specifically so XML can tag specific defs and refer to them later. It is declared inline with the def declaration, like <ThingDef Name="NAMEOFTHING">, rather than as a separate node. Not all Defs have to have a Name attribute, but the ones that do can be inherited by items that refer to them with a ParentName attribute.

Closing thoughts, random stuff