How to properly add DLL to Editor

I am following the guide here. I’ve successfully added DLLs that are now not giving any compilation errors. However when I try to call code during play-time I am getting warnings saying the DLLs are not present.

[ 00:07:45.784 ]: [Warning] Exception has been thrown. Unable to load one or more of the requested types.
Could not load file or assembly 'MessagePack, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b4a0369545f0a1be'. The system cannot find the file specified.
Stack strace:
   at System.Reflection.RuntimeModule.GetTypes(QCallModule module, ObjectHandleOnStack retTypes)
   at System.Reflection.RuntimeModule.GetDefinedTypes()
   at System.Reflection.RuntimeModule.GetTypes()
   at BlastNet.Common.INetMessage.RegisterAssembly(Assembly assembly)
   at BlastNet.Common.INetMessage.RegisterAllMessages()
   at BlastNet.Common.INetMessage.Initialize()
   at BlastNet.Common.BlastNetManager.Initialize(Logger logger)
   at Game.BlastNetworker.StartNetworker(String address, UInt16 port) in G:\Flax\UMMO\Source\Game\BlastNetworker.cs:line 46
   at Game.RealmConnectScreen.OnEnable() in G:\Flax\UMMO\Source\Game\RealmConnectScreen.cs:line 42
   at FlaxEngine.Interop.NativeInterop.Invoker.InvokerNoRet0`1.InvokeThunk(Object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs) in C:\Users\Wojtek\Flax\FlaxEngine\Source\Engine\Engine\NativeInterop.Invoker.cs:line 301
   at FlaxEngine.Interop.NativeInterop.ThunkContext.InvokeThunk(ManagedHandle instanceHandle, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7) in C:\Users\Wojtek\Flax\FlaxEngine\Source\Engine\Engine\NativeInterop.cs:line 1840

When I try to add the DLL (MessagePack) to editor as the guide states:

options.ExternalModules.Add(new BuildOptions.ExternalModule(BuildOptions.ExternalModule.Types.CSharp, path));

I get the error:

[ 00:20:56.925 ]: [Info] Exception: Index was outside the bounds of the array.
Stack trace:
[ 00:20:56.928 ]: [Info]    at Flax.Build.Builder.BuildTargetNativeCppBindingsOnly(RulesAssembly rules, TaskGraph graph, Target target, Dictionary`2 buildContext, Platform platform, TargetArchitecture architecture, TargetConfiguration configuration, Boolean skipBuild) in C:\Users\Wojtek\Flax\FlaxEngine\Source\Tools\Flax.Build\Build\NativeCpp\Builder.NativeCpp.cs:line 1073
   at Flax.Build.Builder.BuildTargets() in C:\Users\Wojtek\Flax\FlaxEngine\Source\Tools\Flax.Build\Build\Builder.cs:line 350
   at Flax.Build.Program.Main() in C:\Users\Wojtek\Flax\FlaxEngine\Source\Tools\Flax.Build\Program.cs:line 152

This may be the result of MessagePack using dynamic code generation though I thought that wouldn’t be the case as Flax uses NET 8.0 compared to something much lower like Unity.

Either way, I’d love to know what I am doing wrong or what limitation I am up against. Thanks so much~

The first error comes from the fact that the given dll is not present nearby game assemblies in compiled binaries folder.

options.ExternalModules shoudl be used to game script modules, to reference 3rd party lib with C# code use:

options.ScriptingAPI.FileReferences.Add(path);

Oh yes, I have tried that. I only tried options.ExternalModules as a means to fix it. Here is my full Game.Build.cs

using System.IO;
using Flax.Build;
using Flax.Build.NativeCpp;

public class Game : GameModule
{
    /// <inheritdoc />
    public override void Init()
    {
        base.Init();
        // C#-only scripting
        BuildNativeCode = false;
    }

    /// <inheritdoc />
    public override void Setup(BuildOptions options)
    {
        base.Setup(options);
        options.ScriptingAPI.IgnoreMissingDocumentationWarnings = true;
        // Here you can modify the build options for your game module
        // To reference another module use: options.PublicDependencies.Add("Audio");
        // To add C++ define use: options.PublicDefinitions.Add("COMPILE_WITH_FLAX");
        // To learn more see scripting documentation.
        // Reference C# DLL placed Content folder
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("MessagePack.dll"));
        //options.ExternalModules.Add(new BuildOptions.ExternalModule(BuildOptions.ExternalModule.Types.CSharp, AssemblyPath("MessagePack.dll")));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("MessagePack.Annotations.dll"));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("MessagePack.Analyzers.dll"));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("MessagePack.SourceGenerator.dll"));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("MessagePack.ReactiveProperty.dll"));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("BlastNet.Common.dll"));
        options.ScriptingAPI.FileReferences.Add(AssemblyPath("BlastNet.Client.dll"));
    }  
    private string AssemblyPath(string assemblyFileName)
    {
        return Path.Combine(FolderPath, "..", "..", "Content", "Assemblies", assemblyFileName);
    }
}

Thanks for the quick response btw. Your engine is absolutely amazing.

EDIT: I think I understand the issue better. I believe what is happening here is that BlastNet.Client.dll depends on MessagePack.dll and when the code is being called in BlastNet.Client, it cannot find the reference to MessagePack.

I was able to solve the issue. The problem was more complex than I initially thought.

At first I did think it was a problem with MessagePack compiling code on the fly, but this is not the case, indeed Flax does support this unlike Unity. (It can be done in Unity but you have to jump through a bunch of hoops in using a separate integration library to compile code ahead of play / builds)

The key here is in compiling to dlls with library dependencies at or less than what Flax is using. Usually in this case it is .NET 8.0 or framework 2.5.1 but it can be hard to tell what version of what uses what version of what. So it may require some trial and error. If you want to spend some time on it, you can compile everything from source and make sure everything is using these base NET packages that are at or lower than the current Flax support. Or if you want to spend less time you can go to NuGet manager in VS Studio or go to their website and manually download the nuget package. From here simply keep downgrading version and trying to see if it works or not. If the error is not nuanced like mine was Flax should simply tell you it is looking for version 9.0.0 and cannot find it. (it should be 8.0.0)

If you manually download the package for example if you go here you can click 'Download Package (.mb) and simply unzip the result. You will find the dlls organized into folders that label which .NET they support.

Once you do all that simply place them into your Flax assemblies like I had made and compile and watch for errors. If you see an error saying it can’t find a certain dll, this means something you have is referencing an incompatible dll.

Once I had did all that it finally compiled without errors. To save some headache here is a working 1.11 Flax Compatible MessagePack. (3.1.4)

Also as another side note it seems Flax gets rid of System.Numerics Vector3 as well as other 3D math structs, so in your dlls you need to make sure you are importing the FlaxEngine.CSharp.dll (C:\Program Files (x86)\Flax\Flax_1.11\Source\Platforms\Windows\Binaries\Game\x64\Release) as a dependency and replacing these. An easy pain free way to do this without any dependency is to define the Flax compiler tag at the top of each file to use that 3D struct instead. An example of this will be the following:

#if FLAX
using Vector3 = FlaxEngine.Vector3;
using Vector2 = FlaxEngine.Vector2;
using Matrix = FlaxEngine.Matrix;
#else
using Vector3 = System.Numerics.Vector3;
using Vector2 = System.Numerics.Vector2;
using Matrix = System.Numerics.Matrix4x4;
#endif

If you don’t do this you will get dll errors stating that System.Numerics does not contain the 3D struct.

1 Like

very cool bug - solving, or work arounds

:sunglasses: :heart:

1 Like