EnumExtender

From Rain World Modding
Jump to navigation Jump to search

Legacy article
This article contains information that is only relevant for legacy versions of the game (1.5 or lower)

"EnumExtender"
No image
Details
Tool type
Dependency library
License
CC0
Authors
Bee
Release links
source, latest build


EnumExtender or EE is a tool mod which allows adding entries to Enums. It is widely used as a dependency library.

Features

EE allows the user to add entries to enums at runtime in two ways:

  • Automatic (does not require referencing EE assembly in your project)
  • Manual (requires referencing EE assembly in your project)

Usage

Automatic extension

On initialization, EE scans all loaded classes, looking for public static class with names starting with EnumExt_.

Extensions are created from public static fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use:

public static class EnumExt_MyMod
{ // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum
    
    //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID"
    public static CreatureCommnuities.CommunityID Vultures;
    //this adds "YellowishWhite" to "SlugcatStats.Name"
    public static SlugcatStats.Name YellowishWhite;
    public static SlugcatStats.Name WhitishYellow;
}

To access these new enum items, instead of [enum].[item], use that static field.

To compare it, use if statements (unfortunately, you can not use static fields for branches in a switch statement). Example use:

public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished)
{
    orig.Invoke(stats, slugcatNumber, malnourished);
    if (stats.name == EnumExt_MyMod.YellowishWhite)
    {
        stats.runspeedFac = 1.2f;
        stats.poleClimbSpeedFac = 1.25f;
        stats.corridorClimbSpeedFac = 1.2f;
    }
}

However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0.

This can be used to easily detect whether EnumExtender is installed or not.

public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0;
// This property returns true after EE initializes (after OnEnable)

Switch statement workaround

If you have multiple new items and really want to use switches, you can do something like the following:

public static class EnumSwitch
{
    //the intermediary enum
    public enum SlugcatStatsName
    {
        DEFAULT = -1, // unrelated to this mod
        YellowishWhite,
        WhitishYellow

    };

    public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)
    {
        if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed
        if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }
        if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }
        return SlugcatStatsName.DEFAULT;
    }
}

And when you need to use switch later,

switch (EnumSwitch.GetSlugStatsNameInterm(name))
{
    default:
    case SlugcatStatsName.DEFAULT: break;
    case SlugcatStatsName.YellowishWhite:
        break;
    case SlugcatStatsName.WhitishYellow:
        break;
}


Manual extension

This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but

  1. Ensure that EE has been initialized. You can either wait until the EnumExt_ get appropriate values, or call PastebinMachine.EnumExtender.EnsureInit()
  2. Call PastebinMachine.EnumExtender.AddDeclaration(Type, string) one or more times. First parameter is Type of the enum, second is the name of new entry. Ensuring there are no name collisions is on you!
  3. Call PastebinMachine.EnumExtender.ExtendEnumsAgain once to register all your new enums.

NOTE: Last step may have a noticeable overhead, and each call to ExtendEnumsAgain causes a small but permanent memory leak. Do not overuse. ExtendEnumsAgain does not return the added values, you have to obtain them manually through Enum.GetNames() or Enum.GetValues(). Storing the resulting values correctly is the user's responsibility.

Summary

Both modes allow you to use methods like Enum.Parse with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency.