Browse Source
Moved all of the callbacks interop code into a separate class with a base class for some common abstractions. Allows for better organization of callbacks as the list grows.
console
Moved all of the callbacks interop code into a separate class with a base class for some common abstractions. Allows for better organization of callbacks as the list grows.
console
5 changed files with 161 additions and 120 deletions
-
39Assets/Scripts/CallbackHandler.cs
-
3Assets/Scripts/CallbackHandler.cs.meta
-
102Assets/Scripts/SysCalls.cs
-
11Assets/Scripts/SysCalls.cs.meta
-
126Assets/Scripts/UniQuake.cs
@ -0,0 +1,39 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
public abstract class CallbackHandler<THandler> |
||||
|
where THandler: CallbackHandler<THandler> |
||||
|
{ |
||||
|
private GCHandle selfHandle; |
||||
|
private List<GCHandle> delegateHandles = new List<GCHandle>(); |
||||
|
|
||||
|
public IntPtr SelfPtr => GCHandle.ToIntPtr(selfHandle); |
||||
|
|
||||
|
protected CallbackHandler() |
||||
|
{ |
||||
|
selfHandle = GCHandle.Alloc(this); |
||||
|
} |
||||
|
|
||||
|
public virtual void Destroy() |
||||
|
{ |
||||
|
foreach (var handle in delegateHandles) |
||||
|
{ |
||||
|
if (handle.IsAllocated) |
||||
|
handle.Free(); |
||||
|
} |
||||
|
|
||||
|
selfHandle.Free(); |
||||
|
} |
||||
|
|
||||
|
protected IntPtr CreateCallback<TDelegate>(TDelegate callback) |
||||
|
{ |
||||
|
delegateHandles.Add(GCHandle.Alloc(callback)); |
||||
|
return Marshal.GetFunctionPointerForDelegate(callback); |
||||
|
} |
||||
|
|
||||
|
protected static THandler GetSelf(IntPtr target) |
||||
|
{ |
||||
|
return (THandler)GCHandle.FromIntPtr(target).Target; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: c630080c312b4f238a73741919618661 |
||||
|
timeCreated: 1617026999 |
||||
@ -0,0 +1,102 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using UnityEngine; |
||||
|
|
||||
|
public class SysCalls: CallbackHandler<SysCalls> |
||||
|
{ |
||||
|
private readonly UniQuake uq; |
||||
|
private readonly double startTime; |
||||
|
|
||||
|
private Callbacks callbacks; |
||||
|
private GCHandle callbacksHandle; |
||||
|
|
||||
|
public IntPtr CallbacksPtr => callbacksHandle.AddrOfPinnedObject(); |
||||
|
|
||||
|
public SysCalls(UniQuake uniQuake) |
||||
|
{ |
||||
|
uq = uniQuake; |
||||
|
startTime = Time.timeAsDouble; |
||||
|
|
||||
|
callbacks = new Callbacks |
||||
|
{ |
||||
|
SysPrint = CreateCallback<SysPrintCallback>(Callback_SysPrint), |
||||
|
SysError = CreateCallback<SysErrorCallback>(Callback_SysError), |
||||
|
SysQuit = CreateCallback<SysQuitCallback>(Callback_SysQuit), |
||||
|
SysFloatTime = CreateCallback<SysFloatTimeCallback>(Callback_SysFloatTime), |
||||
|
}; |
||||
|
|
||||
|
callbacksHandle = GCHandle.Alloc(callbacks, GCHandleType.Pinned); |
||||
|
} |
||||
|
|
||||
|
public override void Destroy() |
||||
|
{ |
||||
|
if (callbacksHandle.IsAllocated) |
||||
|
callbacksHandle.Free(); |
||||
|
|
||||
|
base.Destroy(); |
||||
|
} |
||||
|
|
||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
||||
|
private class Callbacks |
||||
|
{ |
||||
|
public IntPtr SysPrint; |
||||
|
public IntPtr SysError; |
||||
|
public IntPtr SysQuit; |
||||
|
public IntPtr SysFloatTime; |
||||
|
} |
||||
|
|
||||
|
private delegate void SysPrintCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message); |
||||
|
|
||||
|
[AOT.MonoPInvokeCallback(typeof(SysPrintCallback))] |
||||
|
private static void Callback_SysPrint(IntPtr target, string message) |
||||
|
{ |
||||
|
GetSelf(target).Print(message); |
||||
|
} |
||||
|
|
||||
|
private void Print(string message) |
||||
|
{ |
||||
|
Debug.Log(message); |
||||
|
} |
||||
|
|
||||
|
private delegate void SysErrorCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message); |
||||
|
|
||||
|
[AOT.MonoPInvokeCallback(typeof(SysErrorCallback))] |
||||
|
private static void Callback_SysError(IntPtr target, string message) |
||||
|
{ |
||||
|
GetSelf(target).Error(message); |
||||
|
} |
||||
|
|
||||
|
private void Error(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 delegate void SysQuitCallback(IntPtr target); |
||||
|
|
||||
|
[AOT.MonoPInvokeCallback(typeof(SysQuitCallback))] |
||||
|
private static void Callback_SysQuit(IntPtr target) |
||||
|
{ |
||||
|
GetSelf(target).Quit(); |
||||
|
} |
||||
|
|
||||
|
private void Quit() |
||||
|
{ |
||||
|
Debug.Log($"Quitting application normally"); |
||||
|
Application.Quit(0); |
||||
|
} |
||||
|
|
||||
|
private delegate double SysFloatTimeCallback(IntPtr target); |
||||
|
|
||||
|
[AOT.MonoPInvokeCallback(typeof(SysFloatTimeCallback))] |
||||
|
private static double Callback_SysFloatTime(IntPtr target) |
||||
|
{ |
||||
|
return GetSelf(target).FloatTime(); |
||||
|
} |
||||
|
|
||||
|
private double FloatTime() |
||||
|
{ |
||||
|
return Time.timeAsDouble - startTime; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 3666423522d453147bd7d14ebc8b7ebe |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue