Debugging & crash handling
FPS and memory overlay
debug.FPSCounter (created in Main.setupGame() as Main.fpsVar) shows framerate and,
optionally, RAM and peak RAM. Driven by:
| Preference | Effect |
|---|---|
showFPS | show the counter at all |
showRamUsage / showMaxRamUsage | add current / peak memory |
debugInfo | extra diagnostics |
Memory numbers come from debug.Memory and utils.MemoryUtil; debug/mem/ contains a
small C++ include (GetTotalMemory.hx + build.xml) for an accurate native figure.
Two optimizations to preserve: the PlayState check is cached (Main.isPlayState()) rather
than re-running Std.isOfType each frame, and the text outline redraw is throttled.
Crash handling
With CRASH_HANDLER enabled (the default), backend.CrashHandler.init() runs before the
game is created and installs an OpenFL uncaught-error handler. On a crash it writes a log
and shows states.ErrorState instead of killing the window.
The readable native stack traces come from defines set in project.hxp:
openfl-enable-handle-error, HXCPP_CHECK_POINTER, HXCPP_STACK_LINE,
HXCPP_STACK_TRACE, HXCPP_CATCH_SEGV.
ClientPrefs.peOGCrash switches to the plain Psych-style crash dialog for users who
prefer it. CoolUtil.coolError(message, title) is the engine's own error popup, used for
recoverable problems (for example opening the Note Colors menu with the feature off).
Hardware information in the crash log
Every crash log (crash/FNF-Phoenix-Engine_<date>.log) ends with the hardware the game
was running on, so a bug report carries it automatically:
GPU: NVIDIA GeForce RTX 3060
GPU Vendor: NVIDIA
GPU Driver: 535.104.05
Graphics API: OpenGL 4.6
CPU: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
CPU Vendor: Intel
OS: Windows 10.0.19045
Audio: OpenAL Soft | 1.23.1
backend.Native collects the values: the GPU, its vendor and the driver version come
from the OpenGL context (GL.VENDOR, GL.RENDERER, GL.VERSION), the CPU and the
operating system from the small native layer in source/backend/native/. The GPU
sniffing is ported from the Psych Plus Engine
— thanks to the Psych Plus Team for the original implementation.
Everything degrades gracefully: a target without a render context or without the native
queries reports Unknown instead of failing, and the crash log is still written.
The same values are available to scripts through getSystemInfo(), getGPUName(),
getGPUVendor(), getGPUDriverVersion(), getCPUName(), getCPUVendor(),
getOSName(), getOSVersion(), getGraphicsApi() and getAudioApi() (Lua, Python and
HScript), see the Lua and
Python API references.
Script errors
Lua, Python and HScript errors never take the game down:
shaders.ErrorHandledShadercatches shader compile failures.psychlua.DebugLuaTextprints script errors anddebugPrint(...)output on screen, throughluaDebugGroup/pythonDebugGroupinPlayState.- Script hosts catch exceptions per call, so one broken hook does not stop the others.
Build metadata
backend.HaxeCommit exposes the git branch/commit the build came from (printed by
project.hxp's flair() at build time), which is what crash reports and the title screen
can show. VERSION in project.hxp is the single source of the version string.
Discord Rich Presence
backend.DiscordClient (flag DISCORD_ALLOWED, library hxdiscord_rpc) publishes the
current state and song. It is toggled by ClientPrefs.discordRPC, scripts can change it
with changePresence(...), and option menus set an rpcTitle. On Android the equivalent
is routed through android.platform.AndroidDiscord.
Profiling and experimental builds
| Define | Effect |
|---|---|
-DDEBUG_TRACY / FEATURE_DEBUG_TRACY | Tracy profiler instrumentation |
-DULTRA_OPTIMIZED | experimental maximum-speed configuration |
-DULTRA_HTML5 | experimental web optimization |
-debug | Flixel/Haxe debug build, enables #if debug blocks |
Tracing conventions
Unconditional trace() calls were deliberately removed from hot paths. New ones belong
inside #if debug:
#if debug
trace('loaded ${notes.length} notes');
#end
Screenshots
backend.Screenshot plus the backend.SSPlugin Flixel plugin (added in
Main.setupGame()) capture the window to disk without going through the OS.