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.