Open-source project
NeighTools/UnityDoorstop avatar
NeighTools/UnityDoorstop

Doorstop runs your .NET assembly inside Unity before Unity starts

Doorstop -- run C# before Unity does!

596 stars97 forksCLGPL-2.1

At a glance

What is it?
Unity Doorstop is an LGPL licensed C bootstrapper that injects managed .NET assemblies into a Unity game before the engine initialises, working on the Mono runtime and on Il2Cpp through CoreCLR. It suits a game modder or tool author who needs to run code in a Unity process, and it cannot touch the native game code in an Il2Cpp build.
Who is it for?
Unity Doorstop fits a Unity mod or tooling author who needs managed code running at the earliest possible point in a game process, and who needs the same assembly to work on both Mono and Il2Cpp builds.
Can I use it commercially?
Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A bootstrapper that gets in before the engine does

Doorstop is a tool to execute managed .NET assemblies inside Unity as early as possible. The project description in the repository is blunter: run C# before Unity does.

The four listed features explain the scope. It runs first, before Unity can run its own code. It is configurable, through an elementary configuration file that specifies which assembly to execute. It is multiplatform, covering Windows, Linux and macOS. And it supports debugging of managed assemblies in Visual Studio, Rider or dnSpy without modifications to Mono.

That last point is the one that separates Doorstop 4 from the older generation of Unity loaders. The documentation is specific that this is a total rewrite of UnityDoorstop 3, with a separate list of breaking changes in CHANGES.md. A rewrite of a component that runs before the engine means the hook points, the configuration keys and the environment variables are all different from version 3, and a mod that worked there needs work here.

The user is a person writing a mod or an external tool for a Unity game who needs their code to run before the game decides what to load, so that they can patch behaviour, redirect assembly loading, or attach a debugger to the managed side of the process.

Mono and Il2Cpp take two completely different paths

Doorstop supports both Unity runtimes, and the documentation is careful to say the two are not variations on a theme. They are separate execution models with separate requirements.

On Unity Mono, your assembly is executed in the same runtime. You do not need to include your own Common Language Runtime, because the one bundled with the game is used. Your assembly runs alongside other Unity code, and you can access the Unity API directly.

On Il2Cpp, Il2Cpp cannot run managed assemblies, so your assembly is executed in a CoreCLR runtime instead. The consequences are concrete: you need to include .NET 6 or newer CoreCLR runtime with your managed assembly, your code runs in a runtime isolated from Il2Cpp, and you can reach the Il2Cpp runtime only by interacting with its native il2cpp_ API.

That last point is where the practical work is. On an Il2Cpp build you are crossing a boundary between two runtimes, and the interface is a set of native calls. You can call into the game, but you are not inside the game's managed world, and the game's own code was compiled to native code ahead of time.

So the same Doorstop assembly can serve both, but the work to make it do something on an Il2Cpp game is a different project from the work on a Mono game.

The entrypoint contract is one class and one static method

The injection contract is deliberately small. To have Doorstop inject your code, you create an Entrypoint class in the Doorstop namespace and define a public static Start method in it.

cs
using System.IO;

namespace Doorstop;

class Entrypoint
{
  public static void Start()
  {
      File.WriteAllText("doorstop_hello.log", "Hello from Unity!");
  }
}

Once that method is in place you can define any code you want in it. The example writes a log file, which is the smallest possible proof that the injection worked, and the file it writes is the first thing to check when a build does nothing.

The documentation is candid about the limits of this early timing. On Unity Mono, Doorstop bootstraps your assembly with a minimal number of assemblies and minimal configuration. That early execution allows for some interesting tricks, such as redirecting the loading of some game assemblies. But some of the Unity runtime is not initialised at such an early stage, which limits the code you can execute, and you might need to appropriately pause the execution of your code until the moment you want to modify the game.

That is the central trade-off of the whole tool. Maximum earliness is what makes redirection possible, and it is also what makes the Unity API unreliable at that point. A well built Doorstop mod waits for the right moment rather than assuming the engine is ready.

