From b2ad8a50747d7341e1bc3fd19013548f7ac30211 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Mon, 29 Mar 2021 15:47:54 +0200 Subject: [PATCH] Added an opaque target pointer to each callback function, so that Unity can pass an object instance and use that instance when processing callbacks. --- Assets/Scripts/UniQuake.cs | 67 ++++++++++++++++++++--------- engine/projects/uniquake/uniquake.c | 17 +++----- engine/projects/uniquake/uniquake.h | 8 ++-- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index 238f807..8d27f01 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -12,8 +12,9 @@ public class UniQuake: MonoBehaviour private QuakeParms quakeParms; private UnityCallbacks callbacks = new UnityCallbacks(); + private GCHandle selfHandle; - private static double startTime; // TODO: this should be an instance field, but it requires a reference back to this object in the callbacks + private double startTime; void Start() { @@ -43,7 +44,9 @@ public class UniQuake: MonoBehaviour memSize = MemSize, }; - UniQuake_Init(callbacks.CallbacksPtr, quakeParms); + selfHandle = GCHandle.Alloc(this); + + UniQuake_Init(callbacks.CallbacksPtr, GCHandle.ToIntPtr(selfHandle), quakeParms); } void Update() @@ -54,6 +57,7 @@ public class UniQuake: MonoBehaviour private void OnDestroy() { callbacks.Destroy(); + selfHandle.Free(); if (quakeParms != null) { @@ -77,48 +81,69 @@ public class UniQuake: MonoBehaviour } } + private void SysPrint(string message) + { + Debug.Log(message); + } + + private void SysError(string message) + { + Debug.LogError(message); + // TODO: kill execution of the DLL entirely (Sys_Quit expects immediate exit, which this doesn't do) + Application.Quit(1); + } + + private void SysQuit() + { + Debug.Log($"Quitting application normally"); + Application.Quit(0); + } + + private double SysFloatTime() + { + return Time.timeAsDouble - startTime; + } + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - private static extern void UniQuake_Echo(SysPrintCallback logCallback, [MarshalAs(UnmanagedType.LPStr)] string message); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - private static extern void UniQuake_Init(IntPtr callbacks, QuakeParms parms); + private static extern void UniQuake_Init(IntPtr callbacks, IntPtr callbackTarget, QuakeParms parms); [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] private static extern void UniQuake_Update(float deltaTime); - private delegate void SysPrintCallback([MarshalAs(UnmanagedType.LPStr)] string message); + private delegate void SysPrintCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message); [AOT.MonoPInvokeCallback(typeof(SysPrintCallback))] - private static void Callback_SysPrint(string message) + private static void Callback_SysPrint(IntPtr target, string message) { - Debug.Log(message); + var self = (UniQuake)GCHandle.FromIntPtr(target).Target; + self.SysPrint(message); } - private delegate void SysErrorCallback([MarshalAs(UnmanagedType.LPStr)] string message); + private delegate void SysErrorCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message); [AOT.MonoPInvokeCallback(typeof(SysErrorCallback))] - private static void Callback_SysError(string message) + private static void Callback_SysError(IntPtr target, string message) { - Debug.LogError(message); - Application.Quit(1); + var self = (UniQuake)GCHandle.FromIntPtr(target).Target; + self.SysError(message); } - private delegate void SysQuitCallback(); + private delegate void SysQuitCallback(IntPtr target); [AOT.MonoPInvokeCallback(typeof(SysQuitCallback))] - private static void Callback_SysQuit() + private static void Callback_SysQuit(IntPtr target) { - Debug.Log($"Quitting application normally"); - // TODO: kill execution of the DLL entirely (Sys_Quit expects immediate exit, which Application.Quit doesn't do) - Application.Quit(0); + var self = (UniQuake)GCHandle.FromIntPtr(target).Target; + self.SysQuit(); } - private delegate double SysFloatTimeCallback(); + private delegate double SysFloatTimeCallback(IntPtr target); [AOT.MonoPInvokeCallback(typeof(SysFloatTimeCallback))] - private static double Callback_SysFloatTime() + private static double Callback_SysFloatTime(IntPtr target) { - return Time.timeAsDouble - startTime; + var self = (UniQuake)GCHandle.FromIntPtr(target).Target; + return self.SysFloatTime(); } private class UnityCallbacks diff --git a/engine/projects/uniquake/uniquake.c b/engine/projects/uniquake/uniquake.c index 6520825..040174f 100644 --- a/engine/projects/uniquake/uniquake.c +++ b/engine/projects/uniquake/uniquake.c @@ -8,6 +8,7 @@ #include "../../code/quakedef.h" const unity_callbacks_t *unity_callbacks; +void *unity_callbackTarget; void Sys_Error(char *error, ...) { @@ -18,7 +19,7 @@ void Sys_Error(char *error, ...) vsprintf(text, error, argptr); va_end(argptr); - unity_callbacks->SysError(text); + unity_callbacks->SysError(unity_callbackTarget, text); } void Sys_Printf(char *fmt, ...) @@ -30,28 +31,24 @@ void Sys_Printf(char *fmt, ...) vsprintf(text, fmt, argptr); va_end(argptr); - unity_callbacks->SysPrint(text); + unity_callbacks->SysPrint(unity_callbackTarget, text); } void Sys_Quit(void) { Host_Shutdown(); - unity_callbacks->SysQuit(); + unity_callbacks->SysQuit(unity_callbackTarget); } double Sys_FloatTime(void) { - return unity_callbacks->SysFloatTime(); + return unity_callbacks->SysFloatTime(unity_callbackTarget); } -UNIQUAKE_API void UniQuake_Echo(void(__stdcall *DebugLog)(const char *msg), const char *message) -{ - DebugLog(message); -} - -UNIQUAKE_API void UniQuake_Init(const unity_callbacks_t *callbacks, quakeparms_t *parms) +UNIQUAKE_API void UniQuake_Init(const unity_callbacks_t *callbacks, void *callbackTarget, quakeparms_t *parms) { unity_callbacks = callbacks; + unity_callbackTarget = callbackTarget; COM_InitArgv(parms->argc, parms->argv); parms->argc = com_argc; diff --git a/engine/projects/uniquake/uniquake.h b/engine/projects/uniquake/uniquake.h index ef1f9e5..cd9aabe 100644 --- a/engine/projects/uniquake/uniquake.h +++ b/engine/projects/uniquake/uniquake.h @@ -6,10 +6,10 @@ typedef struct unity_callbacks_s { - void(__stdcall *SysPrint)(const char *msg); - void(__stdcall *SysError)(const char *msg); - void(__stdcall *SysQuit)(); - double(__stdcall *SysFloatTime)(); + void(__stdcall *SysPrint)(void *target, const char *msg); + void(__stdcall *SysError)(void *target, const char *msg); + void(__stdcall *SysQuit)(void *target); + double(__stdcall *SysFloatTime)(void *target); } unity_callbacks_t; extern const unity_callbacks_t *unity_callbacks;