GithubHelp home page GithubHelp logo

mcpiroman / unitynativetool Goto Github PK

View Code? Open in Web Editor NEW
177.0 5.0 18.0 255 KB

Allows to unload native plugins in Unity3d editor

License: MIT License

C# 99.67% C 0.33%
unity unity3d unity3d-plugin unity-editor csharp interop c-sharp-library native runtime

unitynativetool's Introduction

Tool created mainly to solve the old problem with reloading native plugins without the need to reopen Unity Editor.

Overview

  • Automatically unloads native plugins after stopping the game and loads them when needed.
  • You can unload/reload them manually, even when the game is running.
  • No code change is required - use usual [DllImport].
  • Low level interface callbacks UnityPluginLoad and UnityPluginUnload do fire - to enable them see this section.
  • Works on Windows, Linux and Mac, but only on x86/x86_64 processors.
  • Ability to log native calls to file in order to diagnose crashes caused by them.

Installation

  1. Either download and add unity package from releases, or clone this repo into the assets of your project.

    • Clone it into the <Project Root>/Packages folder to use it as a local embedded package with upm.
  2. In project settings, set Api Compatibility Level to .NET 4.x or above. Edit > Project Settings > Player > Other Settings > Api Compatibility Level

  3. Check Allow 'unsafe' code. Edit > Project Settings > Player > Other Settings > Allow 'unsafe' code

  4. One of the gameobjects in the scene needs to have DllManipulatorScript on it. (This script calls DontDestroayOnLoad(gameObject) and deletes itself when a duplicate is found in order to behave nicely when switching scenes).

Usage

  • Your plugin files must be at path specified in options. By default, just add __ (two underscores) at the beginning of your dll files in the Assets/Plugins folder (e.g. on Windows, plugin named FastCalcs should be at path Assets\Plugins\__FastCalcs.dll).
  • By default, all extern methods in the main scripts assembly will be mocked (i.e. handled by this tool instead of Unity, allowing them to be unloaded). You can change this in options and use provided attributes to specify that yourself (they are in UnityNativeTool namespace, file Attributes.cs).
  • Options are accessible via DllManipulatorScript editor or window.
  • You can also unload and load all DLLs via shortcut, Alt+D and Alt+Shfit+D respectively. Editable in the Shortcut Manager for 2019.1+
  • You can get callbacks in your C# code when the load state of a DLL has changed with attributes like [NativeDllLoadedTrigger]. See Attributes.cs.
  • Although this tool presumably works in the built game, it's intended to be used only during development.
  • If something doesn't work, first check out available options (and read their descriptions), then report an issue.

Low level interface callbacks support

For that, you'll need a StubLluiPlugin DLL. I only embed it into .unitypackage for x64 Windows platform, so for other cases you'll need to compile it manually.

This is, compile the file ./stubLluiPlugin.c into the dynamic library (name it StubLluiPlugin, no underscores) and put into Unity like you would do with other plugins.

Limitations

  • Native callbacks UnityRenderingExtEvent and UnityRenderingExtQuery do not fire.
  • Only some basic attributes on parameters of extern methods (such as [MarshalAs] or [In]) are supported.
  • Properties MarshalCookie, MarshalType, MarshalTypeRef and SafeArrayUserDefinedSubType on [MarshalAs] attribute are not supported (due to Mono bug).
  • Explicitly specifying UnmanagedType.LPArray in [MarshalAs] is not supported (due to another Mono bug). Note that this should be the default for array types, so in trivial situations you don't need to use it anyway.
  • Properties ExactSpelling and PreserveSig of [DllImport] attribute are not supported.
  • Calling native functions from static constructors generally won't work. Although the rules are more relaxed, you usually shouldn't even attempt to do that in the first place. Note that in C# static constructors don't fire on their own.
  • Additional threads that execute past OnApplicationQuit event are not-very-well handled (usually not something to worry about).