Environment variables tell your code where it is running

Doorstop sets a set of environment variables that a loaded assembly can read to work out its surroundings. They are listed in a table in the documentation and are worth knowing by name, because they are the supported way to locate things rather than guessing paths.

DOORSTOP_INITIALIZED is always set to TRUE, and the documented use is to determine whether your code is running via Doorstop. DOORSTOP_INVOKE_DLL_PATH gives the path to the assembly Doorstop executed, relative to the current working directory. DOORSTOP_PROCESS_PATH gives the path to the application executable where the injected assembly runs. DOORSTOP_DLL_SEARCH_DIRS lists the paths where the runtime searches for assemblies by default, separated by the OS specific separator, which is a semicolon on Windows and a colon on Unix style systems.

Two of them depend on the runtime. DOORSTOP_MANAGED_FOLDER_DIR points at the game's Managed folder on Unity Mono, and at the CoreCLR base class library folder on Il2Cpp. DOORSTOP_MONO_LIB_PATH gives the full path to the mono runtime library, and it only exists on Unity Mono.

The practical use is straightforward. A mod that needs to find the game's data directory reads DOORSTOP_PROCESS_PATH and works from there, rather than assuming it is installed in a Steam library or a GOG folder. A mod that needs to load its own dependencies reads DOORSTOP_DLL_SEARCH_DIRS to know where the runtime will look.

Debugging managed code on Mono, and the dnSpy shortcut

Debugging is where Doorstop 4 puts real distance between itself and the older approach, and the Mono path is the more developed of the two.

To enable it you set debug_enabled to true and can optionally change the debug server address with debug_address. After launching the game you connect to the debugger using that server address, which defaults to 127.0.0.1:10000. By default the game does not wait for the debugger to connect, and you can change that with the debug_suspend option, which is what you want when you are attaching after a breakpoint rather than before launch.

There is a convenience worth taking. If you use dnSpy, its Debug, Start Debugging, Debug engine, Unity option sets the correct debugging configuration, and Doorstop detects dnSpy and automatically enables debugging without any extra configuration. So on dnSpy the setup is close to zero, and on Visual Studio or Rider you configure the address yourself.

The documentation is careful about the scope: this is debugging the assemblies in the runtime, not the game. The feature list says it works without modifications to Mono, which is the point, because the alternative for a mod author used to be shipping a patched Mono build.

On Il2Cpp you debug CoreCLR, and only managed code

The Il2Cpp debugging story is different in kind rather than in degree, and the documentation says so plainly.

Debugging is automatically enabled in CoreCLR. To start, you compile your DLL in debug mode with embedded or portable symbols and start the game with the debugger of your choice, or you attach a debugger to the game once it is running. All standard CoreCLR debuggers should detect the CoreCLR runtime in the game. Hot reloading is supported for Visual Studio, Rider and other debuggers with the .NET 6 hot reloading feature enabled.

Then the limitation, stated without softening: you can only debug managed code. Because the game code is unmanaged, that is, Il2Cpp, you cannot directly debug the actual game code. The documentation's advice is to consider native debuggers such as GDB and visual debugging tools like IDA or Ghidra for that.

So the two runtimes give you two different debugging experiences. On Mono you attach a managed debugger to the game's own managed code, because the game is still managed. On Il2Cpp you debug your own assembly inside a separate CoreCLR, and the game itself is native code that your managed debugger cannot see. Anyone planning a mod for an Il2Cpp title should know that before writing the first line, since the tooling path is completely different.

Configuration comes from an ini file or from command line arguments

Doorstop is configured in one of two ways, and the documentation covers both.

Via a configuration file, the reference files are doorstop_config.ini in the assets/windows directory for Windows and run.sh in assets/nix for the Unix style systems, and those files carry the full set of available options.

