Skip to content
Single-file helper to allow Unity NativePlugins to be updated without restarting the editor.
C# C++ C
Branch: master
Clone or download
Latest commit 29f974f Sep 1, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
NativeReloadUnityProject Minor tweaks Sep 1, 2019
cpp_example_dll
LICENSE Update license to dual MIT / Unlicense Sep 1, 2019
readme.md Minor tweaks Sep 1, 2019

readme.md

fts_unity_native_reload

fts_unity_native_reload is a single C# file that helps Unity auto-reload native plugins.

The only file you need is NativePluginLoader.cs. Everything else exists only to provide a complete example.

The Problem

Unity doesn't unload DLLs after using PInvoke. This makes developing Native Plugins a huge pain in the ass. Everytime you want to update the DLL you need to close the Unity Editor or else you get a "file in use" error. This can be very slow and significantly reduces iteration speed.

This project solves that problem with a simple ~200 line file.

Consider the following:

// my_cool_header.h
extern "C" {
    __declspec(dllexport) float sum(float a, float b);
}

The standard way to call this NativePlugin is:

// C#
// Old and busted PInvoke
public static class FooPlugin_PInvoke {
    [DllImport("cpp_example_dll", EntryPoint = "sum")]
    extern static public float sum(float a, float b);
}

My new and improved way:

// C#
// New hotness
[PluginAttr("cpp_example_dll")]
public static class FooPlugin
{
    [PluginFunctionAttr("sum")] 
    public static Sum sum = null;
    public delegate float Sum(float a, float b);
}

void CoolFunc() {
    float s = FooPlugin.sum(1.0, 2.0);
    float t = FooPlugin_PInvoke.sum(1.0, 2.0); // also works
}

Tada! For this to work all you have to do is add the NativePluginLoader script to your scene.

How It Works

NativePluginLoader.Awake scans all assemblies for classes with the PluginAttr attribute. It calls LoadLibrary with the specified plugin name.

Next, it loops over all public static fields with the PluginFunctionAttr attribute. For each field it calls GetProcAddress and stores the result in the delegate. I wish I could declare the delegate signature and delegate variable in one line. :(

NativePluginLoader.OnDestory calls FreeLibrary for all loaded plugins. The DLLs can then be updated. Next time you run the new DLL will be loaded and the new proc addresses will be found.

The syntax for calling the delegates is identical to using PInvoke. If performance is a concern you can provide a dynamic version inside #if UNITY_EDITOR and rely on PInvoke for standalone builds.

Platforms

This currently only supports Windows. Supporting other platforms should be trivial. Pull requests welcome.

License

The entire repo is dual-licensed under both MIT License and Unlicense.

You can’t perform that action at this time.