DocFX + Singulink = ♥
Edit this page

Writing Custom Features!

Basics

Before writing any custom features, you'll need to make a BepInEx plugin that references SlugBase. You can download those binaries from the Releases page on GitHub.

At its core, defining a feature just requires you to instantiate Feature<T>. The constructor takes a string ID (the same one that you must specify in your character's JSON) and a delegate that converts a JsonAny into T. Accessing your feature requires a SlugBaseCharacter instance, which you can find via SlugBaseCharacter.TryGet.

In most cases, neither parsing your own data nor getting the SlugBaseCharacter will be necessary.

Simple Features

For most features, FeatureTypes will provide a suitable factory method that does the parsing for you.

using static SlugBase.Features.FeatureTypes;

[BepInPlugin("mycoolplugin", "My Cool Plugin", "1.2.3")]
class MyCoolPlugin : BaseUnityPlugin
{
    static readonly PlayerFeature<float> SuperJump = PlayerFloat("super_jump");
}

Then, you implement it with hooks:

void Awake()
{
    On.Player.Jump += Player_Jump;
}

void Player_Jump(On.Player.orig_Jump orig, Player self)
{
    orig(self);
    if(SuperJump.TryGet(self, out var superJump))
    {
        self.jumpBoost *= 1f + superJump;
    }
}

SlugBase provides two types of features: PlayerFeature<T> and GameFeature<T>. These allow you to get the feature's data by Player or RainWorldGame instance. If you've hooked a method that doesn't have access to either of those, getting by SlugBaseCharacter still works.

Warning

If you construct your features in a static constructor or static field initializer, you must make sure that it is called during mod initialization! Consider placing feature fields directly in your BaseUnityPlugin.

Advanced Features

If FeatureTypes doesn't have the data type that you need, you'll need to pass in your own factory delegate:

static readonly GameFeature<Dictionary<CreatureTemplate.Type, float>> CreatureHealth = new("creature_health", json =>
{
    var result = new Dictionary<CreatureTemplate.Type, float>();
    
    foreach (var pair in json.AsObject())
        result.Add(new(pair.Key), pair.Value.AsFloat());

    return result;
});

After that it acts the same as any other feature. If the JSON data is invalid, consider throwing a JsonException, passing in the offending JSON element. This will give the modder a descriptive error with a path to that element.

Reloading Features

You can change a feature's value at any time by modifying the character's JSON file. Your features might not work properly with this right off the bat. If a feature you've implemented needs to update the game state upon reload, consider subscribing to SlugBaseCharacter.Refreshed. This event is only raised while in-game.