11#define IMGUI_DEFINE_MATH_OPERATORS
19#include "absl/debugging/symbolize.h"
20#include "absl/strings/ascii.h"
21#include "absl/strings/str_split.h"
22#include "absl/strings/strip.h"
28#if !defined(__EMSCRIPTEN__) && defined(YAZE_HTTP_API_ENABLED)
40DEFINE_FLAG(std::string, log_file,
"",
"Output log file path for debugging.");
41DEFINE_FLAG(std::string, rom_file,
"",
"ROM file to load on startup.");
42DEFINE_FLAG(
bool, debug,
false,
"Enable debug logging and verbose output.");
44 "Minimum log level: debug, info, warn, error, or fatal.");
46 "Mirror logs to stderr even when writing to a file.");
48 std::string, log_categories,
"",
49 "Comma-separated list of log categories to enable or disable. "
50 "Prefix with '-' to disable a category. "
51 "Example: \"Room,DungeonEditor\" (allowlist) or \"-Input,-Graphics\" "
56 std::string, editor,
"",
57 "The editor to open on startup (e.g., Dungeon, Overworld, Assembly).");
60 "Comma-separated list of panel IDs to open (e.g. "
61 "'dungeon.room_list,emulator.cpu_debugger')");
65 "Welcome screen behavior at startup: auto, show, or hide.");
67 "Dashboard panel behavior at startup: auto, show, or hide.");
69 "Panel sidebar visibility at startup: auto, show, or hide.");
71 "Asset load mode: auto, full, or lazy.");
73DEFINE_FLAG(
int, room, -1,
"Open Dungeon Editor at specific room ID (0-295).");
74DEFINE_FLAG(
int, map, -1,
"Open Overworld Editor at specific map ID (0-159).");
77DEFINE_FLAG(
bool, enable_api,
false,
"Enable the AI Agent API server.");
78DEFINE_FLAG(
int, api_port, 8080,
"Port for the AI Agent API server.");
81 "Run in headless mode without a GUI window.");
83 "Run in service mode (GUI backend initialized but window hidden).");
86 "Run in server mode (implies --enable_api, --enable_test_harness). "
87 "Defaults to --headless unless --service or --no-headless is specified.");
92 "Start gRPC test harness server for automated GUI testing.");
95 "Port for Unified gRPC server (default: 50052).");
97 "Emulator backend for gRPC service: 'internal' or 'mesen'.");
102 "Export symbols to file (requires --rom_file).");
104 "Format for symbol export: mesen, wla, asar, bsnes.");
106 "Load symbol file (.mlb, .sym, .asm) on startup.");
108 "Load Asar symbols from directory on startup.");
110 "Export symbols without initializing UI. Requires --load_symbols "
111 "or --load_asar_symbols.");
130 if (ctrl && ctrl->editor_manager()) {
154 const std::string lower = absl::AsciiStrToLower(raw_level);
155 if (lower ==
"debug") {
158 if (lower ==
"warn" || lower ==
"warning") {
161 if (lower ==
"error") {
164 if (lower ==
"fatal") {
171 std::set<std::string> categories;
172 for (absl::string_view token :
173 absl::StrSplit(raw,
',', absl::SkipWhitespace())) {
174 if (!token.empty()) {
175 categories.insert(std::string(absl::StripAsciiWhitespace(token)));
198 std::vector<std::string> tokens;
199 for (absl::string_view token :
200 absl::StrSplit(raw,
',', absl::SkipWhitespace())) {
201 if (!token.empty()) {
202 tokens.emplace_back(absl::StripAsciiWhitespace(token));
211 for (
int i = 1; i < argc; ++i) {
212 const std::string arg = argv[i];
213 if (arg ==
"--version") {
217 if (arg ==
"--help" || arg ==
"-h") {
219 <<
"Usage: " << argv[0] <<
" [flags]\n\nFlags:\n";
221 std::sort(flags.begin(), flags.end(),
223 return a->name() < b->name();
225 for (
const auto* flag : flags) {
226 std::cout <<
" " << flag->name() <<
"\n " << flag->help() <<
"\n";
243#ifndef __EMSCRIPTEN__
250 bool log_to_console_flag) {
253 std::set<std::string> log_categories =
256 std::string log_path = FLAGS_log_file->Get();
257 if (log_path.empty()) {
260 log_path = (*logs_dir /
"yaze.log").
string();
267 if (debug_flag || log_to_console_flag) {
271 LOG_INFO(
"Main",
"🚀 YAZE started in debug mode");
274 "Logging configured (level=%s, file=%s, console=%s, categories=%zu)",
276 log_path.empty() ?
"<stderr>" : log_path.c_str(),
277 (debug_flag || log_to_console_flag) ?
"on" :
"off",
278 log_categories.size());
283 std::string log_path) {
286 bool server_mode = FLAGS_server->Get();
287 bool service_mode = FLAGS_service->Get();
289 config.
headless = FLAGS_headless->Get() || (server_mode && !service_mode);
291 config.
enable_api = FLAGS_enable_api->Get() || server_mode || service_mode;
295 FLAGS_enable_test_harness->Get() || server_mode || service_mode;
297 config.
backend = FLAGS_backend->Get();
300 config.
rom_file = FLAGS_rom_file->Get();
307 config.
api_port = FLAGS_api_port->Get();
323 if (!FLAGS_open_panels->Get().empty()) {
330 if (!FLAGS_export_symbols->Get().empty() &&
331 FLAGS_export_symbols_fast->Get()) {
335 if (!FLAGS_load_symbols->Get().empty()) {
336 LOG_INFO(
"Main",
"Loading symbols from %s...",
337 FLAGS_load_symbols->Get().c_str());
340 LOG_ERROR(
"Main",
"Failed to load symbols: %s",
341 status.ToString().c_str());
347 if (!FLAGS_load_asar_symbols->Get().empty()) {
348 LOG_INFO(
"Main",
"Loading Asar symbols from %s...",
349 FLAGS_load_asar_symbols->Get().c_str());
353 LOG_ERROR(
"Main",
"Failed to load Asar symbols: %s",
354 status.ToString().c_str());
363 "No symbols loaded. Use --load_symbols or --load_asar_symbols.");
367 LOG_INFO(
"Main",
"Exporting symbols to %s...",
368 FLAGS_export_symbols->Get().c_str());
371 std::string format_str = absl::AsciiStrToLower(FLAGS_symbol_format->Get());
372 if (format_str ==
"asar")
374 else if (format_str ==
"wla")
376 else if (format_str ==
"bsnes")
380 if (export_or.ok()) {
381 std::ofstream out(FLAGS_export_symbols->Get());
384 LOG_INFO(
"Main",
"Symbols exported successfully (fast path)");
387 LOG_ERROR(
"Main",
"Failed to open output file: %s",
388 FLAGS_export_symbols->Get().c_str());
391 LOG_ERROR(
"Main",
"Failed to export symbols: %s",
392 export_or.status().ToString().c_str());
398#if !defined(__EMSCRIPTEN__) && defined(YAZE_HTTP_API_ENABLED)
399std::unique_ptr<yaze::cli::api::HttpServer> SetupApiServer(
405 auto api_server = std::make_unique<yaze::cli::api::HttpServer>();
408 api_server->SetSymbolProviderSource(
412 return &manager->emulator().symbol_provider();
418 api_server->SetWindowActions(
421 return controller ? (controller->ShowWindow(),
true) : false;
425 return controller ? (controller->HideWindow(),
false)
429 auto status = api_server->Start(config.
api_port);
431 LOG_ERROR(
"Main",
"Failed to start API server: %s",
432 std::string(status.message()).c_str());
443int main(
int argc,
char** argv) {
444 absl::InitializeSymbolizer(argv[0]);
456 const bool debug_flag = FLAGS_debug->Get();
457 const bool log_to_console_flag = FLAGS_log_to_console->Get();
459 std::string log_path = FLAGS_log_file->Get();
460 if (log_path.empty()) {
463 log_path = (*logs_dir /
"yaze.log").
string();
474#if !defined(__EMSCRIPTEN__)
479 if (!FLAGS_export_symbols->Get().empty() &&
480 FLAGS_export_symbols_fast->Get()) {
487 return yaze_run_cocoa_app_delegate(config);
491#if defined(_WIN32) && !defined(__EMSCRIPTEN__)
496 yaze::app::wasm::InitializeWasmPlatform();
500 static bool s_wasm_initialized =
false;
503 auto WasmMainLoop = []() {
505 if (!s_wasm_initialized) {
506 if (yaze::app::wasm::IsFileSystemReady()) {
507 LOG_INFO(
"Main",
"Filesystem ready, initializing application...");
509 s_wasm_initialized =
true;
522 emscripten_set_main_loop(WasmMainLoop, 0, 1);
527#if defined(YAZE_HTTP_API_ENABLED)
528 std::unique_ptr<yaze::cli::api::HttpServer> api_server;
530#if defined(YAZE_HTTP_API_ENABLED)
531 api_server = SetupApiServer(config);
535 "HTTP API requested but not enabled at build time "
536 "(set -DYAZE_ENABLE_HTTP_API=ON and rebuild).");
544 if (ctrl && ctrl->editor_manager()) {
547 if (!FLAGS_load_symbols->Get().empty()) {
548 LOG_INFO(
"Main",
"Loading symbols from %s...",
549 FLAGS_load_symbols->Get().c_str());
550 auto status = symbols.LoadSymbolFile(FLAGS_load_symbols->Get());
552 LOG_ERROR(
"Main",
"Failed to load symbols: %s",
553 status.ToString().c_str());
557 if (!FLAGS_load_asar_symbols->Get().empty()) {
558 LOG_INFO(
"Main",
"Loading Asar symbols from %s...",
559 FLAGS_load_asar_symbols->Get().c_str());
561 symbols.LoadAsarAsmDirectory(FLAGS_load_asar_symbols->Get());
563 LOG_ERROR(
"Main",
"Failed to load Asar symbols: %s",
564 status.ToString().c_str());
570 if (!FLAGS_export_symbols->Get().empty()) {
571 LOG_INFO(
"Main",
"Exporting symbols to %s...",
572 FLAGS_export_symbols->Get().c_str());
575 if (ctrl && ctrl->editor_manager()) {
580 auto& symbols = manager->
emulator().symbol_provider();
584 std::string format_str =
585 absl::AsciiStrToLower(FLAGS_symbol_format->Get());
586 if (format_str ==
"asar")
588 else if (format_str ==
"wla")
590 else if (format_str ==
"bsnes")
593 auto export_or = symbols.ExportSymbols(format);
594 if (export_or.ok()) {
595 std::ofstream out(FLAGS_export_symbols->Get());
598 LOG_INFO(
"Main",
"Symbols exported successfully");
600 LOG_ERROR(
"Main",
"Failed to open output file: %s",
601 FLAGS_export_symbols->Get().c_str());
604 LOG_ERROR(
"Main",
"Failed to export symbols: %s",
605 export_or.status().ToString().c_str());
614 LOG_INFO(
"Main",
"Running in HEADLESS mode (no GUI window)");
620 std::this_thread::sleep_for(std::chrono::milliseconds(16));
625 LOG_INFO(
"Main",
"Running in SERVICE mode (Hidden GUI window)");
634#if defined(YAZE_HTTP_API_ENABLED)
bool RunSymbolExportFastPath()
yaze::AppConfig BuildAppConfig(yaze::util::LogLevel log_level, std::string log_path)
int main(int argc, char **argv)
yaze::util::LogLevel ResolveLogConfig(bool debug_flag, bool log_to_console_flag)
void SetupCrashHandling()
Controller * GetController()
static Application & Instance()
void Initialize(const AppConfig &config)
editor::EditorManager * editor_manager()
The EditorManager controls the main editor window and manages the various editor classes.
auto emulator() -> emu::Emulator &
A class for emulating and debugging SNES games.
Provider for symbol (label) resolution in disassembly.
absl::Status LoadAsarAsmDirectory(const std::string &directory_path)
Load symbols from a directory of ASM files.
absl::StatusOr< std::string > ExportSymbols(SymbolFormat format) const
Export all symbols to a string in the specified format.
absl::Status LoadSymbolFile(const std::string &path, SymbolFormat format=SymbolFormat::kAuto)
Load symbols from a .sym file (various formats)
static void CleanupOldLogs(int keep_count=5)
Clean up old crash logs, keeping only the most recent N logs.
static void Initialize(const std::string &version)
Initialize the crash handler for the application.
void Parse(int argc, char **argv)
std::vector< IFlag * > AllFlags() const
static LogManager & instance()
void configure(LogLevel level, const std::string &file_path, const std::set< std::string > &categories)
Configures the logging system.
#define DEFINE_FLAG(type, name, default_val, help_text)
#define YAZE_VERSION_STRING
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
#define RETURN_IF_EXCEPTION(expression)
bool HandleHelpOrVersion(int argc, char **argv)
const char * LogLevelToString(yaze::util::LogLevel level)
std::set< std::string > ParseLogCategories(const std::string &raw)
yaze::util::LogLevel ParseLogLevelFlag(const std::string &raw_level, bool debug_flag)
std::vector< std::string > ParseCommaList(const std::string &raw)
yaze::editor::EditorManager * GetGlobalEditorManager()
yaze::emu::Emulator * GetGlobalEmulator()
SymbolFormat
Supported symbol file formats.
FlagRegistry * global_flag_registry()
LogLevel
Defines the severity levels for log messages. This allows for filtering messages based on their impor...
AssetLoadMode AssetLoadModeFromString(absl::string_view value)
StartupVisibility StartupVisibilityFromString(absl::string_view value)
Configuration options for the application startup.
AssetLoadMode asset_load_mode
std::string startup_editor
std::string log_categories
StartupVisibility welcome_mode
std::vector< std::string > open_panels
StartupVisibility sidebar_mode
StartupVisibility dashboard_mode
Public YAZE API umbrella header.