From fa50659490ae8a44ddef2fbb17cce596691ae196 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Sun, 4 Apr 2021 13:52:43 +0200 Subject: [PATCH] Use custom exceptions to stop control flow in the Quake engine on Error and Quit, and shut down the engine. Doesn't work quite as intended yet (Quit will terminate the entire Unity application for some reason, instead of just Quake) but it's a step in the right direction. --- Assets/Scripts/SysCalls.cs | 9 ++-- Assets/Scripts/UniQuake.cs | 66 ++++++++++++++++++++++++- engine/projects/uniquake/sys_uniquake.c | 1 - engine/projects/uniquake/uniquake.c | 5 ++ 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Assets/Scripts/SysCalls.cs b/Assets/Scripts/SysCalls.cs index 36fb1f6..ba6da75 100644 --- a/Assets/Scripts/SysCalls.cs +++ b/Assets/Scripts/SysCalls.cs @@ -99,9 +99,8 @@ public class SysCalls: CallbackHandler 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); + // Use an exception to emulate Quake's behavior of immediately terminating the game's code execution on error + throw new QuakeException(message, 1); } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -115,8 +114,8 @@ public class SysCalls: CallbackHandler private void Quit() { - Debug.Log($"Quitting application normally"); - Application.Quit(0); + // This exception will be caught by the UniQuake update loop where the game will be shut down + throw new QuakeException("Quitting application normally"); } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index 2d04ce3..1933449 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -11,6 +11,8 @@ public class UniQuake: MonoBehaviour private SysCalls sysCalls; private ModCalls modCalls; + private bool initialized = false; + void Start() { string[] arguments = @@ -33,16 +35,62 @@ public class UniQuake: MonoBehaviour sysCalls = new SysCalls(this); modCalls = new ModCalls(this); - UniQuake_Init(quakeParms, sysCalls.ToIntPtr, modCalls.ToIntPtr); + try + { + UniQuake_Init(quakeParms, sysCalls.ToIntPtr, modCalls.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() { - UniQuake_Update(Time.deltaTime); + 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() { + modCalls.Destroy(); sysCalls.Destroy(); if (quakeParms != null) @@ -57,4 +105,18 @@ public class UniQuake: MonoBehaviour [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] private static extern void UniQuake_Update(float deltaTime); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + private static extern void UniQuake_Shutdown(); } + +public class QuakeException: Exception +{ + public int ExitCode { get; } + + public QuakeException(string message, int exitCode = 0) + : base(message) + { + ExitCode = exitCode; + } +} diff --git a/engine/projects/uniquake/sys_uniquake.c b/engine/projects/uniquake/sys_uniquake.c index 3d2f838..1f3e1f9 100644 --- a/engine/projects/uniquake/sys_uniquake.c +++ b/engine/projects/uniquake/sys_uniquake.c @@ -30,7 +30,6 @@ void Sys_Printf(char *fmt, ...) void Sys_Quit(void) { - Host_Shutdown(); unity_syscalls->SysQuit(unity_syscalls->target); } diff --git a/engine/projects/uniquake/uniquake.c b/engine/projects/uniquake/uniquake.c index 5a3e606..f520d2f 100644 --- a/engine/projects/uniquake/uniquake.c +++ b/engine/projects/uniquake/uniquake.c @@ -20,3 +20,8 @@ UNIQUAKE_API void UniQuake_Update(float deltaTime) Host_Frame(deltaTime); } + +UNIQUAKE_API void UniQuake_Shutdown() +{ + Host_Shutdown(); +}