47 LOG_INFO(
"App",
"Initializing Application instance...");
62 LOG_INFO(
"App",
"Found pending ROM load: %s", start_path.c_str());
63 }
else if (!start_path.empty()) {
64 LOG_INFO(
"App",
"Using configured startup ROM: %s", start_path.c_str());
66 LOG_INFO(
"App",
"No pending ROM, starting empty.");
69 LOG_INFO(
"App",
"WASM build - ROM loading handled via wasm_bootstrap queue.");
77 LOG_ERROR(
"App",
"Failed to initialize controller: %s",
78 std::string(status.message()).c_str());
84 LOG_INFO(
"App",
"Controller initialized successfully. Active: %s",
90 const std::string& preferred_path,
91 test::TestManager::FailureScreenshotCallback callback) {
92 controller->RequestScreenshot({.preferred_path = preferred_path,
93 .reveal_to_user = false,
94 .callback = std::move(callback)});
102 if (
controller_->editor_manager()->user_settings().prefs().test_mode) {
103 LOG_INFO(
"App",
"Test mode: hiding welcome and editor picker");
119 if (!start_path.empty() &&
controller_->editor_manager()) {
126 LOG_INFO(
"App",
"Initializing Unified gRPC Server...");
127 canvas_automation_service_ =
128 std::make_unique<CanvasAutomationServiceImpl>();
129 grpc_server_ = std::make_unique<YazeGRPCServer>();
132 auto rom_getter = [
this]() {
135 auto rom_loader = [
this](
const std::string& path) ->
bool {
138 auto status =
controller_->editor_manager()->OpenRomOrProject(
146 LOG_INFO(
"App",
"Using Mesen2 backend for emulator service");
148 std::make_unique<emu::mesen::MesenEmulatorAdapter>();
149 emulator_interface = emulator_backend_.get();
153 internal_emulator = &
controller_->editor_manager()->emulator();
156 "EditorManager not ready; internal emulator services may be "
161 std::make_unique<emu::InternalEmulatorAdapter>(internal_emulator);
164 adapter->SetRomLoader([
this](
const std::string& path) ->
bool {
167 auto status =
controller_->editor_manager()->OpenRomOrProject(
172 adapter->SetRomGetter(
173 [
this]() {
return controller_->GetCurrentRom(); });
175 emulator_backend_ = std::move(adapter);
176 emulator_interface = emulator_backend_.get();
180 auto status = grpc_server_->Initialize(
185 canvas_automation_service_.get());
190 grpc_server_->SetEmulatorScreenshotCapturer([] {
191 static std::atomic<int> next_capture{0};
192 const auto path = std::filesystem::temp_directory_path() /
193 absl::StrFormat(
"yaze_gamestate_%d_%d.png",
194 static_cast<int>(getpid()),
195 next_capture.fetch_add(1));
196 return test::CaptureScreenshotOnRenderThread(
201 status = grpc_server_->StartAsync();
203 LOG_ERROR(
"App",
"Failed to start gRPC server: %s",
204 std::string(status.message()).c_str());
206 LOG_INFO(
"App",
"Unified gRPC server started on port %d",
210 LOG_ERROR(
"App",
"Failed to initialize gRPC server: %s",
211 std::string(status.message()).c_str());
215 if (canvas_automation_service_) {
217 canvas_automation_service_.get());
225 yaze::app::wasm::SetRomLoadHandler(
231 const char* runtime_dir = std::getenv(
"XDG_RUNTIME_DIR");
232 const char* status_dir = (runtime_dir && *runtime_dir) ? runtime_dir :
"/tmp";
233 activity_file_ = std::make_unique<app::ActivityFile>(
234 absl::StrFormat(
"%s/yaze-%d.status", status_dir, pid));
235 UpdateActivityStatus();
236 LOG_INFO(
"App",
"Activity file created: %s",
237 activity_file_->GetPath().c_str());
241void Application::Tick() {
250 absl::Cleanup end_tick = [
this] {
255 auto now = std::chrono::steady_clock::now();
257 delta_time_ = 0.016f;
258 first_frame_ =
false;
260 auto elapsed = std::chrono::duration<float>(now - last_frame_time_);
261 delta_time_ = elapsed.count();
263 last_frame_time_ = now;
266 if (
auto* bus = editor::ContentRegistry::Context::event_bus()) {
267 bus->Publish(editor::FrameBeginEvent::Create(delta_time_));
271 auto& wasm_collab = app::platform::GetWasmCollaborationInstance();
272 wasm_collab.ProcessPendingChanges();
275 controller_->OnInput();
276 auto status = controller_->OnLoad();
278 LOG_ERROR(
"App",
"Controller Load Error: %s",
279 std::string(status.message()).c_str());
281 emscripten_cancel_main_loop();
286 if (!controller_->IsActive()) {
291 controller_->DoRender();
294 if (
auto* bus = editor::ContentRegistry::Context::event_bus()) {
295 bus->Publish(editor::FrameEndEvent::Create(delta_time_));
299void Application::LoadRom(
const std::string& path) {
300 LOG_INFO(
"App",
"Requesting ROM load: %s", path.c_str());
304 yaze::app::wasm::TriggerRomLoad(path);
306 "Forwarded to wasm_bootstrap queue (controller not ready): %s",
310 LOG_INFO(
"App",
"Queued ROM load (controller not ready): %s", path.c_str());
317 if (!controller_->IsActive()) {
318 status = controller_->OnEntry(path);
320 status = controller_->editor_manager()->OpenRomOrProject(path);
324 std::string error_msg =
325 absl::StrCat(
"Failed to load ROM: ", status.message());
326 LOG_ERROR(
"App",
"%s", error_msg.c_str());
331 var msg = UTF8ToString($0);
338 LOG_INFO(
"App",
"ROM loaded successfully: %s", path.c_str());
347#ifndef __EMSCRIPTEN__
349 UpdateActivityStatus();
354 { console.log(
"ROM loaded successfully: " + UTF8ToString($0)); },
369void Application::UpdateActivityStatus() {
374 status.
pid = getpid();
378 if (controller_ && controller_->editor_manager()) {
379 auto* rom = controller_->GetCurrentRom();
384 if (config_.enable_test_harness && config_.test_harness_port > 0) {
386 absl::StrFormat(
"localhost:%d", config_.test_harness_port);
390 activity_file_->Update(status);
398void Application::Shutdown() {
401 LOG_INFO(
"App",
"Syncing filesystem before shutdown...");
407 LOG_INFO(
"App",
"Shutting down Unified gRPC Server...");
408 grpc_server_->Shutdown();
409 grpc_server_.reset();
411 canvas_automation_service_.reset();
412 test::TestManager::Get().SetFailureScreenshotRequester({});
415#ifndef __EMSCRIPTEN__
417 if (activity_file_) {
418 LOG_INFO(
"App",
"Removing activity file: %s",
419 activity_file_->GetPath().c_str());
420 activity_file_.reset();
425 controller_->OnExit();