Comparison of Unity plugin framework implementations

The table below lists a comparison of features and implementation details of Unity plugin frameworks that are considered "modern". As a disclaimer I am a developer of BepInEx which has likely influenced which properties I have compared together.

Project comparison BepInExIPABSIPAUnity Mod ManagerMelonLoader
Actively maintained Yes No Yes Yes Yes
Code license LGPL MIT MIT MIT Apache 2.0
Project language C# C# C# C# C# / Rust
Game specific No No Beat Saber No No
Nightly builds Yes No No No Yes
Backwards compatible versioning Semver No Semver No Semver
Game engine support BepInExIPABSIPAUnity Mod ManagerMelonLoader
3.x Yes Likely No No Yes
4.x Yes Likely Likely Unknown Yes
5.X Yes Yes Yes Yes Yes
2017.X Yes Unofficially Yes Yes Yes
2018.X Yes Unofficially Likely Yes Yes
2019.X Yes Unofficially Yes Unknown Yes
2020.X Yes Unofficially Likely Unknown Yes
IL2CPP Yes No No No Yes
Platform support BepInExIPABSIPAUnity Mod ManagerMelonLoader
Windows Yes Yes Yes Yes Yes
Mac OSX Native Partial Wine/Mono No Wine/Mono No
Linux Native + Proton Partial Wine/Mono Wine Wine/Mono Wine (Native Unstable)
ARM No No No No LemonLoader
Feature support BepInExIPABSIPAUnity Mod ManagerMelonLoader
External console Yes No color Yes No Yes
Configuration Yes (TOML) No Yes (JSON) Yes (XML) Yes (TOML)
Plugin logging Yes Direct to console Yes Yes Yes
Extensible logging system Yes No Yes No No
Plugin manifests Attribute only No Yes Yes Attribute only
Plugin-level dependency sorting No semver No Yes Yes Yes
Loader version checking Yes No Yes Yes Yes (Installer only)
Multi-game directory support Yes Yes No No Yes
Preloader patches Yes No No No No
Preloader assembly swapping Yes No No No No
Inbuilt manager plugin No No Yes Yes No
Plugin and loader auto-update No No Yes Yes No
Manager tool Unofficially No Yes Yes Installer only
Plugin hot loading Unofficially No Yes No Yes
dnSpy debug helpers Yes No No No Yes
Mechanism BepInExIPABSIPAUnity Mod ManagerMelonLoader
Patchless loading Yes No Partial, windows only Windows only Yes
Patched loading Partial Yes Yes Yes No
Drag + drop installation Yes No Yes No Yes
Survives updates / integrity checks Yes No Yes Only updates Yes
Inbuilt Harmony support 2.x (HarmonyX) No 2.x 2.x 2.x (HarmonyX)
Inbuilt MonoMod.RuntimeDetour support Yes No No No Yes
Inbuilt Il2CppInterop support Yes No No No Yes
Unity hotfixes BepInExIPABSIPAUnity Mod ManagerMelonLoader
Assembly.AppBase + Location unicode fix Yes No No No No
Unity 2018.X .NET Standard Reflection.Emit fix Yes No Yes Yes No
Unity 4.x incomplete console implementation fix Yes No Yes No Yes
Unity <= 5.x incomplete trace implementation fix Yes No No No No
Terminfo2 support in underlying Mono console driver Yes No Partial No No
Unix stdout redirection fix Yes No No No No


Project comparison

Actively maintained

Pretty straightforward. Has the project receieved an update in the last 12 months?

Code license

The license that the source code is under. It restricts what you can do with the code.

Project language

The programming language used in the framework, and by extension the language of plugins it supports.

Note that supporting plugins created in a language that executes native code (i.e. C/C++), or a language that is not able to be easily decompiled (also C/C++) is a security risk.

Game specific

If the loader is mainly intended for a single game and is not easily usable on other games, then it would be difficult to work with.

Nightly builds

Does the project have automatic builds for code commits pushed to master?

Backwards compatible versioning

If the version numbers of the framework indicate that major versions break API/ABI, then the framework has this property.

The most popular form of this versioning system is Semantic Versioning. If a major version number changes (i.e. 1.0.0 -> 2.0.0), then it is not considered backwards compatible. If any number less than that changes (i.e. 1.0.0 -> 1.1.0), then it is still considered backwards compatible.




Unity engine support

A matrix of which Unity versions the framework supports. You can determine what version of Unity your game is by right clicking on the game .exe -> Properties -> Details -> Version.

Note that all versions except for IL2CPP are for Mono runtime games.




Platform support

The operating systems that the framework supports (and in the case of ARM, the type of processor too).

