Add engine fatal error types handling

Add general out-of-memory handling
Add safety memory buffer for crash or out of memory handling
Refactor Globals exit/error state to be in Engine class
This commit is contained in:
Wojtek Figat
2025-01-24 20:07:12 +01:00
parent fa2f2e3104
commit cf40facefe
20 changed files with 166 additions and 159 deletions

View File

@@ -71,6 +71,9 @@ Action Engine::Draw;
Action Engine::Pause;
Action Engine::Unpause;
Action Engine::RequestingExit;
FatalErrorType Engine::FatalError = FatalErrorType::None;
bool Engine::IsRequestingExit = false;
int32 Engine::ExitCode = 0;
Window* Engine::MainWindow = nullptr;
int32 Engine::Main(const Char* cmdLine)
@@ -201,7 +204,7 @@ int32 Engine::Main(const Char* cmdLine)
PROFILE_CPU_NAMED("Platform.Tick");
Platform::Tick();
}
// Update game logic
if (Time::OnBeginUpdate(time))
{
@@ -236,12 +239,13 @@ int32 Engine::Main(const Char* cmdLine)
FileSystem::DeleteDirectory(Globals::TemporaryFolder);
}
return Globals::ExitCode;
return ExitCode;
}
void Engine::Exit(int32 exitCode)
void Engine::Exit(int32 exitCode, FatalErrorType error)
{
ASSERT(IsInMainThread());
FatalError = error;
// Call on exit event
OnExit();
@@ -250,23 +254,23 @@ void Engine::Exit(int32 exitCode)
exit(exitCode);
}
void Engine::RequestExit(int32 exitCode)
void Engine::RequestExit(int32 exitCode, FatalErrorType error)
{
if (Globals::IsRequestingExit)
if (IsRequestingExit)
return;
#if USE_EDITOR
// Send to editor (will leave play mode if need to)
if (Editor::Managed->OnAppExit())
{
Globals::IsRequestingExit = true;
Globals::ExitCode = exitCode;
RequestingExit();
}
#else
if (!Editor::Managed->OnAppExit())
return;
#endif
IsRequestingExit = true;
ExitCode = exitCode;
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
Globals::IsRequestingExit = true;
Globals::ExitCode = exitCode;
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
FatalError = error;
RequestingExit();
#endif
}
void Engine::OnFixedUpdate()
@@ -407,7 +411,7 @@ bool Engine::IsReady()
bool Engine::ShouldExit()
{
return Globals::IsRequestingExit;
return IsRequestingExit;
}
bool Engine::IsEditor()

View File

@@ -14,9 +14,9 @@ class JsonAsset;
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Engine
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Engine);
public:
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Engine);
public:
/// <summary>
/// The engine start time (local time).
/// </summary>
@@ -38,7 +38,6 @@ public:
API_FIELD(ReadOnly) static uint64 FrameCount;
public:
/// <summary>
/// Event called on engine fixed update.
/// </summary>
@@ -84,8 +83,22 @@ public:
/// </summary>
API_EVENT() static Action RequestingExit;
public:
/// <summary>
/// The current state of the fatal error. Set to None if no error occurred yet.
/// </summary>
API_FIELD(ReadOnly) static FatalErrorType FatalError;
/// <summary>
/// Flags set to true if engine needs to be closed (exit is pending). Use FatalError to determinate the exit reason (specific error or normal shutdown).
/// </summary>
API_FIELD(ReadOnly) static bool IsRequestingExit;
/// <summary>
/// The current process exit code (pending to return).
/// </summary>
static int32 ExitCode;
public:
/// <summary>
/// The main engine function (must be called from platform specific entry point).
/// </summary>
@@ -97,16 +110,17 @@ public:
/// Exits the engine.
/// </summary>
/// <param name="exitCode">The exit code.</param>
API_FUNCTION(Attributes="DebugCommand") static void Exit(int32 exitCode = -1);
/// <param name="error">The fatal error type (or None on graceful exit).</param>
API_FUNCTION(Attributes="DebugCommand") static void Exit(int32 exitCode = -1, FatalErrorType error = FatalErrorType::None);
/// <summary>
/// Requests normal engine exit.
/// </summary>
/// <param name="exitCode">The exit code.</param>
API_FUNCTION() static void RequestExit(int32 exitCode = 0);
/// <param name="error">The fatal error type (or None on graceful exit).</param>
API_FUNCTION() static void RequestExit(int32 exitCode = 0, FatalErrorType error = FatalErrorType::None);
public:
/// <summary>
/// Fixed update callback used by the physics simulation (fixed stepping).
/// </summary>
@@ -138,7 +152,6 @@ public:
static void OnExit();
public:
// Returns true if engine is running without main window (aka headless mode).
API_PROPERTY() static bool IsHeadless();
@@ -184,7 +197,6 @@ public:
API_PROPERTY() static bool HasGameViewportFocus();
private:
static void OnPause();
static void OnUnpause();
};

