Modding Tutorials/DefModExtension

From RimWorld Wiki
Jump to navigation Jump to search

Modding Tutorials

A DefModExtension is a way to add fields to Defs. DefModExtensions are a simple way to extend functionality to a Def. A DefModExtension doesn't directly add fields to classes as that's technically impossible to do at runtime. The implementation is that the Def class has a public List<DefModExtension> which can easily be extended.

+ Is really simple and light-weight to use.
+ Works on any Def.
+ Exposes its functionality to XML.
+ Compatible with savefiles, other mods, you name it.
+ Does not come with the compatibility issues and pitfalls of creating a custom Def class.
+ Does not have the overhead of a ThingComp.
+ More broadly applicable than a ThingComp (not every Def is a ThingWithComps!).

- Static and global data.
- Can't save data.
- Only works on Defs.
- A DefModExtension does not know what Def it belongs to. (There are ways around this, like setting a Def field in your DefModExtension and populating it in XML/C#)


You know the deal by now.

  • Solution
  • Custom code
  • C#
  • XML

The Code[edit]

using Verse;

namespace ExampleNameSpace
    public class ExampleModExtension : DefModExtension
        public bool canBeARimQuest = true;

That's it. DefModExtensions can of course contain any field you wish: a C# Type, a Thingfilter, a list -- but for the sake of a simple example, we'll use a bool.

Using the DefModExtension[edit]

You can use the DefModExtension on any Def with that extension. Their usage is much the same way as any other field in a Def. The biggest difference is in the syntax; instead of bool value = def.field, it's bool value = def.GetModExtension<ExampleModExtension>().field

using Verse;
using RimWorld;

namespace ExampleNameSpace
    public class OurExampleClass
        private static bool IsAcceptableQuest(IncidentDef incidentDef)
            if (incidentDef.letterDef == LetterDefOf.NegativeEvent)
                return false;

            if (incidentDef.HasModExtension<ExampleModExtension>())
                return incidentDef.GetModExtension<ExampleModExtension>().canBeARimQuest;

            return true;

Or if you like your code shorter, you can use null conditionals and null coalescing:

            return incidentDef.letterDef != LetterDefOf.NegativeEvent
                && (incidentDef.GetModExtension<ExampleModExtension>()?.canBeARimQuest ?? true); 
                //will return value of mod extension if not null, otherwise assumed true.

Adding it to your def[edit]

            <li Class="ExampleNameSpace.ExampleModExtension">

Using xpath to add it to a def[edit]

If you wanted to xpath patch a mod extension onto an existing def, you'd use PatchOperationAddModExtension, which is like PatchOperationAdd but saves having to check if modExtensions has already been added/having to include it in your value field:

    <Operation Class="PatchOperationAddModExtension">
            <li Class="ExampleNameSpace.ExampleModExtension">

See also[edit]

Ludeon thread on Mod Extensions
The pull request on which the code in this article is based on