Troubleshooting & advanced usage

  • The path in the DLL path pattern option cannot be simply set to {assets}/Plugins/{name}.dll as it would interfere with Unity's plugin loading - hence the underscores.
  • In version 2019.3.x Unity changed behaviour of building. If you want to use this tool in the built game (although preferably just for development) you should store your plugins in architecture-specific subfolders and update the DLL path pattern option accordingly, e.g. {assets}/Plugins/x86_64/__{name}.dll.
  • The UnityNativeTool.DllManipulatorScript script by default has an execution order of -10000 to make it run first. If you have a script that has even lower execution order and that scripts calls a DLL, then you should make sure that UnityNativeTool.DllManipulatorScript runs before it, e.g. by further lowering its execution order.

Performance

Configuration Relative call time
Vanilla Unity 100%
Preloaded mode ~150%
Lazy mode ~190%
With thread safety ~430%

References

unitynativetool's People

Contributors

mcpiroman avatar rogerbarton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

unitynativetool's Issues

Support more processor architectures, platforms and .NET runtimes

The code used to do the cornerstone of work - changing method code at runtime - was extracted from Hamonyproject and is located in scripts/Detour.cs.
It works with native x86 code and closely integrates with Mono framework.

Since then this functionality has been extracted from Harmony and developed in MonoMod.Common project. Most importantly it supports more processor architectures (actually only x86 and ARM?) and other .NET runtimes (.NET Core, 5, 6). The latter might be important in case Unity would finally move away from Mono. It also has the potential to (or does it already?) run on other platforms, such as Android. Harmony now uses MonoMod.Common.

Since then MonoMod.Common project has not quite been adopted to newer platforms. Importantly, here it says it won't support .NET 7 and Apple Silicon processors, at least in the present form, but there is some work on the required redesign as well as some alternative initiatives. Related issues from Harmony's side: pardeike/Harmony#424, pardeike/Harmony#504.

For this project the same tour is needed: replace the old Detour.cs file with a dedicated library, either MonoMod.Common, its successor (MonoModReorg.RuntimeDetour/), or something similar.
This should be rather straightforward re-plumbing, except that here we deture external methods, which may impose its own issues (e.g. handling of MarshalAs attribut), as opposed to regular .NET methods which are targeted by such frameworks.
From user perspective the only downside is it will likely require to bundle a 3-party DLL file, instead just a of transparent sources as it is now.