View File

@@ -18,9 +18,11 @@ String Globals::ProjectContentFolder;
#if USE_MONO
String Globals::MonoPath;
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
bool Globals::FatalErrorOccurred;
bool Globals::IsRequestingExit;
int32 Globals::ExitCode;
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
uint64 Globals::MainThreadID;
String Globals::EngineVersion(TEXT(FLAXENGINE_VERSION_TEXT));
int32 Globals::EngineBuildNumber = FLAXENGINE_VERSION_BUILD;

View File

@@ -10,8 +10,9 @@
/// </summary>
API_CLASS(Static, Attributes="DebugCommand") class FLAXENGINE_API Globals
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
public:
// Paths
// Main engine directory path.
@@ -34,7 +35,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
API_FIELD(ReadOnly) static String BinariesFolder;
#if USE_EDITOR
// Project specific cache folder path (editor-only).
API_FIELD(ReadOnly) static String ProjectCacheFolder;
@@ -43,43 +43,60 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
// Game source code directory path (editor-only).
API_FIELD(ReadOnly) static String ProjectSourceFolder;
#endif
// Project content directory path
// Project content directory path.
API_FIELD(ReadOnly) static String ProjectContentFolder;
#if USE_MONO
// Mono library folder path
// Mono library folder path.
API_FIELD(ReadOnly) static String MonoPath;
#endif
public:
// State
// True if fatal error occurred (engine is exiting)
static bool FatalErrorOccurred;
// True if fatal error occurred (engine is exiting).
// [Deprecated in v1.10]
static DEPRECATED("Use Engine::FatalError instead.") bool FatalErrorOccurred;
// True if engine needs to be closed
static bool IsRequestingExit;
// True if engine needs to be closed.
// [Deprecated in v1.10]
static DEPRECATED("Use Engine::IsRequestingExit instead.") bool IsRequestingExit;
/// <summary>
/// True if engine needs to be closed
/// Flags set to true if engine needs to be closed (exit is pending).
/// [Deprecated in v1.10]
/// </summary>
API_PROPERTY() FORCE_INLINE static bool GetIsRequestingExit() { return IsRequestingExit; }
API_PROPERTY() DEPRECATED("Use Engine::IsRequestingExit instead.") FORCE_INLINE static bool GetIsRequestingExit()
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
return IsRequestingExit;
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
}
/// <summary>
/// True if fatal error occurred (engine is exiting)
/// Flags set to true if fatal error occurred (engine is exiting).
/// [Deprecated in v1.10]
/// </summary>
API_PROPERTY() FORCE_INLINE static bool GetFatalErrorOccurred() { return FatalErrorOccurred; }
API_PROPERTY() DEPRECATED("Use Engine::FatalError instead.") FORCE_INLINE static bool GetFatalErrorOccurred()
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
return FatalErrorOccurred;
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
}
// Exit code
static int32 ExitCode;
// Process exit code (pending to return).
// [Deprecated in v1.10]
static DEPRECATED("Use Engine::ExitCode instead.") int32 ExitCode;
public:
// Threading
// Main Engine thread id
// Main Engine thread id.
API_FIELD(ReadOnly) static uint64 MainThreadID;
public:
// Config
/// <summary>