Lighthouse Engine Logging and Debugging Capabilities: Complete Guide
Lighthouse provides built-in on-screen debug text, per-module debug stubs, audio-specific flags, and compile-time toggles to inspect game state without external tools.
The HarbourMasters Lighthouse project is an open-source N64-style game engine that ships with lightweight, runtime-visible debugging utilities. These capabilities are designed for target hardware and emulators, offering printf-style diagnostics where a conventional console does not exist. This guide covers every logging and debugging facility available in the codebase.
On-Screen Debug Text Overlay
The primary debugging interface is a small console rendered directly on the game screen. It can display integers, floats, and strings in real time.
Core Functions in src/core1/debugtext.c
The debug text system centers on three key functions:
gcdebugText_showLargeValue(int slot, s32 value)— Prints a 32-bit integer to a numbered on-screen slot.gcdebugText_pauseThread(void)— Halts execution so you can read the value before it updates.gcdebugText_isThreadLocked(void)— Returns whether the debug thread lock is active, useful for race-condition detection.
Example: Displaying a Large Integer
/* Print 12345678 to debug slot 1 */
gcdebugText_showLargeValue(1, 12345678);
gcdebugText_pauseThread(); /* Halt to inspect in emulator */
This pattern appears throughout the engine when developers need immediate visual feedback without serial output.
Per-Module Debug Stubs
Most core modules expose a *_debug or *_debugN function that prints internal state when invoked. These stubs are empty in release builds but activate when compiled with DEBUG or _DEBUG_INTERNAL macros.
Key Debug Stubs by Module
| Function | Source File | Purpose |
|---|---|---|
viewport_debug |
src/core1/viewport.c |
Visualizes viewport transform matrices and clipping planes. |
overlayManager_debug |
src/core1/overlaymanager.c |
Lists active memory overlays and their load states. |
mumboscore_debug |
src/core2/mumboscore.c |
Dumps Mumbo token counts and unlock flags. |
jiggyscore_debug |
src/core2/jiggyscore.c |
Prints Jiggy piece collection state. |
honeycombscore_debug |
src/core2/honeycombscore.c |
Shows health upgrade progress. |
Example: Invoking Module Debug Output
void mySpecialFunction(void) {
/* ... normal game logic ... */
viewport_debug(); /* Prints viewport state (DEBUG builds only) */
}
These stubs follow a consistent naming convention: module name suffixed with _debug, returning void and taking no parameters in most cases.
Audio Subsystem Debug Flags
The n_audio subsystem includes specialized diagnostics for tracking sound engine failures. Two files implement these checks:
src/core1/n_audio/n_seqplayer.c— Sequence player diagnostics.src/core1/n_audio/n_csplayer.c— Compressed sound player diagnostics.
Both use a debugFlags field with macros like ALFlagFailIf to assertion-fail or print when specific error conditions occur.
Example: Checking Audio Debug Flags
/* From n_seqplayer.c: flag missing sound errors */
if (seqp->debugFlags & NO_SOUND_ERR_MASK) {
gcdebugText_showLargeValue(2, 2002); /* Error code 2002 = missing sound */
}
The NO_SOUND_ERR_MASK and similar constants allow granular control over which audio errors surface to the debug overlay.
Compile-Time Debug Toggles
All debug functionality is gated by preprocessor macros. Enabling these at build time activates the entire debugging surface without source changes.
Build Configuration Macros
| Macro | Effect | Typical Location |
|---|---|---|
DEBUG |
Legacy toggle; enables basic debug stubs. | Compiler command line or CMakeLists.txt |
_DEBUG_INTERNAL |
Modern replacement; activates verbose logging and on-screen text. | CMakeLists.txt or header predefines |
In CMakeLists.txt, you might define:
target_compile_definitions(lighthouse PRIVATE _DEBUG_INTERNAL)
When neither macro is defined, debug stubs compile to empty functions and gcdebugText_* calls become no-ops, ensuring zero runtime overhead in release builds.
Thread-Safety Verification
The debug text system includes primitives for detecting concurrent access to critical sections.
Functions for Race-Condition Detection
gcdebugText_isThreadLocked(void)— Query whether the debug system holds its internal lock.gcdebugText_pauseThread(void)— Explicitly acquire the lock and halt; serves as a breakpoint substitute.
Example: Verifying Thread Safety
if (gcdebugText_isThreadLocked()) {
/* Another context already holds the lock — potential race */
gcdebugText_showLargeValue(3, 0xDEAD);
}
gcdebugText_pauseThread(); /* Safe inspection point */
This pattern helps catch main thread violations on N64 hardware where traditional debuggers are unavailable.
Summary
- On-screen debug text in
src/core1/debugtext.cprovidesgcdebugText_showLargeValue,gcdebugText_pauseThread, andgcdebugText_isThreadLockedfor runtime visualization. - Per-module stubs like
viewport_debug,overlayManager_debug, andmumboscore_debugoffer state dumps when_DEBUG_INTERNALis defined. - Audio debug flags in
n_seqplayer.candn_csplayer.cexposedebugFlagsfields for sound engine diagnostics. - Compile-time toggles via
DEBUGor_DEBUG_INTERNALmacros enable or strip all debug code at build time. - Thread-safety helpers allow rudimentary race condition detection without external tooling.
These capabilities make Lighthouse logging and debugging practical for N64 hardware development where conventional debugging infrastructure is absent.
Frequently Asked Questions
How do I enable debug output in a Lighthouse build?
Define _DEBUG_INTERNAL in your build configuration, typically by adding target_compile_definitions(lighthouse PRIVATE _DEBUG_INTERNAL) to CMakeLists.txt or passing -D_DEBUG_INTERNAL to your compiler. This activates all debug stubs and the on-screen text overlay.
Where is the on-screen debug console implemented?
The debug text overlay lives in src/core1/debugtext.c. It provides gcdebugText_showLargeValue for printing integers, gcdebugText_pauseThread for execution halts, and gcdebugText_isThreadLocked for thread-safety checks.
Do debug features impact release build performance?
No. When DEBUG and _DEBUG_INTERNAL are undefined, all debug functions compile to empty bodies or no-ops. The linker typically eliminates them entirely, resulting in zero runtime overhead.
Can I add custom debug output to my own Lighthouse module?
Yes. Follow the established pattern: create a yourmodule_debug(void) function that prints relevant state, guard it with #ifdef _DEBUG_INTERNAL, and call it where needed. The build system will strip it automatically in release builds.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →