BepInPlugins

From Rain World Modding
Jump to navigation Jump to search

BepInPlugins are the predominant form for Rain World code mods.

They are a form of game mod native to BepInEx. They are not compatible with Partiality.

Creating a BepInPlugin[edit source]

Prerequisites[edit source]

  • A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary)
  • Rain World with RW BepInEx set up - see here.
  • Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice.
    • The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8)

Step 1 - The project[edit source]

Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to add some references.

It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are:

  • BepInEx/core/BepInEx.dll
  • BepInEx/plugins/HOOKS-Assembly-CSharp.dll
  • BepInEx/utils/PUBLIC-Assembly-CSharp.dll
  • RainWorld_Data/Managed/UnityEngine.dll
  • RainWorld_Data/Managed/UnityEngine.CoreModule.dll

Step 2 - The BepInPlugin class[edit source]

In a your new C# file, make a public class that has the BepInEx.BepInPlugin attribute and inherits from BepInEx.BaseUnityPlugin . The BaseUnityPlugin class inherits from MonoBehaviour, so you can use standard Unity script methods such as OnEnable and OnDisable in this class.

The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the username.mode_name format.

Include an assembly-level SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true) declaration alongside your plugin class. This prevents errors later down the line.

using BepInEx;
using System.Security.Permissions;
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
namespace SomeMod
{
    [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)
    public class MyModName : BaseUnityPlugin
    {

    }
}

Step 3 - Hooking[edit source]

Hooks allow you to execute your own code when the method you are hooking from the game code is called.

Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or OnEnable, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:
namespace SomeMod;

[BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")]
public class MyMod : BaseUnityPlugin
{
    public void OnEnable()
    {
        /* This is called when the mod is loaded. */
        // subscribe your PlayerUpdateHook to the Player.Update method from the game
        On.Player.Update += PlayerUpdateHook;
    }

    void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)
    {
        /* This method will be subscribed to Player.Update. */
        orig(self, eu);

        /* Calling orig is what allows the original method and
         * other hooks to the same method do their thing.
         * Not calling this is almost always undesirable, and
         * can cause big issues.
         *   You can execute code before or after the call of
         * orig as necessary.
         */

    }

}


Note that our hook there - PlayerUpdateHook - takes the orig method, the Player object whose Update method was called (since Player.Update is not static), and the parameters taken by the original method.

If you have many hooks consider organising them, perhaps into separate classes.
"Where can I find these magical and elusive Rain World methods?"
Since the source code for Rain World is not public, one must use a decompiler such as DnSpy or ILSpy to look through the Assembly-CSharp.dll file.

Reminder: you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see GitHub's guide to code licensing and if in doubt ask the author.

Testing your code[edit source]

Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to:

  1. Create a folder and JSON for your mod, as described by Downpour Reference/Mod Directories, and
  2. Copy your mod DLL to a plugins folder within your mod's folder, as described by Downpour Reference/BepInEx Files.
  3. Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button.
    • At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod.

Enums[edit source]

Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use Downpour Reference/ExtEnum.

Advanced Techniques[edit source]

IL Hooking[edit source]

IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code.

Risk of Thunder's guide to IL hooking can be found here.

RuntimeDetour[edit source]

RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters.

A brief guide can be found on the MonoMod RuntimeDetour page. MonoMod's RuntimeDetour guide can be found here.

Harmony Patching[edit source]

Harmony patching is a form of runtime patching.

The HarmonyX wiki can be found here.