feat: Exit on first Python callback exception (closes #133)

By default, McRogueFace now exits with code 1 on the first unhandled
exception in timer, click, key, or animation callbacks. This prevents
repeated exception output that wastes resources in AI-driven development.

Changes:
- Add exit_on_exception config flag (default: true)
- Add --continue-after-exceptions CLI flag to preserve old behavior
- Update exception handlers in Timer, PyCallable, and Animation
- Signal game loop via McRFPy_API atomic flags
- Return proper exit code from main()

Before: Timer exceptions repeated 1000+ times until timeout
After: Single traceback, clean exit with code 1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
John McCardle 2025-11-26 10:26:30 -05:00
commit 19ded088b0
12 changed files with 160 additions and 8 deletions

View file

@ -44,6 +44,11 @@ int run_game_engine(const McRogueFaceConfig& config)
if (Py_IsInitialized()) {
McRFPy_API::api_shutdown();
}
// Return exception exit code if a Python exception signaled exit
if (McRFPy_API::shouldExit()) {
return McRFPy_API::exit_code.load();
}
return 0;
}
@ -181,9 +186,13 @@ int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv
// Run the game engine after script execution
engine->run();
McRFPy_API::api_shutdown();
delete engine;
// Return exception exit code if signaled
if (McRFPy_API::shouldExit()) {
return McRFPy_API::exit_code.load();
}
return result;
}
else if (config.interactive_mode) {
@ -207,6 +216,10 @@ int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv
engine->run();
McRFPy_API::api_shutdown();
delete engine;
// Return exception exit code if signaled
if (McRFPy_API::shouldExit()) {
return McRFPy_API::exit_code.load();
}
return 0;
}