I'm marking this issue as up-for-grabs as I likely won't tackle on this (and I likely won't use Unity anymore).

DllManipulatorScript is not the last GameObject calling OnDestroy when scene is being destroyed.

The order of OnDestroy is not guaranteed, because the order of script excution doesn't work when calling OnDestroy.

class OneObj : MonoBehavior {
  void OnDestroy() { NativeApi.test(); }
}

The code above will raise IndexOutofBoundException randomly when stopping game in editor.

I dont know how to solve this problem.

I am using a stupid solution:

  1. invoke DllManipulatorScript.Reinitialize in Awake(){} when game started.
  2. manually invoke DllManipulatorScript.Reset via menu item before building cpp dll.

Is there better way?

Dynamic Dll detection possibility

Hi! This is more a question than an issue, but I want to know if it is theoretically possible to find dynamically dlls in the project and load it using this tool.

I'm trying to do a tool that unload all native DLLs before executing a libraries update process because some of them contains firebase and another libraries DLLs that cause the project to crash (Because cannot replace dlls if they are loaded and locked by the Unity Instance)

If this is possible how is the best approach to do it?

can't overwrite my .dll in Assets/plugins after the first "play" in unity editor

I'm probably missing something. Here is the problem I have now:
in the editor: play game, then stop.
Then, with windows file explorer, I'm try to overwrite my __xxx.dll file in Assets/plugins => Windows tells my the file is used, and I can't overwrite to update it with a new version.
Note: VS debugger was attached during play, and UnloadAll() has been called correctly. and SysUnloadDll returned true.
Any idea?

Hanging on quit

Thanks so much for your efforts. My (native rendering) plugin works fine until I end the game (click play again), at which point it freezes the Unity editor and I have to kill and restart. The plugin uses many threads internally, which are cleaned up OnApplicationQuit. I saw the comment related to threads running past OnApplicationQuit in the readme, and was wondering if this could be related. Note, the plugin starts and stops without your tool enabled. The plugin itself relies on several DLLs that are in the Assets folder (not sure if this is somehow related).

Testing on Windows 10, deploy to Android

Nice library! I have been using this for dev on Windows and finally got around trying to build for Android.

I have my Android .so libs that run just fine on devices but I am wondering what I am doing wrong to be able to test on the PC and then build for Android.

Can this project even work like this? Use my custom library dlls for testing on Windows, then in the same project/scene be able to switch to the Android target and build without error?

I already have an abstract audio engine that runs fine on Android(runtime switch for implementation) using a lib .so but it seems like I am missing the part where I tell Unity, this is only for the Editor on Windows.

Tried also strategically setting all dlls to only be editor but that does not seem to matter. Here is the stack;

image

Thanks!

Consider changing OnApplicationQuit to OnDisable

Script execution order has no impact on OnApplicationQuit. As such, cleaning up work done by a dll after leaving play mode is a bit clunky. You can't do it in OnApplicationQuit on a different monobehaviour because the dll may already be unloaded by that point. Changing OnApplicationQuit to OnDisable inside DllManipulatorScript would give a clear window of opportunity for any fixes or logging before unloading.

Skipping copy of attribute [OptionalAttribute] in function GotoPos as it is not supported. However, if it is desirable to include it, adding such support should be easy. See the method that throws this exception.

Is this feature planed? Or can someone implement it?

Thanks

Skipping copy of attribute [OptionalAttribute] in function GotoPos as it is not supported. However, if it is desirable to include it, adding such support should be easy. See the method that throws this exception.
UnityEngine.Debug:LogWarning (object)
UnityNativeTool.Internal.DllManipulator:CreateAttributeBuilderFromAttributeInstance (System.Attribute,string) (at Assets/UnityNativeTool/DllManipulator.cs:492)
UnityNativeTool.Internal.DllManipulator:CreateDelegateTypeForNativeFunctionSignature (UnityNativeTool.Internal.NativeFunctionSignature,string) (at Assets/UnityNativeTool/DllManipulator.cs:453)
UnityNativeTool.Internal.DllManipulator:GetNativeFunctionMockMethod (System.Reflection.MethodInfo) (at Assets/UnityNativeTool/DllManipulator.cs:300)
UnityNativeTool.Internal.DllManipulator:MockNativeFunction (System.Reflection.MethodInfo) (at Assets/UnityNativeTool/DllManipulator.cs:260)
UnityNativeTool.Internal.DllManipulator:Initialize (UnityNativeTool.Internal.DllManipulatorOptions,int,string) (at Assets/UnityNativeTool/DllManipulator.cs:99)
UnityNativeTool.DllManipulatorScript:Initialize () (at Assets/UnityNativeTool/DllManipulatorScript.cs:92)
UnityNativeTool.DllManipulatorScript:OnEnable () (at Assets/UnityNativeTool/DllManipulatorScript.cs:64)

MarshalAs with LPArray

Hello,

Thank you very much for developing this tool. I'm assisting a professor at my university with some programming tasks, and this tool seems like it solves one of the problems I'm working on. I have a question that I'm hoping you might be able to help me with.

In your documentation, I see this in the "Limitations" section:

[MarshalAs] attribute's properties MarshalCookie, MarshalType, MarshalTypeRef and SafeArrayUserDefinedSubType are not supported (due to Mono bug).

As expected given this issue, there are a couple of DLL imports I can't mock without Unity crashing:

[DllImport("Behavior")]
public static extern void transferActorData([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] actorParameter[] agents, int agentcount, int behavior);

[DllImport("Behavior")]
public static extern void transferObstacleData([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] obstacleParameter[] obstacles, int obstaclecount);

I'm assuming this is because they use MarshalAs with the UnmanagedType parameter.

Admittedly, I'm not familiar enough with imports of this kind to know how to work around this. (This is my first time attempting to use custom plugins in Unity.) I wanted to ask if you know of a different way to pass these arrays, which could be compatible with your tool. Is there such a thing, to your knowledge?

Thanks again for sharing your work on this.

Matt

UnityPluginLoad/Unload callbacks not firing, warning to compile StubLluiPlugin after installing from .unitypackage

Hi, relatively new to Unity so please bear with me.

I followed the instructions for installation in the readme by using the .unitypackage downloaded from the latest release (8.0) and have set up my project as per the readme "Usage" section. When I enter play mode, I'm getting the message:

StubLluiPlugin not found. UnityPluginLoad and UnityPluginUnload callbacks won't fire. If you didn't install UnityNativeTool from .unitypackage or it didn't contain the compiled plugin, you'll need to compile it manually. You may also comment out this warning if you don't care about these callbacks.

I do need these callbacks for my project. I'm wondering why I'm seeing this warning given I installed from a .unitypackage, but more importantly, I'm not sure how I would compile it manually. Is there a specific command you can give?

How to use this to lazy load plugins for Unity Test Framework tests?

I'm using this successfully in play mode but when I run play mode tests in Unity Test Framework, I'm seeing a System.DllNotFoundException. When I replace the DllImport("<plugin>") with DllImport("__<plugin>") in the test file it works, but then I have to restart Unity to load a new version of the plugin. Is this something you can help with?

Here's my test file if it helps:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class PlayTestScript
{
    [DllImport("__RenderingPlugin")]
    private static extern int TestFunction();

    // A Test behaves as an ordinary method
    [Test]
    public void PlayTestScriptSimplePasses()
    {
        // Use the Assert class to test conditions
        Assert.AreEqual(42, TestFunction());
    }
}

Crash with IUnityInterface ?

Thank you for this amazing package.

Unfortunately I can't get it to work with this unity native plugin sample project:
https://github.com/Unity-Technologies/NativeRenderingPlugin

Everything compiles but the Unity editor freezes up when loading the dll. When I start playmode or when I press alt - shift - D.

(WIthout the package the dll loads correctly and works in playmode).
I followed all the steps under the "usage" section.

Im running Unity 2022.3.5f1 on Windows x64.

Could the problem be that the dll uses IUnityInterface.h?
for instance: a function is declared like this:
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)

