using System; using System.IO; using System.Runtime.InteropServices; using UnityEngine; public partial class UniQuake { #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 IntPtr libraryHandle; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void UniQuake_InitFunc(IntPtr parms); 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; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void UniQuake_SetFmodSystemFunc(IntPtr fmodSystem, int playerNumber = 0); private UniQuake_SetFmodSystemFunc UniQuake_SetFmodSystem; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void UniQuake_SetCallbacksFunc(IntPtr context, IntPtr callbacks); private UniQuake_SetCallbacksFunc UniQuake_SetSysCallbacks; private UniQuake_SetCallbacksFunc UniQuake_SetRenderCallbacks; private UniQuake_SetCallbacksFunc UniQuake_SetGameCallbacks; private void LoadLibrary() { string dllFile = Path.Combine(Application.dataPath, DllPath); // Experimental code to allow running multiple instances of Quake next to each other if (PlayerNumber > 1) { string directory = Path.GetDirectoryName(dllFile); string filename = Path.GetFileNameWithoutExtension(dllFile); string extension = Path.GetExtension(dllFile); dllFile = Path.Combine(directory, filename + PlayerNumber + extension); } 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(nameof(UniQuake_Init)); UniQuake_Update = LoadLibraryFunction(nameof(UniQuake_Update)); UniQuake_Shutdown = LoadLibraryFunction(nameof(UniQuake_Shutdown)); UniQuake_SetFmodSystem = LoadLibraryFunction(nameof(UniQuake_SetFmodSystem)); UniQuake_SetSysCallbacks = LoadLibraryFunction(nameof(UniQuake_SetSysCallbacks)); UniQuake_SetRenderCallbacks = LoadLibraryFunction(nameof(UniQuake_SetRenderCallbacks)); UniQuake_SetGameCallbacks = LoadLibraryFunction(nameof(UniQuake_SetGameCallbacks)); } private TDelegate LoadLibraryFunction(string functionName) { IntPtr procAddress = SystemLibrary.GetProcAddress(libraryHandle, functionName); if (procAddress == IntPtr.Zero) { throw new DllNotFoundException($"Could not find library function: {functionName}"); } return Marshal.GetDelegateForFunctionPointer(procAddress); } private void FreeLibrary() { if (libraryHandle != IntPtr.Zero) { SystemLibrary.FreeLibrary(libraryHandle); libraryHandle = IntPtr.Zero; } } }