For Linux and Mac OSX, there are four types of support:

  1. Native: The framework can be executed as-is on this platform.
  2. Wine: The loader can be ran through an emulator program called Wine that allows Windows programs to run on Linux/OSX. Can be prety slow.
  3. Proton: The loader can be run via Proton, which is Steam's version of Wine. It generally performs better than Wine, and has better support for games (anything that Wine can run, Proton can run too)
  4. Mono: The loader can be executed/installed via Mono, which is a cross-platform of the .NET Framework runtime. It has very little overhead.

BepInEx supports both native execution, and execution through Proton for games that do not have a Linux/OSX version.

Both IPA and UMM support Mono for their installers. However IPA only has partial support without Wine, as it performs Windows system calls without checking what OS it is running under, and can break itself.

BSIPA only supports Wine on Linux. OSX may work too, but is untested.

MelonLoader mainly supports Windows and Wine. Linux support can be unstable.




Feature support

External console

If the loader can spawn an external console window, then the framework has this property.

Configuration

Does the loader have a framework for plugin-specific configuration? If so, what configuration file format does it support?

Plugin logging

If the framework supports logging per-plugin, then this property is satisifed. Half points if the plugin has to manually identify itself in the log output.

Extensible logging system

Does the logging system support custom listeners? Can plugins create multiple log sources for their own nefarious uses?

Plugin manifests

Whether or not the framework supports reading metadata from the plugin itself.

BSIPA and UMM support a complex .json file embedded in the plugin, however BepInEx and MelonLoader only support metadata from code attributes.

Plugin-level dependency sorting

Plugins support listing other plugins as dependencies, and the framework will ensure that they are loaded in such an order that all dependencies have already been loaded.

BSIPA and UMM also support adding a version range to this, to ensure that it only loads if the dependencies are also the correct version, and not just the order.

Loader version checking

Similar to above, but for ensuring that plugins are only loaded on framework versions that the plugins are compatible with.

Multi-game directory support

Whether or not the loader can execute in directories that contain more than one Unity game, and contains load filters to ensure that plugins are not loaded in games that they are not supposed to load in.

Preloader patches

The loader supports executing .DLL edits in-memory. This is different to something like a Harmony hook, as this allows editing the actual .DLL itself.

This is extremely powerful, especially for doing things that Harmony cannot do (for example, adding values to an enum)

Preloader assembly swapping

Similar to above, but allows switching a .DLL file being loaded with another one.

Inbuilt manager plugin

A built-in plugin that allows the user to perform maintenence tasks, such as enabling and disabling other plugins from loading at launch.

Plugin and loader auto-update

Whether or not the loader has a framework that performs things like auto-updating for both plugins and the launcher itself.

Manager tool

An external tool that handles framework/plugin installation, and plugin enabling/setup.

BepInEx has an unofficial manager tool in Risk of Rain 2.

Plugin hot loading

Plugins can be unloaded and reloaded on demand.

BepInEx only supports this via a developer tool.

dnSpy debug helpers

Hooks are included that help integration with dnSpy debugging (such as triggering breakpoints).




Mechanism

Patchless loading

The loader can execute without needing to patch/edit any files of the game.

BSIPA is considered partial, as while it does not need patching to initially execute, it will patch the game's assemblies for future startups.

Patched loading

The inverse to above, where the game's files are patched to facilitate loading. If this loader supports patchless loading, than patched loading exists as a secondary entrypoint instead of the primary entrypoint.

Drag + drop installation.

As it says on the tin. The loader can be installed by simply dragging and dropping the files on top of the install; no additional installation required.

Inbuilt Harmony support

If the framework carries it's own distribution of the Harmony hooking library, and the version it uses.

Inbuilt Harmony support

The framework carries it's own distribution of the MonoMod.RuntimeDetour hooking library.




Unity hotfixes

Assembly.AppBase + Location unicode fix

Fixes a bug where Assembly.AppBase and Assembly.Location will output garbled text if the game is in a folder path that contains unicode characters.

Unity 2018.X .NET Standard Reflection.Emit fix

Fixes Harmony hooking on versions of Unity 2018 that break System.Reflection.Emit methods. Note that this is not an issue in MonoMod.RuntimeDetour, and is fixed on Harmony versions 2.0 and above.

Unity 4.x incomplete console implementation fix

Fixes issues with the Console class not supporting things like foreground and background color, and the Title property.

BepInEx and MelonLoader fix this by providing new Console implementations.

Unity <= 5.x incomplete trace implementation fix

Fixes issues with the Trace class calling an incorrect method when reporting a Trace event.

Terminfo2 support in underlying Mono console driver

Fixes color terminal support on Linux/OSX/Unix systems.

BSIPA has a partial fix that only works for Terminfo1 TTY terminals.

Unix stdout redirection fix

Fixes stdout logging on Unix platforms, as Unity consumes the data when it shouldn't.




Page layout stolen from http://www.etalabs.net/compare_libcs.html