I'm not sure if this is supported?

I also tried specifying the mocked functions, this results in:
image

However on alt + shift + D it freezes up.

Do you have any idea what could be causing the issue?

Thanks in advance
Jeroen

Installing linux build support breaks windows dll loading

In dll manipulator line 694,
it check if it is UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX
and for some reason that is true, but also UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN is true
the solution is to move windows to the first if.

#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN 
            return PInvokes_Windows.FreeLibrary(libHandle);
#elif UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
            return PInvokes_Osx.dlclose(libHandle) == 0;
#elif UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX
            return PInvokes_Linux.dlclose(libHandle) == 0;
#else
            throw GetUnsupportedPlatformExcpetion();
#endif

DLL invocation in constructor doesn't work

It seems as the original dll is still in use and the "CallingMethodTranspiler" is not working.
setup:
`
[MockNativeDeclarations]
[MockNativeCalls]
class RustMesh {
public RustMesh() { create_mesh(); }
[DllImport("hello")]
private static extern IntPtr create_mesh();
}

public class RustBehaviour : MonoBehaviour
{
void Start()
{
var rustMesh = new RustMesh();
}
}
`

hello.dll is next to the RustBehaviour .cs

I've added some log to the DllManipulator and loading seems to be ok.

I've tried to add a different path for hello.dll and it is really unloaded and reloaded the functions, but calling any function still calls the original dll

Any hint?

Android support

Any ideas how to make this work with Android? I am dynamically creating the library at runtime (patching a file) and would like to then load it.

DLLs are not unloaded when changed path pattern

