yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
main.cc
Go to the documentation of this file.
1#if __APPLE__
3#endif
4
5#ifdef __EMSCRIPTEN__
6#include <emscripten.h>
9#endif
10
11#define IMGUI_DEFINE_MATH_OPERATORS
12#include <set>
13
14#include "absl/debugging/symbolize.h"
15#include "absl/strings/ascii.h"
16#include "absl/strings/str_split.h"
17#include "absl/strings/strip.h"
18#include "app/application.h"
19#include "app/startup_flags.h"
20#include "app/controller.h"
22#include "core/features.h"
23#include "util/crash_handler.h"
24#include "util/flag.h"
25#include "util/log.h"
26#include "util/platform_paths.h"
27#include "yaze.h"
28
29// ============================================================================
30// Global Accessors for WASM Integration
31DEFINE_FLAG(std::string, log_file, "", "Output log file path for debugging.");
32DEFINE_FLAG(std::string, rom_file, "", "ROM file to load on startup.");
33DEFINE_FLAG(bool, debug, false, "Enable debug logging and verbose output.");
34DEFINE_FLAG(std::string, log_level, "info",
35 "Minimum log level: debug, info, warn, error, or fatal.");
36DEFINE_FLAG(bool, log_to_console, false,
37 "Mirror logs to stderr even when writing to a file.");
39 std::string, log_categories, "",
40 "Comma-separated list of log categories to enable or disable. "
41 "Prefix with '-' to disable a category. "
42 "Example: \"Room,DungeonEditor\" (allowlist) or \"-Input,-Graphics\" "
43 "(blocklist).");
44
45// Navigation flags
46DEFINE_FLAG(std::string, editor, "",
47 "The editor to open on startup (e.g., Dungeon, Overworld, Assembly).");
48
49DEFINE_FLAG(std::string, open_panels, "",
50 "Comma-separated list of panel IDs to open (e.g. 'dungeon.room_list,emulator.cpu_debugger')");
51
52// UI visibility flags
53DEFINE_FLAG(std::string, startup_welcome, "auto",
54 "Welcome screen behavior at startup: auto, show, or hide.");
55DEFINE_FLAG(std::string, startup_dashboard, "auto",
56 "Dashboard panel behavior at startup: auto, show, or hide.");
57DEFINE_FLAG(std::string, startup_sidebar, "auto",
58 "Panel sidebar visibility at startup: auto, show, or hide.");
59
60DEFINE_FLAG(int, room, -1, "Open Dungeon Editor at specific room ID (0-295).");
61DEFINE_FLAG(int, map, -1, "Open Overworld Editor at specific map ID (0-159).");
62
63// AI Agent API flags
64DEFINE_FLAG(bool, enable_api, false, "Enable the AI Agent API server.");
65DEFINE_FLAG(int, api_port, 8080, "Port for the AI Agent API server.");
66
67#ifdef YAZE_WITH_GRPC
68// gRPC test harness flags
69DEFINE_FLAG(bool, enable_test_harness, false,
70 "Start gRPC test harness server for automated GUI testing.");
71DEFINE_FLAG(int, test_harness_port, 50051,
72 "Port for gRPC test harness server (default: 50051).");
73#endif
74
75// ============================================================================
76// Global Accessors for WASM Integration
77// These are used by yaze_debug_inspector.cc and wasm_terminal_bridge.cc
78// ============================================================================
79namespace yaze {
80namespace emu {
81class Emulator;
82}
83namespace editor {
84class EditorManager;
85}
86}
87
88namespace yaze::app {
89
92 if (ctrl && ctrl->editor_manager()) {
93 return &ctrl->editor_manager()->emulator();
94 }
95 return nullptr;
96}
97
100 if (ctrl) {
101 return ctrl->editor_manager();
102 }
103 return nullptr;
104}
105
106} // namespace yaze::app
107
108namespace {
109
110yaze::util::LogLevel ParseLogLevelFlag(const std::string& raw_level,
111 bool debug_flag) {
112 if (debug_flag) {
114 }
115
116 const std::string lower = absl::AsciiStrToLower(raw_level);
117 if (lower == "debug") {
119 }
120 if (lower == "warn" || lower == "warning") {
122 }
123 if (lower == "error") {
125 }
126 if (lower == "fatal") {
128 }
130}
131
132std::set<std::string> ParseLogCategories(const std::string& raw) {
133 std::set<std::string> categories;
134 for (absl::string_view token :
135 absl::StrSplit(raw, ',', absl::SkipWhitespace())) {
136 if (!token.empty()) {
137 categories.insert(std::string(absl::StripAsciiWhitespace(token)));
138 }
139 }
140 return categories;
141}
142
144 switch (level) {
146 return "debug";
148 return "info";
150 return "warn";
152 return "error";
154 return "fatal";
155 }
156 return "info";
157}
158
159std::vector<std::string> ParseCommaList(const std::string& raw) {
160 std::vector<std::string> tokens;
161 for (absl::string_view token :
162 absl::StrSplit(raw, ',', absl::SkipWhitespace())) {
163 if (!token.empty()) {
164 tokens.emplace_back(absl::StripAsciiWhitespace(token));
165 }
166 }
167 return tokens;
168}
169
170} // namespace
171
175
176int main(int argc, char** argv) {
177 absl::InitializeSymbolizer(argv[0]);
178
179#ifndef __EMSCRIPTEN__
182#endif
183
185 RETURN_IF_EXCEPTION(parser.Parse(argc, argv));
186
187 // Set up logging
188 const bool debug_flag = FLAGS_debug->Get();
189 const bool log_to_console_flag = FLAGS_log_to_console->Get();
190 yaze::util::LogLevel log_level =
191 ParseLogLevelFlag(FLAGS_log_level->Get(), debug_flag);
192 std::set<std::string> log_categories =
193 ParseLogCategories(FLAGS_log_categories->Get());
194
195 std::string log_path = FLAGS_log_file->Get();
196 if (log_path.empty()) {
198 if (logs_dir.ok()) {
199 log_path = (*logs_dir / "yaze.log").string();
200 }
201 }
202
203 yaze::util::LogManager::instance().configure(log_level, log_path,
204 log_categories);
205
206 if (debug_flag || log_to_console_flag) {
208 }
209 if (debug_flag) {
210 LOG_INFO("Main", "🚀 YAZE started in debug mode");
211 }
212 LOG_INFO("Main",
213 "Logging configured (level=%s, file=%s, console=%s, categories=%zu)",
214 LogLevelToString(log_level),
215 log_path.empty() ? "<stderr>" : log_path.c_str(),
216 (debug_flag || log_to_console_flag) ? "on" : "off",
217 log_categories.size());
218
219 // Build AppConfig from flags
220 yaze::AppConfig config;
221 config.rom_file = FLAGS_rom_file->Get();
222 config.log_file = log_path;
223 config.debug = (log_level == yaze::util::LogLevel::YAZE_DEBUG);
224 config.log_categories = FLAGS_log_categories->Get();
225 config.startup_editor = FLAGS_editor->Get();
226 config.jump_to_room = FLAGS_room->Get();
227 config.jump_to_map = FLAGS_map->Get();
228 config.enable_api = FLAGS_enable_api->Get();
229 config.api_port = FLAGS_api_port->Get();
230
231 config.welcome_mode =
232 yaze::StartupVisibilityFromString(FLAGS_startup_welcome->Get());
233 config.dashboard_mode =
234 yaze::StartupVisibilityFromString(FLAGS_startup_dashboard->Get());
235 config.sidebar_mode =
236 yaze::StartupVisibilityFromString(FLAGS_startup_sidebar->Get());
237
238 if (!FLAGS_open_panels->Get().empty()) {
239 config.open_panels = ParseCommaList(FLAGS_open_panels->Get());
240 }
241
242#ifdef YAZE_WITH_GRPC
243 config.enable_test_harness = FLAGS_enable_test_harness->Get();
244 config.test_harness_port = FLAGS_test_harness_port->Get();
245#endif
246
247#ifdef __APPLE__
248 return yaze_run_cocoa_app_delegate(config);
249#elif defined(_WIN32)
250 SDL_SetMainReady();
251#endif
252
253#ifdef __EMSCRIPTEN__
254 yaze::app::wasm::InitializeWasmPlatform();
255
256 // Store config for deferred initialization
257 static yaze::AppConfig s_wasm_config = config;
258 static bool s_wasm_initialized = false;
259
260 // Main loop that handles deferred initialization for filesystem readiness
261 auto WasmMainLoop = []() {
262 // Wait for filesystem to be ready before initializing application
263 if (!s_wasm_initialized) {
264 if (yaze::app::wasm::IsFileSystemReady()) {
265 LOG_INFO("Main", "Filesystem ready, initializing application...");
267 s_wasm_initialized = true;
268 } else {
269 // Still waiting for filesystem - do nothing this frame
270 return;
271 }
272 }
273
274 // Normal tick once initialized
275 TickFrame();
276 };
277
278 // Use 0 for frame rate to enable requestAnimationFrame (better performance)
279 // The third parameter (1) simulates infinite loop
280 emscripten_set_main_loop(WasmMainLoop, 0, 1);
281#else
282 // Desktop Main Loop (Linux/Windows)
283
284 // API Server
285 std::unique_ptr<yaze::cli::api::HttpServer> api_server;
286 if (config.enable_api) {
287 api_server = std::make_unique<yaze::cli::api::HttpServer>();
288 auto status = api_server->Start(config.api_port);
289 if (!status.ok()) {
290 LOG_ERROR("Main", "Failed to start API server: %s", std::string(status.message()).c_str());
291 } else {
292 LOG_INFO("Main", "API Server started on port %d", config.api_port);
293 }
294 }
295
297
298 while (yaze::Application::Instance().GetController()->IsActive()) {
299 TickFrame();
300 }
301
303
304 if (api_server) {
305 api_server->Stop();
306 }
307
308#endif // __EMSCRIPTEN__
309
310 return EXIT_SUCCESS;
311}
Controller * GetController()
Definition application.h:72
static Application & Instance()
void Initialize(const AppConfig &config)
editor::EditorManager * editor_manager()
Definition controller.h:51
static Flags & get()
Definition features.h:92
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.
Definition emulator.h:39
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)
Definition flag.h:139
static LogManager & instance()
Definition log.cc:31
void configure(LogLevel level, const std::string &file_path, const std::set< std::string > &categories)
Configures the logging system.
Definition log.cc:45
static absl::StatusOr< std::filesystem::path > GetUserDocumentsSubdirectory(const std::string &subdir)
Get a subdirectory within the user documents folder.
#define DEFINE_FLAG(type, name, default_val, help_text)
Definition flag.h:126
#define YAZE_VERSION_STRING
Definition yaze.h:43
#define LOG_ERROR(category, format,...)
Definition log.h:109
#define LOG_INFO(category, format,...)
Definition log.h:105
#define RETURN_IF_EXCEPTION(expression)
Definition macro.h:104
void TickFrame()
Definition main.cc:172
int main(int argc, char **argv)
Definition main.cc:176
const char * LogLevelToString(yaze::util::LogLevel level)
Definition main.cc:143
std::set< std::string > ParseLogCategories(const std::string &raw)
Definition main.cc:132
yaze::util::LogLevel ParseLogLevelFlag(const std::string &raw_level, bool debug_flag)
Definition main.cc:110
std::vector< std::string > ParseCommaList(const std::string &raw)
Definition main.cc:159
yaze::editor::EditorManager * GetGlobalEditorManager()
Definition main.cc:98
yaze::emu::Emulator * GetGlobalEmulator()
Definition main.cc:90
FlagRegistry * global_flag_registry()
Definition flag.h:119
LogLevel
Defines the severity levels for log messages. This allows for filtering messages based on their impor...
Definition log.h:23
StartupVisibility StartupVisibilityFromString(absl::string_view value)
Configuration options for the application startup.
Definition application.h:23
std::string rom_file
Definition application.h:25
Yet Another Zelda3 Editor (YAZE) - Public C API.