If you are like me and prefer to address serious errors in a timely fashion instead of ignoring them, you'll be soon wondering how to change this strange behaviour and stop the execution of your program on a non-recoverable error. After some research, I've found no standard solution, only three workarounds:
- You can wrap every MonoBehaviour callback in a try-catch block and abort on catch.
- You can forgo the standard throwing mechanism altogether and call your own routine, something like
ThrowException(new Exception())
, which will terminate your application. - You can attach a listener to the log and react if an exception is logged. It will work even if the Player log is turned off in Player settings.
class ErrorHandler extends MonoBehaviour
{
static function ThrowException(_exception: Exception)
{
if (exception == null) {
exception = _exception;
}
}
static function HasExceptionHappened(): boolean
{
return (exception != null);
}
static private var exception: Exception;
function Update()
{
if (exception != null) {
Debug.LogException(exception);
exception = null;
Application.Quit();
}
}
}
DoSomething();
if (ErrorHandler.HasExceptionHappened()) return;
DoSomethingElse();
if (ErrorHandler.HasExceptionHappened()) return;
Also, you couldn't force 3rd party scripts to use it anyway. The only sound solution seems to be the #3 (see [1] for more details).
What if you wanted to abort?
Application.Quit()
is great for exiting under normal conditions, but how do you indicate to the outside world that your application didn't finish peacefully? System.Environment.Exit()
doesn't work, neither do System.Environment.ExitCode
, System.Diagnostics.Debug
or System.Diagnostics.Trace
methods. The best bet would be to store the return value into a file or a system registry, where it could be acted upon by an error reporter or whatever running in parallel. Considering the
System.Diagnostics.Debug
and System.Diagnostics.Trace
don't work, asserts are also not available. And the System.Diagnostics.Contracts.Contract.Assert()
is too new to be supported. It's easy to implement your own basic asserts though:
[Conditional("DEBUG")]
static public void Assert(bool _condition, string _message = "")
{
if (! _condition) {
Debug.LogError("Assertion failed: " + _message);
Application.Quit();
}
}
Notice the
“DEBUG”
constant. It is not set by default, and in Unity you cannot use #define
to make pre-processor defines. They are simply ignored. However, you can specify them in “Edit → Project Settings → Player” under “Scripting Define Symbols” for each platform. It is a little clumsy to write and delete them by hand, but the process could be possibly automated by a script (see PlayerSettings.SetScriptingDefineSymbolsForGroup).
No comments:
Post a Comment