Browse Source

Added an opaque target pointer to each callback function, so that Unity can pass an object instance and use that instance when processing callbacks.

console
Nico de Poel 5 years ago
parent
commit
b2ad8a5074
  1. 65
      Assets/Scripts/UniQuake.cs
  2. 17
      engine/projects/uniquake/uniquake.c
  3. 8
      engine/projects/uniquake/uniquake.h

65
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
}
}
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
private static extern void UniQuake_Echo(SysPrintCallback logCallback, [MarshalAs(UnmanagedType.LPStr)] string message);
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_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

17
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;

8
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;
Loading…
Cancel
Save