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.");
79 "Enable guarded editor commands on the loopback HTTP API.");
80DEFINE_FLAG(
int, api_port, 8080,
"Port for the AI Agent API server.");
83 "Run in headless mode without a GUI window.");
85 "Run in service mode (GUI backend initialized but window hidden).");
88 "Run in server mode (implies --enable_api, --enable_test_harness). "
89 "Defaults to --headless unless --service or --no-headless is specified.");
94 "Start gRPC test harness server for automated GUI testing.");
97 "Port for Unified gRPC server (default: 50052).");
99 "Emulator backend for gRPC service: 'internal' or 'mesen'.");
104 "Export symbols to file (requires --rom_file).");
106 "Format for symbol export: mesen, wla, asar, bsnes.");
108 "Load symbol file (.mlb, .sym, .asm) on startup.");
110 "Load Asar symbols from directory on startup.");
112 "Export symbols without initializing UI. Requires --load_symbols "
113 "or --load_asar_symbols.");
132 if (ctrl && ctrl->editor_manager()) {
156 const std::string lower = absl::AsciiStrToLower(raw_level);
157 if (lower ==
"debug") {
160 if (lower ==
"warn" || lower ==
"warning") {
163 if (lower ==
"error") {
166 if (lower ==
"fatal") {
173 std::set<std::string> categories;
174 for (absl::string_view token :
175 absl::StrSplit(raw,
',', absl::SkipWhitespace())) {
176 if (!token.empty()) {
177 categories.insert(std::string(absl::StripAsciiWhitespace(token)));
200 std::vector<std::string> tokens;
201 for (absl::string_view token :
202 absl::StrSplit(raw,
',', absl::SkipWhitespace())) {
203 if (!token.empty()) {
204 tokens.emplace_back(absl::StripAsciiWhitespace(token));
213 for (
int i = 1; i < argc; ++i) {
214 const std::string arg = argv[i];
215 if (arg ==
"--version") {
219 if (arg ==
"--help" || arg ==
"-h") {
221 <<
"Usage: " << argv[0] <<
" [flags]\n\nFlags:\n";
223 std::sort(flags.begin(), flags.end(),
225 return a->name() < b->name();
227 for (
const auto* flag : flags) {
228 std::cout <<
" " << flag->name() <<
"\n " << flag->help() <<
"\n";
245#ifndef __EMSCRIPTEN__
252 bool log_to_console_flag) {
255 std::set<std::string> log_categories =
258 std::string log_path = FLAGS_log_file->Get();
259 if (log_path.empty()) {
262 log_path = (*logs_dir /
"yaze.log").
string();
269 if (debug_flag || log_to_console_flag) {
273 LOG_INFO(
"Main",
"🚀 YAZE started in debug mode");
276 "Logging configured (level=%s, file=%s, console=%s, categories=%zu)",
278 log_path.empty() ?
"<stderr>" : log_path.c_str(),
279 (debug_flag || log_to_console_flag) ?
"on" :
"off",
280 log_categories.size());
285 std::string log_path) {
288 bool server_mode = FLAGS_server->Get();
289 bool service_mode = FLAGS_service->Get();
291 config.
headless = FLAGS_headless->Get() || (server_mode && !service_mode);
294 config.
enable_api = FLAGS_enable_api->Get() || server_mode || service_mode ||
299 FLAGS_enable_test_harness->Get() || server_mode || service_mode;
301 config.
backend = FLAGS_backend->Get();
304 config.
rom_file = FLAGS_rom_file->Get();
311 config.
api_port = FLAGS_api_port->Get();
327 if (!FLAGS_open_panels->Get().empty()) {
334 if (!FLAGS_export_symbols->Get().empty() &&
335 FLAGS_export_symbols_fast->Get()) {
339 if (!FLAGS_load_symbols->Get().empty()) {
340 LOG_INFO(
"Main",
"Loading symbols from %s...",
341 FLAGS_load_symbols->Get().c_str());
344 LOG_ERROR(
"Main",
"Failed to load symbols: %s",
345 status.ToString().c_str());
351 if (!FLAGS_load_asar_symbols->Get().empty()) {
352 LOG_INFO(
"Main",
"Loading Asar symbols from %s...",
353 FLAGS_load_asar_symbols->Get().c_str());
357 LOG_ERROR(
"Main",
"Failed to load Asar symbols: %s",
358 status.ToString().c_str());
367 "No symbols loaded. Use --load_symbols or --load_asar_symbols.");
371 LOG_INFO(
"Main",
"Exporting symbols to %s...",
372 FLAGS_export_symbols->Get().c_str());
375 std::string format_str = absl::AsciiStrToLower(FLAGS_symbol_format->Get());
376 if (format_str ==
"asar")
378 else if (format_str ==
"wla")
380 else if (format_str ==
"bsnes")
384 if (export_or.ok()) {
385 std::ofstream out(FLAGS_export_symbols->Get());
388 LOG_INFO(
"Main",
"Symbols exported successfully (fast path)");
391 LOG_ERROR(
"Main",
"Failed to open output file: %s",
392 FLAGS_export_symbols->Get().c_str());
395 LOG_ERROR(
"Main",
"Failed to export symbols: %s",
396 export_or.status().ToString().c_str());
404int main(
int argc,
char** argv) {
405 absl::InitializeSymbolizer(argv[0]);
417 const bool debug_flag = FLAGS_debug->Get();
418 const bool log_to_console_flag = FLAGS_log_to_console->Get();
420 std::string log_path = FLAGS_log_file->Get();
421 if (log_path.empty()) {
424 log_path = (*logs_dir /
"yaze.log").
string();
435#if !defined(__EMSCRIPTEN__)
440 if (!FLAGS_export_symbols->Get().empty() &&
441 FLAGS_export_symbols_fast->Get()) {
447 if (!config.headless) {
448 return yaze_run_cocoa_app_delegate(config);
452#if defined(_WIN32) && !defined(__EMSCRIPTEN__)
457 yaze::app::wasm::InitializeWasmPlatform();
461 static bool s_wasm_initialized =
false;
464 auto WasmMainLoop = []() {
466 if (!s_wasm_initialized) {
467 if (yaze::app::wasm::IsFileSystemReady()) {
468 LOG_INFO(
"Main",
"Filesystem ready, initializing application...");
470 s_wasm_initialized =
true;
483 emscripten_set_main_loop(WasmMainLoop, 0, 1);
488#if defined(YAZE_HTTP_API_ENABLED)
489 std::unique_ptr<yaze::cli::api::HttpServer> api_server;
491#if !defined(YAZE_HTTP_API_ENABLED)
492 if (config.enable_api) {
494 "HTTP API requested but not enabled at build time "
495 "(set -DYAZE_ENABLE_HTTP_API=ON and rebuild).");
501#if defined(YAZE_HTTP_API_ENABLED)
502 api_server = yaze::app::SetupEditorHttpServer(config);
507 if (ctrl && ctrl->editor_manager()) {
510 if (!FLAGS_load_symbols->Get().empty()) {
511 LOG_INFO(
"Main",
"Loading symbols from %s...",
512 FLAGS_load_symbols->Get().c_str());
513 auto status = symbols.LoadSymbolFile(FLAGS_load_symbols->Get());
515 LOG_ERROR(
"Main",
"Failed to load symbols: %s",
516 status.ToString().c_str());
520 if (!FLAGS_load_asar_symbols->Get().empty()) {
521 LOG_INFO(
"Main",
"Loading Asar symbols from %s...",
522 FLAGS_load_asar_symbols->Get().c_str());
524 symbols.LoadAsarAsmDirectory(FLAGS_load_asar_symbols->Get());
526 LOG_ERROR(
"Main",
"Failed to load Asar symbols: %s",
527 status.ToString().c_str());
533 if (!FLAGS_export_symbols->Get().empty()) {
534 LOG_INFO(
"Main",
"Exporting symbols to %s...",
535 FLAGS_export_symbols->Get().c_str());
538 if (ctrl && ctrl->editor_manager()) {
543 auto& symbols = manager->
emulator().symbol_provider();
547 std::string format_str =
548 absl::AsciiStrToLower(FLAGS_symbol_format->Get());
549 if (format_str ==
"asar")
551 else if (format_str ==
"wla")
553 else if (format_str ==
"bsnes")
556 auto export_or = symbols.ExportSymbols(format);
557 if (export_or.ok()) {
558 std::ofstream out(FLAGS_export_symbols->Get());
561 LOG_INFO(
"Main",
"Symbols exported successfully");
563 LOG_ERROR(
"Main",
"Failed to open output file: %s",
564 FLAGS_export_symbols->Get().c_str());
567 LOG_ERROR(
"Main",
"Failed to export symbols: %s",
568 export_or.status().ToString().c_str());
572#if defined(YAZE_HTTP_API_ENABLED)
580 if (config.headless) {
581 LOG_INFO(
"Main",
"Running in HEADLESS mode (no GUI window)");
587 std::this_thread::sleep_for(std::chrono::milliseconds(16));
591 if (config.service_mode) {
592 LOG_INFO(
"Main",
"Running in SERVICE mode (Hidden GUI window)");
599#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.