yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
application.cc
Go to the documentation of this file.
1#include "app/application.h"
2
3#include "absl/strings/str_cat.h"
4#include "util/log.h"
5
6#ifdef YAZE_WITH_GRPC
11#endif
12
13#ifdef __EMSCRIPTEN__
14#include <emscripten.h>
17#endif
18
19namespace yaze {
20
22 static Application instance;
23 return instance;
24}
25
27 config_ = config;
28 LOG_INFO("App", "Initializing Application instance...");
29
30 controller_ = std::make_unique<Controller>();
31
32 // Process pending ROM load if we have one (from flags/config - non-WASM only)
33 std::string start_path = config_.rom_file;
34
35#ifndef __EMSCRIPTEN__
36 if (!pending_rom_.empty()) {
37 // Pending ROM takes precedence over config (e.g. drag-drop before init)
38 start_path = pending_rom_;
39 pending_rom_.clear();
40 LOG_INFO("App", "Found pending ROM load: %s", start_path.c_str());
41 } else if (!start_path.empty()) {
42 LOG_INFO("App", "Using configured startup ROM: %s", start_path.c_str());
43 } else {
44 LOG_INFO("App", "No pending ROM, starting empty.");
45 }
46#else
47 LOG_INFO("App", "WASM build - ROM loading handled via wasm_bootstrap queue.");
48 // In WASM, start_path from config might be ignored if we rely on web uploads
49 // But we can still try to pass it if it's a server-hosted ROM
50#endif
51
52 // Always call OnEntry to initialize Window/Renderer, even with empty path
53 auto status = controller_->OnEntry(start_path);
54 if (!status.ok()) {
55 LOG_ERROR("App", "Failed to initialize controller: %s", std::string(status.message()).c_str());
56 } else {
57 LOG_INFO("App", "Controller initialized successfully. Active: %s", controller_->IsActive() ? "Yes" : "No");
58
59 if (controller_->editor_manager()) {
60 controller_->editor_manager()->ApplyStartupVisibility(config_);
61 }
62
63 // If we successfully loaded a ROM at startup, run startup actions
64 if (!start_path.empty() && controller_->editor_manager()) {
66 }
67
68#ifdef YAZE_WITH_GRPC
69 // Start AgentControlServer for MCP/CLI debugging (always enabled with gRPC)
70 if (controller_->editor_manager()) {
71 auto rom_getter = [this]() -> Rom* {
72 return controller_->GetCurrentRom();
73 };
74 auto rom_loader = [this](const std::string& path) -> bool {
75 if (!controller_ || !controller_->editor_manager()) return false;
76 auto status = controller_->editor_manager()->OpenRomOrProject(path);
77 return status.ok();
78 };
79 agent_control_server_ = std::make_unique<yaze::agent::AgentControlServer>(
80 &controller_->editor_manager()->emulator(), rom_getter, rom_loader);
81 agent_control_server_->Start();
82 LOG_INFO("App", "AgentControlServer started on port 50053");
83 }
84
85 // Initialize gRPC test harness server if enabled (separate from AgentControlServer)
87 LOG_INFO("App", "Initializing gRPC automation services...");
88 canvas_automation_service_ = std::make_unique<CanvasAutomationServiceImpl>();
89 grpc_server_ = std::make_unique<YazeGRPCServer>();
90
91 auto th_rom_getter = [this]() { return controller_->GetCurrentRom(); };
92 auto th_rom_loader = [this](const std::string& path) -> bool {
93 if (!controller_ || !controller_->editor_manager()) return false;
94 auto status = controller_->editor_manager()->OpenRomOrProject(path);
95 return status.ok();
96 };
97
98 if (controller_->editor_manager()) {
99 auto emulator_service =
100 std::make_unique<yaze::net::EmulatorServiceImpl>(
101 &controller_->editor_manager()->emulator(),
102 th_rom_getter, th_rom_loader);
103 auto add_status =
104 grpc_server_->AddService(std::move(emulator_service));
105 if (!add_status.ok()) {
106 LOG_ERROR("App", "Failed to attach emulator service: %s",
107 std::string(add_status.message()).c_str());
108 }
109 } else {
110 LOG_WARN("App", "EditorManager not ready; emulator gRPC disabled");
111 }
112
113 // Initialize server with all services
114 auto status = grpc_server_->Initialize(
117 th_rom_getter,
118 nullptr, // Version manager not ready
119 nullptr, // Approval manager not ready
120 canvas_automation_service_.get()
121 );
122
123 if (status.ok()) {
124 status = grpc_server_->StartAsync(); // Start in background thread
125 if (!status.ok()) {
126 LOG_ERROR("App", "Failed to start gRPC server: %s", std::string(status.message()).c_str());
127 } else {
128 LOG_INFO("App", "gRPC server started on port %d", config_.test_harness_port);
129 }
130 } else {
131 LOG_ERROR("App", "Failed to initialize gRPC server: %s", std::string(status.message()).c_str());
132 }
133
134 // Connect services to controller/editor manager
135 if (canvas_automation_service_) {
136 controller_->SetCanvasAutomationService(canvas_automation_service_.get());
137 }
138 }
139#endif
140 }
141
142#ifdef __EMSCRIPTEN__
143 // Register the ROM load handler now that controller is ready.
144 yaze::app::wasm::SetRomLoadHandler([](std::string path) {
146 });
147#endif
148}
149
151 if (!controller_) return;
152
153#ifdef __EMSCRIPTEN__
154 auto& wasm_collab = app::platform::GetWasmCollaborationInstance();
155 wasm_collab.ProcessPendingChanges();
156#endif
157
158 controller_->OnInput();
159 auto status = controller_->OnLoad();
160 if (!status.ok()) {
161 LOG_ERROR("App", "Controller Load Error: %s", std::string(status.message()).c_str());
162#ifdef __EMSCRIPTEN__
163 emscripten_cancel_main_loop();
164#endif
165 return;
166 }
167
168 if (!controller_->IsActive()) {
169 // Window closed
170 // LOG_INFO("App", "Controller became inactive");
171 }
172
173 controller_->DoRender();
174}
175
176void Application::LoadRom(const std::string& path) {
177 LOG_INFO("App", "Requesting ROM load: %s", path.c_str());
178
179 if (!controller_) {
180#ifdef __EMSCRIPTEN__
181 yaze::app::wasm::TriggerRomLoad(path);
182 LOG_INFO("App", "Forwarded to wasm_bootstrap queue (controller not ready): %s", path.c_str());
183#else
184 pending_rom_ = path;
185 LOG_INFO("App", "Queued ROM load (controller not ready): %s", path.c_str());
186#endif
187 return;
188 }
189
190 // Controller exists.
191 absl::Status status;
192 if (!controller_->IsActive()) {
193 status = controller_->OnEntry(path);
194 } else {
195 status = controller_->editor_manager()->OpenRomOrProject(path);
196 }
197
198 if (!status.ok()) {
199 std::string error_msg = absl::StrCat("Failed to load ROM: ", status.message());
200 LOG_ERROR("App", "%s", error_msg.c_str());
201
202#ifdef __EMSCRIPTEN__
203 EM_ASM({
204 var msg = UTF8ToString($0);
205 console.error(msg);
206 alert(msg);
207 }, error_msg.c_str());
208#endif
209 } else {
210 LOG_INFO("App", "ROM loaded successfully: %s", path.c_str());
211
212 // Run startup actions whenever a new ROM is loaded IF it matches our startup config
213 // (Optional: we might only want to run actions once at startup, but for CLI usage usually
214 // you load one ROM and want the actions applied to it).
215 // For now, we'll only run actions if this is the first load or if explicitly requested.
216 // Actually, simpler: just run them. The user can close cards if they want.
218
219#ifdef __EMSCRIPTEN__
220 EM_ASM({
221 console.log("ROM loaded successfully: " + UTF8ToString($0));
222 }, path.c_str());
223#endif
224 }
225}
226
228 if (!controller_ || !controller_->editor_manager()) return;
229
230 auto* manager = controller_->editor_manager();
231 manager->ProcessStartupActions(config_);
232}
233
234#ifdef __EMSCRIPTEN__
235extern "C" void SyncFilesystem();
236#endif
237
239#ifdef __EMSCRIPTEN__
240 // Sync IDBFS to persist any changes before shutdown
241 LOG_INFO("App", "Syncing filesystem before shutdown...");
242 SyncFilesystem();
243#endif
244
245#ifdef YAZE_WITH_GRPC
246 if (agent_control_server_) {
247 LOG_INFO("App", "Shutting down AgentControlServer...");
248 agent_control_server_->Stop();
249 agent_control_server_.reset();
250 }
251 if (grpc_server_) {
252 LOG_INFO("App", "Shutting down gRPC test harness server...");
253 grpc_server_->Shutdown();
254 grpc_server_.reset();
255 }
256 canvas_automation_service_.reset();
257#endif
258
259 if (controller_) {
260 controller_->OnExit();
261 controller_.reset();
262 }
263}
264
265} // namespace yaze
Main application singleton managing lifecycle and global state.
Definition application.h:53
std::string pending_rom_
Definition application.h:91
AppConfig config_
Definition application.h:86
static Application & Instance()
std::unique_ptr< Controller > controller_
Definition application.h:85
void LoadRom(const std::string &path)
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
static TestManager & Get()
#define LOG_ERROR(category, format,...)
Definition log.h:109
#define LOG_WARN(category, format,...)
Definition log.h:107
#define LOG_INFO(category, format,...)
Definition log.h:105
Configuration options for the application startup.
Definition application.h:24
std::string rom_file
Definition application.h:26
bool enable_test_harness
Definition application.h:45