Via command line arguments, the arguments are available on both Unix style systems and Windows builds, and they all start with --doorstop- and always contain an argument. There are two argument types. A bool is true or false, and a string is any sequence of characters and numbers, which you wrap in quotes if the string contains spaces.

The build side is comparable in simplicity. Doorstop uses xmake to build the project, and you build it by running build.bat, build.ps1 or build.sh. The available build options are -with_logging to build with logging enabled, -arch for the architectures to build for separated by commas, for example -arch x86,x64, and -debug for a debug mode build, which is currently only for Unix style systems. The documentation notes that initial build times are usually slower because the build script downloads and installs xmake automatically, and that on Unix xmake is built directly from the source code.

The repository root is small and matches this: src/ for the C sources, assets/ for the per platform binaries and configuration templates, xmake.lua as the build definition, build scripts for the three platforms, info.lua, and the CHANGES.md file.

An LGPL loader that the modding community actually depends on

The licence is LGPL-2.1, with the LICENSE file at the root of the repository. That matters more for this project than for a typical library, because the code is injected into a game process, and the question of what a mod author may redistribute with their mod is a practical one rather than a theoretical one.

The maintenance picture is healthy and the release history shows it. The listed releases are Version 4.6.0 on 2026-10-19, Version 4.5.0 on 2026-02-04 and Version 4.4.1 on 2025-09-02, and the last push was on 2026-10-19, the same day as the 4.6.0 tag. The repository is not archived.

The cadence of roughly two to eight months between releases, with a burst right after the 4.0 rewrite, matches a project that is widely depended on. Doorstop is the kind of component that other modding tools build on, and the version 4 rewrite was disruptive enough that the CHANGES.md list of breaking changes matters to anyone maintaining an existing integration.

The alternative approaches differ in kind. A mod that patches the game's own managed assemblies on Mono can work without any loader, but it needs the game to be Mono based and it cannot run code before the game does. Il2Cpp games cannot be patched that way at all, which is where a loader that brings its own CoreCLR earns its keep. And for tooling that must observe a game from the outside, the debugger support here is the reason to prefer this over a general process injector.

Editorial conclusion

Unity Doorstop fits a Unity mod or tooling author who needs managed code running at the earliest possible point in a game process, and who needs the same assembly to work on both Mono and Il2Cpp builds. It does not fit someone who wants to modify Il2Cpp game code directly, since the documentation is explicit that you can only debug managed code there and that native debuggers such as GDB, IDA or Ghidra are the tool for that, and it does not fit a project that wants a stable configuration surface, because version 4 is a total rewrite with its own list of breaking changes. Before adopting it, read CHANGES.md to see what the rewrite changed, decide which runtime your target game uses, and confirm you can ship the CoreCLR runtime yourself when the game is Il2Cpp, since the assembly will not run without it.

Frequently asked questions

What does Unity Doorstop actually do?

It executes a managed .NET assembly inside a Unity game as early as possible, before Unity can run its own code, so that the assembly can patch the game or attach a debugger to it.

Do I need to ship a .NET runtime with my Doorstop mod?

On Unity Mono you do not, because the Common Language Runtime bundled with the game is used. On Il2Cpp you do, since the assembly runs in CoreCLR and you need to include .NET 6 or newer with it.

Can I debug the game code with Doorstop on an Il2Cpp build?

No. The documentation states you can only debug managed code, because the game code is unmanaged under Il2Cpp. For the actual game code it suggests native debuggers such as GDB, and visual tools like IDA or Ghidra.

How do I build Unity Doorstop from source?

Doorstop uses xmake. Run build.bat, build.ps1 or build.sh, with options such as -with_logging, -arch for the target architectures and -debug for a debug build, which is currently only available on Unix style systems.

Official sources

  1. Issues
  2. License: LGPL-2.1
  3. NeighTools/UnityDoorstop on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/neightools-unitydoorstop.svg)](https://hysenlabs.com/projects/neightools-unitydoorstop)

Was this useful?