Browse Source

Replaced native file I/O functions with managed versions implemented in Unity. Worked first try! :D

console
Nico de Poel 5 years ago
parent
commit
cb8bb17c63
  1. 3
      Assets/Scripts/CallbackHandler.cs
  2. 238
      Assets/Scripts/SysCalls.cs
  3. 16
      engine/code/sys_win.c
  4. 66
      engine/projects/uniquake/sys_uniquake.c
  5. 9
      engine/projects/uniquake/uniquake.h

3
Assets/Scripts/CallbackHandler.cs

@ -17,7 +17,7 @@ public abstract class CallbackHandler<THandler>
selfHandle = GCHandle.Alloc(this);
}
public void Destroy()
public virtual void Destroy()
{
if (callbacksHandle.IsAllocated)
callbacksHandle.Free();
@ -32,6 +32,7 @@ public abstract class CallbackHandler<THandler>
protected void RegisterCallbacks<TCallbacks>(TCallbacks callbacks)
{
// Pin the callbacks struct so that native code can safely keep a pointer to it and re-use it on subsequent calls
callbacksHandle = GCHandle.Alloc(callbacks, GCHandleType.Pinned);
}

238
Assets/Scripts/SysCalls.cs

@ -1,12 +1,18 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using AOT;
using UnityEngine;
public class SysCalls: CallbackHandler<SysCalls>
{
private const int MaxFileHandles = 50;
private readonly UniQuake uq;
private readonly double startTime;
private readonly FileStream[] fileHandles = new FileStream[MaxFileHandles];
public SysCalls(UniQuake uniQuake)
{
uq = uniQuake;
@ -15,15 +21,39 @@ public class SysCalls: CallbackHandler<SysCalls>
var callbacks = new Callbacks
{
target = SelfPtr,
SysPrint = CreateCallback<SysPrintCallback>(Callback_SysPrint),
SysError = CreateCallback<SysErrorCallback>(Callback_SysError),
SysQuit = CreateCallback<SysQuitCallback>(Callback_SysQuit),
SysFloatTime = CreateCallback<SysFloatTimeCallback>(Callback_SysFloatTime),
SysFileOpenRead = CreateCallback<SysFileOpenReadCallback>(Callback_SysFileOpenRead),
SysFileOpenWrite = CreateCallback<SysFileOpenWriteCallback>(Callback_SysFileOpenWrite),
SysFileClose = CreateCallback<SysFileCloseCallback>(Callback_SysFileClose),
SysFileSeek = CreateCallback<SysFileSeekCallback>(Callback_SysFileSeek),
SysFileRead = CreateCallback<SysFileReadCallback>(Callback_SysFileRead),
SysFileWrite = CreateCallback<SysFileWriteCallback>(Callback_SysFileWrite),
SysFileTime = CreateCallback<SysFileTimeCallback>(Callback_SysFileTime),
SysMkDir = CreateCallback<SysMkDirCallback>(Callback_SysMkDir),
};
RegisterCallbacks(callbacks);
}
public override void Destroy()
{
for (int i = 0; i < MaxFileHandles; ++i)
{
if (fileHandles[i] != null)
fileHandles[i].Dispose();
}
base.Destroy();
}
/// <summary>
/// This matches struct unity_syscalls_s from uniquake.h in native code.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 0)]
private class Callbacks
{
@ -33,12 +63,21 @@ public class SysCalls: CallbackHandler<SysCalls>
public IntPtr SysError;
public IntPtr SysQuit;
public IntPtr SysFloatTime;
public IntPtr SysFileOpenRead;
public IntPtr SysFileOpenWrite;
public IntPtr SysFileClose;
public IntPtr SysFileSeek;
public IntPtr SysFileRead;
public IntPtr SysFileWrite;
public IntPtr SysFileTime;
public IntPtr SysMkDir;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysPrintCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message);
[AOT.MonoPInvokeCallback(typeof(SysPrintCallback))]
[MonoPInvokeCallback(typeof(SysPrintCallback))]
private static void Callback_SysPrint(IntPtr target, string message)
{
GetSelf(target).Print(message);
@ -46,13 +85,13 @@ public class SysCalls: CallbackHandler<SysCalls>
private void Print(string message)
{
Debug.Log(message);
// Debug.Log(message); // TODO: collect logs per frame and print after each Update loop
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysErrorCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string message);
[AOT.MonoPInvokeCallback(typeof(SysErrorCallback))]
[MonoPInvokeCallback(typeof(SysErrorCallback))]
private static void Callback_SysError(IntPtr target, string message)
{
GetSelf(target).Error(message);
@ -68,7 +107,7 @@ public class SysCalls: CallbackHandler<SysCalls>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysQuitCallback(IntPtr target);
[AOT.MonoPInvokeCallback(typeof(SysQuitCallback))]
[MonoPInvokeCallback(typeof(SysQuitCallback))]
private static void Callback_SysQuit(IntPtr target)
{
GetSelf(target).Quit();
@ -83,7 +122,7 @@ public class SysCalls: CallbackHandler<SysCalls>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate double SysFloatTimeCallback(IntPtr target);
[AOT.MonoPInvokeCallback(typeof(SysFloatTimeCallback))]
[MonoPInvokeCallback(typeof(SysFloatTimeCallback))]
private static double Callback_SysFloatTime(IntPtr target)
{
return GetSelf(target).FloatTime();
@ -93,4 +132,193 @@ public class SysCalls: CallbackHandler<SysCalls>
{
return Time.timeAsDouble - startTime;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SysFileOpenReadCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string path, out int handle);
[MonoPInvokeCallback(typeof(SysFileOpenReadCallback))]
private static int Callback_SysFileOpenRead(IntPtr target, string path, out int handle)
{
return GetSelf(target).FileOpenRead(path, out handle);
}
private int FileOpenRead(string path, out int handle)
{
int i = FindFileHandle();
try
{
Debug.Log($"Opening file for reading: {path}");
FileStream fileStream = File.OpenRead(path);
fileHandles[i] = fileStream;
handle = i;
return (int)fileStream.Length;
}
catch
{
handle = -1;
return -1;
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SysFileOpenWriteCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string path);
[MonoPInvokeCallback(typeof(SysFileOpenWriteCallback))]
private static int Callback_SysFileOpenWrite(IntPtr target, string path)
{
return GetSelf(target).FileOpenWrite(path);
}
private int FileOpenWrite(string path)
{
int i = FindFileHandle();
try
{
Debug.Log($"Opening file for writing: {path}");
FileStream fileStream = File.OpenWrite(path);
fileHandles[i] = fileStream;
return i;
}
catch (Exception ex)
{
Error($"Error opening {path}: {ex.Message}");
return -1;
}
}
private int FindFileHandle()
{
for (int i = 1; i < MaxFileHandles; ++i)
{
if (fileHandles[i] == null)
return i;
}
Error("Out of handles!");
return -1;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysFileCloseCallback(IntPtr target, int handle);
[MonoPInvokeCallback(typeof(SysFileCloseCallback))]
private static void Callback_SysFileClose(IntPtr target, int handle)
{
GetSelf(target).FileClose(handle);
}
private void FileClose(int handle)
{
if (handle < 0 || handle >= MaxFileHandles)
{
Debug.LogWarning($"Invalid file handle! {handle}");
return;
}
fileHandles[handle].Dispose();
fileHandles[handle] = null;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysFileSeekCallback(IntPtr target, int handle, int position);
[MonoPInvokeCallback(typeof(SysFileSeekCallback))]
private static void Callback_SysFileSeek(IntPtr target, int handle, int position)
{
GetSelf(target).FileSeek(handle, position);
}
private void FileSeek(int handle, int position)
{
if (handle < 0 || handle >= MaxFileHandles)
{
Debug.LogWarning($"Invalid file handle! {handle}");
return;
}
fileHandles[handle].Seek(position, SeekOrigin.Begin);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SysFileReadCallback(IntPtr target, int handle, IntPtr dest, int count);
[MonoPInvokeCallback(typeof(SysFileReadCallback))]
private static int Callback_SysFileRead(IntPtr target, int handle, IntPtr dest, int count)
{
return GetSelf(target).FileRead(handle, dest, count);
}
private int FileRead(int handle, IntPtr dest, int count)
{
if (handle < 0 || handle >= MaxFileHandles)
{
Debug.LogWarning($"Invalid file handle! {handle}");
return 0;
}
byte[] buf = new byte[count]; // TODO: reuse buffer
int numRead = fileHandles[handle].Read(buf, 0, count);
Marshal.Copy(buf, 0, dest, numRead);
return numRead;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SysFileWriteCallback(IntPtr target, int handle, IntPtr data, int count);
[MonoPInvokeCallback(typeof(SysFileWriteCallback))]
private static int Callback_SysFileWrite(IntPtr target, int handle, IntPtr data, int count)
{
return GetSelf(target).FileWrite(handle, data, count);
}
private int FileWrite(int handle, IntPtr data, int count)
{
if (handle < 0 || handle >= MaxFileHandles)
{
Debug.LogWarning($"Invalid file handle! {handle}");
return 0;
}
byte[] buf = new byte[count]; // TODO: reuse buffer
Marshal.Copy(data, buf, 0, count);
fileHandles[handle].Write(buf, 0, count);
return count;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SysFileTimeCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string path);
[MonoPInvokeCallback(typeof(SysFileTimeCallback))]
private static int Callback_SysFileTime(IntPtr target, string path)
{
return GetSelf(target).FileTime(path);
}
private int FileTime(string path)
{
// It would logically make more sense to return an actual file write time here,
// but a signed 32-bit int is quite limited and we don't want any Year 2038 problems here.
return File.Exists(path) ? 1 : -1;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SysMkDirCallback(IntPtr target, [MarshalAs(UnmanagedType.LPStr)] string path);
[MonoPInvokeCallback(typeof(SysMkDirCallback))]
private static void Callback_SysMkDir(IntPtr target, string path)
{
GetSelf(target).MkDir(path);
}
private void MkDir(string path)
{
try
{
Directory.CreateDirectory(path);
}
catch
{
Debug.LogWarning($"Could not create directory: {path}");
}
}
}

16
engine/code/sys_win.c

@ -162,7 +162,7 @@ int FileLength (FILE *f)
return end;
}
int Sys_FileOpenRead (char *path, int *hndl)
int Sys_FileOpenRead_Obsolete (char *path, int *hndl)
{
FILE *f;
int i, retval;
@ -191,7 +191,7 @@ int Sys_FileOpenRead (char *path, int *hndl)
return retval;
}
int Sys_FileOpenWrite (char *path)
int Sys_FileOpenWrite_Obsolete(char *path)
{
FILE *f;
int i;
@ -221,7 +221,7 @@ int Sys_FileOpenWrite (char *path)
sys_handles[handle] = NULL;
VID_ForceLockState (t);
}*/
void Sys_FileClose (int handle)
void Sys_FileClose_Obsolete(int handle)
{
int t;
@ -241,7 +241,7 @@ void Sys_FileClose (int handle)
}
// jkrige - pk3 file support
void Sys_FileSeek (int handle, int position)
void Sys_FileSeek_Obsolete(int handle, int position)
{
int t;
@ -296,7 +296,7 @@ void Sys_FFileClose (FILE *f)
VID_ForceLockState (t);
return x;
}*/
int Sys_FileRead (int handle, void *dest, int count)
int Sys_FileRead_Obsolete(int handle, void *dest, int count)
{
int t, x;
@ -311,7 +311,7 @@ int Sys_FileRead (int handle, void *dest, int count)
}
// jkrige - pk3 file support
int Sys_FileWrite (int handle, void *data, int count)
int Sys_FileWrite_Obsolete(int handle, void *data, int count)
{
int t, x;
@ -322,7 +322,7 @@ int Sys_FileWrite (int handle, void *data, int count)
return x;
}
int Sys_FileTime (char *path)
int Sys_FileTime_Obsolete(char *path)
{
FILE *f;
int t, retval;
@ -345,7 +345,7 @@ int Sys_FileTime (char *path)
return retval;
}
void Sys_mkdir (char *path)
void Sys_mkdir_Obsolete(char *path)
{
_mkdir (path);
}

66
engine/projects/uniquake/sys_uniquake.c

@ -38,3 +38,69 @@ double Sys_FloatTime(void)
{
return unity_syscalls->SysFloatTime(unity_syscalls->target);
}
int Sys_FileOpenRead(char *path, int *hndl)
{
int t, retval;
t = VID_ForceUnlockedAndReturnState();
retval = unity_syscalls->SysFileOpenRead(unity_syscalls->target, path, hndl);
VID_ForceLockState(t);
return retval;
}
int Sys_FileOpenWrite(char *path)
{
int t, retval;
t = VID_ForceUnlockedAndReturnState();
retval = unity_syscalls->SysFileOpenWrite(unity_syscalls->target, path);
VID_ForceLockState(t);
return retval;
}
void Sys_FileClose(int handle)
{
int t;
t = VID_ForceUnlockedAndReturnState();
unity_syscalls->SysFileClose(unity_syscalls->target, handle);
VID_ForceLockState(t);
}
void Sys_FileSeek(int handle, int position)
{
int t;
t = VID_ForceUnlockedAndReturnState();
unity_syscalls->SysFileSeek(unity_syscalls->target, handle, position);
VID_ForceLockState(t);
}
int Sys_FileRead(int handle, void *dest, int count)
{
int t, retval;
t = VID_ForceUnlockedAndReturnState();
retval = unity_syscalls->SysFileRead(unity_syscalls->target, handle, dest, count);
VID_ForceLockState(t);
return retval;
}
int Sys_FileWrite(int handle, void *data, int count)
{
int t, retval;
t = VID_ForceUnlockedAndReturnState();
retval = unity_syscalls->SysFileWrite(unity_syscalls->target, handle, data, count);
VID_ForceLockState(t);
return retval;
}
int Sys_FileTime(char *path)
{
int t, retval;
t = VID_ForceUnlockedAndReturnState();
retval = unity_syscalls->SysFileTime(unity_syscalls->target, path);
VID_ForceLockState(t);
return retval;
}
void Sys_mkdir(char *path)
{
unity_syscalls->SysMkDir(unity_syscalls->target, path);
}

9
engine/projects/uniquake/uniquake.h

@ -17,6 +17,15 @@ typedef struct unity_syscalls_s
void(*SysError)(void *target, const char *msg);
void(*SysQuit)(void *target);
double(*SysFloatTime)(void *target);
int(*SysFileOpenRead)(void *target, char *path, int *hndl);
int(*SysFileOpenWrite)(void *target, char *path);
void(*SysFileClose)(void *target, int handle);
void(*SysFileSeek)(void *target, int handle, int position);
int(*SysFileRead)(void *target, int handle, void *dest, int count);
int(*SysFileWrite)(void *target, int handle, void *data, int count);
int(*SysFileTime)(void *target, char *path);
void(*SysMkDir)(void *target, char *path);
} unity_syscalls_t;
extern const unity_syscalls_t *unity_syscalls;
Loading…
Cancel
Save