You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

183 lines
4.6 KiB

using System;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
public class UniQuake: MonoBehaviour
{
#if UNITY_EDITOR
private const string DllPath = "Plugins/windows/x86_64/uniquake.dll";
#elif UNITY_STANDALONE_WIN
#if UNITY_64
private const string DllPath = "Plugins/x86_64/uniquake.dll";
#else
private const string DllPath = "Plugins/x86/uniquake.dll";
#endif
#endif
private const int MemSize = 0x4000000; // 64 MB of heap space
private IntPtr libraryHandle;
private QuakeParms quakeParms;
private SystemModule systemModule;
private RenderModule renderModule;
private bool initialized = false;
private double startTime;
/// <summary>
/// Time since startup for this particular instance of Quake
/// </summary>
public double CurrentTime => Time.timeAsDouble - startTime;
void Start()
{
systemModule = new SystemModule(this);
renderModule = new RenderModule(this);
LoadLibrary();
string[] arguments =
{
"",
"-window",
"-width", "1440",
"-height", "1080",
"+developer", "1",
};
quakeParms = new QuakeParms
{
baseDir = Application.persistentDataPath,
cacheDir = null,
};
quakeParms.SetArguments(arguments);
quakeParms.AllocateMemory(MemSize);
startTime = Time.timeAsDouble;
try
{
UniQuake_Init(quakeParms, systemModule.ToIntPtr, renderModule.ToIntPtr);
initialized = true;
}
catch (QuakeException ex)
{
if (ex.ExitCode == 0)
Debug.Log(ex.Message);
else
Debug.LogException(ex);
Shutdown();
}
catch (Exception ex)
{
Debug.LogException(ex);
Shutdown();
}
}
void Update()
{
if (!initialized)
return;
try
{
UniQuake_Update(Time.deltaTime);
}
catch (QuakeException ex)
{
if (ex.ExitCode == 0)
Debug.Log(ex.Message);
else
Debug.LogException(ex);
Shutdown();
}
catch (Exception ex)
{
Debug.LogException(ex);
Shutdown();
}
}
private void Shutdown()
{
initialized = false;
UniQuake_Shutdown();
Destroy(this);
}
private void OnDestroy()
{
renderModule.Destroy();
systemModule.Destroy();
if (quakeParms != null)
{
quakeParms.Destroy();
quakeParms = null;
}
FreeLibrary();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void UniQuake_InitFunc(QuakeParms parms, IntPtr sysCalls, IntPtr modCalls);
private UniQuake_InitFunc UniQuake_Init;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void UniQuake_UpdateFunc(float deltaTime);
private UniQuake_UpdateFunc UniQuake_Update;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void UniQuake_ShutdownFunc();
private UniQuake_ShutdownFunc UniQuake_Shutdown;
private void LoadLibrary()
{
string dllFile = Path.Combine(Application.dataPath, DllPath);
libraryHandle = SystemLibrary.LoadLibrary(dllFile);
if (libraryHandle == IntPtr.Zero)
{
throw new DllNotFoundException($"Failed to load UniQuake library from path: {dllFile}, last error = {Marshal.GetLastWin32Error()}");
}
UniQuake_Init = LoadLibraryFunction<UniQuake_InitFunc>("UniQuake_Init");
UniQuake_Update = LoadLibraryFunction<UniQuake_UpdateFunc>("UniQuake_Update");
UniQuake_Shutdown = LoadLibraryFunction<UniQuake_ShutdownFunc>("UniQuake_Shutdown");
}
private TDelegate LoadLibraryFunction<TDelegate>(string name)
{
IntPtr procAddress = SystemLibrary.GetProcAddress(libraryHandle, name);
if (procAddress == IntPtr.Zero)
{
throw new DllNotFoundException($"Could not find library function: {name}");
}
return Marshal.GetDelegateForFunctionPointer<TDelegate>(procAddress);
}
private void FreeLibrary()
{
if (libraryHandle != IntPtr.Zero)
{
SystemLibrary.FreeLibrary(libraryHandle);
libraryHandle = IntPtr.Zero;
}
}
}
public class QuakeException: Exception
{
public int ExitCode { get; }
public QuakeException(string message, int exitCode = 0)
: base(message)
{
ExitCode = exitCode;
}
}