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