diff --git a/Assets/Scripts/SystemLibrary.cs b/Assets/Scripts/SystemLibrary.cs new file mode 100644 index 0000000..015fb13 --- /dev/null +++ b/Assets/Scripts/SystemLibrary.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +public static class SystemLibrary +{ +#if UNITY_STANDALONE_WIN + [DllImport("kernel32", EntryPoint = "LoadLibrary", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern IntPtr LoadLibraryNative(string lpFileName); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetDllDirectory(string lpPathName); + + public static IntPtr LoadLibrary(string lpFileName) + { + string lpPathName = Path.GetDirectoryName(lpFileName); + lpFileName = Path.GetFileName(lpFileName); + SetDllDirectory(lpPathName.Replace('/', '\\')); + return LoadLibraryNative(lpFileName); + } + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FreeLibrary(IntPtr hModule); + + [DllImport("kernel32")] + public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); +#endif +} diff --git a/Assets/Scripts/SystemLibrary.cs.meta b/Assets/Scripts/SystemLibrary.cs.meta new file mode 100644 index 0000000..a103550 --- /dev/null +++ b/Assets/Scripts/SystemLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d583e6fe28a9299438ec95a379db0527 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index a6f61d7..6a36e74 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -1,12 +1,24 @@ using System; +using System.IO; using System.Runtime.InteropServices; using UnityEngine; public class UniQuake: MonoBehaviour -{ - private const string DllName = "uniquake.dll"; +{ +#if UNITY_EDITOR + private const string DllPath = "Plugins/windows/x86_64/uniquake.dll"; +#elif UNITY_STANDALONE_WIN + #if UNITY_64 + private const string DllPath = "Plugins/x86_64/uniquake.dll"; + #else + private const string DllPath = "Plugins/x86/uniquake.dll"; + #endif +#endif + private const int MemSize = 0x4000000; // 64 MB of heap space + private IntPtr libraryHandle; + private QuakeParms quakeParms; private SysCalls sysCalls; private ModCalls modCalls; @@ -20,7 +32,12 @@ public class UniQuake: MonoBehaviour public double CurrentTime => Time.timeAsDouble - startTime; void Start() - { + { + sysCalls = new SysCalls(this); + modCalls = new ModCalls(this); + + LoadLibrary(); + string[] arguments = { "", @@ -38,9 +55,6 @@ public class UniQuake: MonoBehaviour quakeParms.SetArguments(arguments); quakeParms.AllocateMemory(MemSize); - sysCalls = new SysCalls(this); - modCalls = new ModCalls(this); - startTime = Time.timeAsDouble; try @@ -106,16 +120,55 @@ public class UniQuake: MonoBehaviour quakeParms.Destroy(); quakeParms = null; } + + FreeLibrary(); } - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - private static extern void UniQuake_Init(QuakeParms parms, IntPtr sysCalls, IntPtr modCalls); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void UniQuake_InitFunc(QuakeParms parms, IntPtr sysCalls, IntPtr modCalls); + private UniQuake_InitFunc UniQuake_Init; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void UniQuake_UpdateFunc(float deltaTime); + private UniQuake_UpdateFunc UniQuake_Update; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void UniQuake_ShutdownFunc(); + private UniQuake_ShutdownFunc UniQuake_Shutdown; - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - private static extern void UniQuake_Update(float deltaTime); + private void LoadLibrary() + { + string dllFile = Path.Combine(Application.dataPath, DllPath); + libraryHandle = SystemLibrary.LoadLibrary(dllFile); + if (libraryHandle == IntPtr.Zero) + { + throw new DllNotFoundException($"Failed to load UniQuake library from path: {dllFile}, last error = {Marshal.GetLastWin32Error()}"); + } + + UniQuake_Init = LoadLibraryFunction("UniQuake_Init"); + UniQuake_Update = LoadLibraryFunction("UniQuake_Update"); + UniQuake_Shutdown = LoadLibraryFunction("UniQuake_Shutdown"); + } - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - private static extern void UniQuake_Shutdown(); + private TDelegate LoadLibraryFunction(string name) + { + IntPtr procAddress = SystemLibrary.GetProcAddress(libraryHandle, name); + if (procAddress == IntPtr.Zero) + { + throw new DllNotFoundException($"Could not find library function: {name}"); + } + + return Marshal.GetDelegateForFunctionPointer(procAddress); + } + + private void FreeLibrary() + { + if (libraryHandle != IntPtr.Zero) + { + SystemLibrary.FreeLibrary(libraryHandle); + libraryHandle = IntPtr.Zero; + } + } } public class QuakeException: Exception