I'm not sure why. I have a game object with the dll manipulator script set to preload mode. Having added some logs in DllManipulator it seems like all functions are loaded and unloaded correctly. And yet, I can't replace the dll with a new version without closing unity first. Did I misunderstand the purpose of this repository?

Can't figure out why the native dll isn't unloading

Hi, I've been pulling lots of hairs trying to figure out how to unload a native dll and I came across to this wonderful solution.

I tried to set it up and make sure I follow the direction but it doesn't seem to work.
It runs fine for the first time but Unity Editor freezes at the second run.
Assets.zip

I'm including a sample project for the testing.
I'll really appreciate if you can help why it's not working.
Cheers

New plugin not loaded without restarting editor on Ubuntu

Hi,

I'm on Ubuntu 18.04 and using Unity 2019.4. When I build my plugin into the Plugins folder when my editor is open, the DllManipulator still loads the old .so, even if do the "unload all dlls" and load commands. Only by restarting the editor it loads the newly built one.

I followed the instructions and checked that I have all these set up properly:

  • Api Compatibility Level to .NET 4.
  • Allow 'unsafe' code.
  • DllManipulatorScript in active scene
  • underscores before plugin name
  • Execution order

Any idea why it's not working?

Meta files - Inconsistent guids

Hey, first of all I would like to say thanks for creating this project!

I have a project where we fetch our third party dependencies (including UnityNativeTool) instead of having them checked in to our source control. In our other third party dependencies they include the .meta files. I see in UnityNativeTool the .meta files are not checked into GitHub. This results in different guids being generated on different machines with our setup. To get around this I made a fork and just committed the meta files (https://github.com/zaucy/UnityNativeTool/tree/with-meta-files).

It's a non-issue for me to maintain the fork for my project. I was just wondering if it may be ideal to include the .meta files incase someone else runs into the same issue :)

DLLs not unloaded when using in edit mode.

I have play mode working fine, but now looking at some editor scripts, and it appears I cannot release the lock on the files without restarting unity.

Is there any tricks to get DLL unloading working in Edit Mode?

I have checked Enable in Edit Mode, set to lazy, and clicked Unload yet the file is still locked and cannot be replaced/deleted.

issue with built game ?

Hi,
I'm testing Unity Native Tool with the Unity editor, it works perfectly well, congrats !
But: with the built game: I attach the visual studio debugger to my game .exe: my breakpoints are never reached. (and the current project is the one for my .dll )
(please note: I manage to attach the debugger to the editor. it only does not work with the built game)
Is there something I'm missing?
thanks

Native calls from static constructor fail

Hi , mcpiroman, I am trying to use swig with UnityNativeTool together. but I got some error that I can't resolve. Need your help again.

The code I am using is copied from master branch.

This my dll ( Placing dll in x86_64 doesn't help. ):
QQ图片20200611083619

Errors:
QQ图片20200611083425

This is status of running DllManipulator:
QQ图片20200611082817

Here are detailed exceptions:
QQ图片20200611083537

QQ图片20200611083600

Use relative path for assemblyPaths

This is not so important but similar to #16. As the Options.assemblyPaths are currently serialized as absolute paths in the scene file, when opening the project on another device the paths are incorrect and have to be set again.

Is it possible to use relative paths to avoid this, maybe use Assembly.outputPath? This only has to be for the strings stored/serialized in the scene file. Is there an easy solution to this?

native rendering plugins

I have a native rendering plugin that works fine in the Editor but when I try to load it via UnityNativeTool it reports a NativeDllException and the Game view seems to freeze up. Is it possible to unload & reload rendering plugins or are they just tied in too tightly?

dll cant be deleted in unity2019.3.1

The UnityNativeTool has been installed.
The path of dll is : Assets/Plugins/__libezg_Debug.dll.
DllManipulatorScript has beed attached to a gameobject.
Run game, native function works fine(just a add method that return int).
stop game.
DLL cant be deleted now.
It complains that the dll has been opened by unity editor.

DllManipulatorScript::OnApplicationQuit has been called.
Did I miss something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.