7#include <emscripten/bind.h>
9#include "absl/strings/str_format.h"
22#include "nlohmann/json.hpp"
33editor::EditorManager* WasmControlApi::editor_manager_ =
nullptr;
34bool WasmControlApi::initialized_ =
false;
40EM_JS(
void, SetupYazeControlApi, (), {
41 if (typeof Module ===
'undefined')
return;
49 window.yaze.control = {
51 switchEditor: function(editorName) {
52 if (Module.controlSwitchEditor) {
53 try {
return JSON.parse(Module.controlSwitchEditor(editorName)); }
54 catch(e) {
return {error: e.message}; }
56 return {error:
"API not ready"};
59 getCurrentEditor: function() {
60 if (Module.controlGetCurrentEditor) {
61 try {
return JSON.parse(Module.controlGetCurrentEditor()); }
62 catch(e) {
return {error: e.message}; }
64 return {error:
"API not ready"};
67 getAvailableEditors: function() {
68 if (Module.controlGetAvailableEditors) {
69 try {
return JSON.parse(Module.controlGetAvailableEditors()); }
70 catch(e) {
return {error: e.message}; }
72 return {error:
"API not ready"};
76 openWindow: function(cardId) {
77 if (Module.controlOpenWindow) {
78 try {
return JSON.parse(Module.controlOpenWindow(cardId)); }
79 catch(e) {
return {error: e.message}; }
81 return {error:
"API not ready"};
83 openPanel: function(cardId) {
return this.openWindow(cardId); },
85 closeWindow: function(cardId) {
86 if (Module.controlCloseWindow) {
87 try {
return JSON.parse(Module.controlCloseWindow(cardId)); }
88 catch(e) {
return {error: e.message}; }
90 return {error:
"API not ready"};
92 closePanel: function(cardId) {
return this.closeWindow(cardId); },
94 toggleWindow: function(cardId) {
95 if (Module.controlToggleWindow) {
96 try {
return JSON.parse(Module.controlToggleWindow(cardId)); }
97 catch(e) {
return {error: e.message}; }
99 return {error:
"API not ready"};
101 togglePanel: function(cardId) {
return this.toggleWindow(cardId); },
103 getVisibleWindows: function() {
104 if (Module.controlGetVisibleWindows) {
105 try {
return JSON.parse(Module.controlGetVisibleWindows()); }
106 catch(e) {
return {error: e.message}; }
108 return {error:
"API not ready"};
110 getVisiblePanels: function() {
return this.getVisibleWindows(); },
112 getAvailableWindows: function() {
113 if (Module.controlGetAvailableWindows) {
114 try {
return JSON.parse(Module.controlGetAvailableWindows()); }
115 catch(e) {
return {error: e.message}; }
117 return {error:
"API not ready"};
119 getAvailablePanels: function() {
return this.getAvailableWindows(); },
121 getWindowsInCategory: function(category) {
122 if (Module.controlGetWindowsInCategory) {
123 try {
return JSON.parse(Module.controlGetWindowsInCategory(category)); }
124 catch(e) {
return {error: e.message}; }
126 return {error:
"API not ready"};
130 showAllWindows: function() {
131 if (Module.controlShowAllWindows) {
132 try {
return JSON.parse(Module.controlShowAllWindows()); }
133 catch(e) {
return {error: e.message}; }
135 return {error:
"API not ready"};
137 showAllPanels: function() {
return this.showAllWindows(); },
139 hideAllWindows: function() {
140 if (Module.controlHideAllWindows) {
141 try {
return JSON.parse(Module.controlHideAllWindows()); }
142 catch(e) {
return {error: e.message}; }
144 return {error:
"API not ready"};
146 hideAllPanels: function() {
return this.hideAllWindows(); },
148 showAllPanelsInCategory: function(category) {
149 if (Module.controlShowAllWindowsInCategory) {
150 try {
return JSON.parse(Module.controlShowAllWindowsInCategory(category)); }
151 catch(e) {
return {error: e.message}; }
153 return {error:
"API not ready"};
156 hideAllPanelsInCategory: function(category) {
157 if (Module.controlHideAllWindowsInCategory) {
158 try {
return JSON.parse(Module.controlHideAllWindowsInCategory(category)); }
159 catch(e) {
return {error: e.message}; }
161 return {error:
"API not ready"};
164 showOnlyPanel: function(cardId) {
165 if (Module.controlShowOnlyWindow) {
166 try {
return JSON.parse(Module.controlShowOnlyWindow(cardId)); }
167 catch(e) {
return {error: e.message}; }
169 return {error:
"API not ready"};
173 setPanelLayout: function(layoutName) {
174 if (Module.controlSetPanelLayout) {
175 try {
return JSON.parse(Module.controlSetPanelLayout(layoutName)); }
176 catch(e) {
return {error: e.message}; }
178 return {error:
"API not ready"};
181 getAvailableLayouts: function() {
182 if (Module.controlGetAvailableLayouts) {
183 try {
return JSON.parse(Module.controlGetAvailableLayouts()); }
184 catch(e) {
return {error: e.message}; }
186 return {error:
"API not ready"};
189 saveCurrentLayout: function(layoutName) {
190 if (Module.controlSaveCurrentLayout) {
191 try {
return JSON.parse(Module.controlSaveCurrentLayout(layoutName)); }
192 catch(e) {
return {error: e.message}; }
194 return {error:
"API not ready"};
198 triggerMenuAction: function(actionPath) {
199 if (Module.controlTriggerMenuAction) {
200 try {
return JSON.parse(Module.controlTriggerMenuAction(actionPath)); }
201 catch(e) {
return {error: e.message}; }
203 return {error:
"API not ready"};
206 getAvailableMenuActions: function() {
207 if (Module.controlGetAvailableMenuActions) {
208 try {
return JSON.parse(Module.controlGetAvailableMenuActions()); }
209 catch(e) {
return {error: e.message}; }
211 return {error:
"API not ready"};
214 toggleMenuBar: function() {
215 if (Module.controlToggleMenuBar) {
216 try {
return JSON.parse(Module.controlToggleMenuBar()); }
217 catch(e) {
return {error: e.message}; }
219 return {error:
"API not ready"};
223 getSessionInfo: function() {
224 if (Module.controlGetSessionInfo) {
225 try {
return JSON.parse(Module.controlGetSessionInfo()); }
226 catch(e) {
return {error: e.message}; }
228 return {error:
"API not ready"};
231 createSession: function() {
232 if (Module.controlCreateSession) {
233 try {
return JSON.parse(Module.controlCreateSession()); }
234 catch(e) {
return {error: e.message}; }
236 return {error:
"API not ready"};
239 switchSession: function(sessionIndex) {
240 if (Module.controlSwitchSession) {
241 try {
return JSON.parse(Module.controlSwitchSession(sessionIndex)); }
242 catch(e) {
return {error: e.message}; }
244 return {error:
"API not ready"};
249 if (Module.controlGetRomStatus) {
250 try {
return JSON.parse(Module.controlGetRomStatus()); }
251 catch(e) {
return {error: e.message}; }
253 return {error:
"API not ready"};
258 if (Module.controlReadRomBytes) {
259 try {
return JSON.parse(Module.controlReadRomBytes(address, count)); }
260 catch(e) {
return {error: e.message}; }
262 return {error:
"API not ready"};
265 writeRomBytes: function(address, bytes) {
266 if (Module.controlWriteRomBytes) {
267 try {
return JSON.parse(Module.controlWriteRomBytes(address, JSON.stringify(bytes))); }
268 catch(e) {
return {error: e.message}; }
270 return {error:
"API not ready"};
273 saveRom: function() {
274 if (Module.controlSaveRom) {
275 try {
return JSON.parse(Module.controlSaveRom()); }
276 catch(e) {
return {error: e.message}; }
278 return {error:
"API not ready"};
282 isReady: function() {
283 return Module.controlIsReady ? Module.controlIsReady() :
false;
287 getPlatformInfo: function() {
288 if (Module.controlGetPlatformInfo) {
289 try {
return JSON.parse(Module.controlGetPlatformInfo()); }
290 catch(e) {
return {error: e.message}; }
292 return {error:
"API not ready"};
295 waitUntilReady: function() {
296 return new Promise(function(resolve) {
297 var check = function() {
298 if (Module.controlIsReady && Module.controlIsReady()) {
301 setTimeout(check, 100);
310 window.yaze.editor = {
311 getSnapshot: function() {
312 if (Module.editorGetSnapshot) {
313 try {
return JSON.parse(Module.editorGetSnapshot()); }
314 catch(e) {
return {error: e.message}; }
316 return {error:
"API not ready"};
319 getCurrentRoom: function() {
320 if (Module.editorGetCurrentDungeonRoom) {
321 try {
return JSON.parse(Module.editorGetCurrentDungeonRoom()); }
322 catch(e) {
return {error: e.message}; }
324 return {error:
"API not ready"};
327 getCurrentMap: function() {
328 if (Module.editorGetCurrentOverworldMap) {
329 try {
return JSON.parse(Module.editorGetCurrentOverworldMap()); }
330 catch(e) {
return {error: e.message}; }
332 return {error:
"API not ready"};
335 getSelection: function() {
336 if (Module.editorGetSelection) {
337 try {
return JSON.parse(Module.editorGetSelection()); }
338 catch(e) {
return {error: e.message}; }
340 return {error:
"API not ready"};
347 getRoomTiles: function(roomId) {
348 if (Module.dataGetRoomTileData) {
349 try {
return JSON.parse(Module.dataGetRoomTileData(roomId)); }
350 catch(e) {
return {error: e.message}; }
352 return {error:
"API not ready"};
355 getRoomObjects: function(roomId) {
356 if (Module.dataGetRoomObjects) {
357 try {
return JSON.parse(Module.dataGetRoomObjects(roomId)); }
358 catch(e) {
return {error: e.message}; }
360 return {error:
"API not ready"};
363 getRoomProperties: function(roomId) {
364 if (Module.dataGetRoomProperties) {
365 try {
return JSON.parse(Module.dataGetRoomProperties(roomId)); }
366 catch(e) {
return {error: e.message}; }
368 return {error:
"API not ready"};
372 getMapTiles: function(mapId) {
373 if (Module.dataGetMapTileData) {
374 try {
return JSON.parse(Module.dataGetMapTileData(mapId)); }
375 catch(e) {
return {error: e.message}; }
377 return {error:
"API not ready"};
380 getMapEntities: function(mapId) {
381 if (Module.dataGetMapEntities) {
382 try {
return JSON.parse(Module.dataGetMapEntities(mapId)); }
383 catch(e) {
return {error: e.message}; }
385 return {error:
"API not ready"};
388 getMapProperties: function(mapId) {
389 if (Module.dataGetMapProperties) {
390 try {
return JSON.parse(Module.dataGetMapProperties(mapId)); }
391 catch(e) {
return {error: e.message}; }
393 return {error:
"API not ready"};
397 getPalette: function(groupName, paletteId) {
398 if (Module.dataGetPaletteData) {
399 try {
return JSON.parse(Module.dataGetPaletteData(groupName, paletteId)); }
400 catch(e) {
return {error: e.message}; }
402 return {error:
"API not ready"};
405 getPaletteGroups: function() {
406 if (Module.dataListPaletteGroups) {
407 try {
return JSON.parse(Module.dataListPaletteGroups()); }
408 catch(e) {
return {error: e.message}; }
410 return {error:
"API not ready"};
415 window.yaze.agent = {
417 sendMessage: function(message) {
418 if (Module.agentSendMessage) {
419 try {
return JSON.parse(Module.agentSendMessage(message)); }
420 catch(e) {
return {error: e.message}; }
422 return {error:
"API not ready"};
426 getChatHistory: function() {
427 if (Module.agentGetChatHistory) {
428 try {
return JSON.parse(Module.agentGetChatHistory()); }
429 catch(e) {
return {error: e.message}; }
431 return {error:
"API not ready"};
435 getConfig: function() {
436 if (Module.agentGetConfig) {
437 try {
return JSON.parse(Module.agentGetConfig()); }
438 catch(e) {
return {error: e.message}; }
440 return {error:
"API not ready"};
444 setConfig: function(config) {
445 if (Module.agentSetConfig) {
446 try {
return JSON.parse(Module.agentSetConfig(JSON.stringify(config))); }
447 catch(e) {
return {error: e.message}; }
449 return {error:
"API not ready"};
453 getProviders: function() {
454 if (Module.agentGetProviders) {
455 try {
return JSON.parse(Module.agentGetProviders()); }
456 catch(e) {
return {error: e.message}; }
458 return {error:
"API not ready"};
462 getProposals: function() {
463 if (Module.agentGetProposals) {
464 try {
return JSON.parse(Module.agentGetProposals()); }
465 catch(e) {
return {error: e.message}; }
467 return {error:
"API not ready"};
471 acceptProposal: function(proposalId) {
472 if (Module.agentAcceptProposal) {
473 try {
return JSON.parse(Module.agentAcceptProposal(proposalId)); }
474 catch(e) {
return {error: e.message}; }
476 return {error:
"API not ready"};
480 rejectProposal: function(proposalId) {
481 if (Module.agentRejectProposal) {
482 try {
return JSON.parse(Module.agentRejectProposal(proposalId)); }
483 catch(e) {
return {error: e.message}; }
485 return {error:
"API not ready"};
489 getProposalDetails: function(proposalId) {
490 if (Module.agentGetProposalDetails) {
491 try {
return JSON.parse(Module.agentGetProposalDetails(proposalId)); }
492 catch(e) {
return {error: e.message}; }
494 return {error:
"API not ready"};
498 openSidebar: function() {
499 if (Module.agentOpenSidebar) {
500 try {
return JSON.parse(Module.agentOpenSidebar()); }
501 catch(e) {
return {error: e.message}; }
503 return {error:
"API not ready"};
506 closeSidebar: function() {
507 if (Module.agentCloseSidebar) {
508 try {
return JSON.parse(Module.agentCloseSidebar()); }
509 catch(e) {
return {error: e.message}; }
511 return {error:
"API not ready"};
515 isReady: function() {
516 return Module.agentIsReady ? Module.agentIsReady() :
false;
520 console.log(
"[yaze] window.yaze.control API initialized");
521 console.log(
"[yaze] window.yaze.editor API initialized");
522 console.log(
"[yaze] window.yaze.data API initialized");
523 console.log(
"[yaze] window.yaze.agent API initialized");
530void WasmControlApi::Initialize(editor::EditorManager* editor_manager) {
531 editor_manager_ = editor_manager;
532 initialized_ = (editor_manager_ !=
nullptr);
535 SetupJavaScriptBindings();
536 LOG_INFO(
"WasmControlApi",
"Control API initialized");
540bool WasmControlApi::IsReady() {
541 return initialized_ && editor_manager_ !=
nullptr;
544std::string WasmControlApi::ToggleMenuBar() {
545 nlohmann::json result;
547 result[
"success"] =
false;
548 result[
"error"] =
"Control API not initialized";
549 return result.dump();
552 auto* ui = editor_manager_->ui_coordinator();
553 ui->SetMenuBarVisible(!ui->IsMenuBarVisible());
555 result[
"success"] =
true;
556 result[
"visible"] = ui->IsMenuBarVisible();
558 return result.dump();
561void WasmControlApi::SetupJavaScriptBindings() {
562 SetupYazeControlApi();
569editor::WorkspaceWindowManager* WasmControlApi::GetWindowManager() {
570 if (!IsReady() || !editor_manager_) {
573 return &editor_manager_->window_manager();
576std::string WasmControlApi::EditorTypeToString(
int type) {
583int WasmControlApi::StringToEditorType(
const std::string& name) {
586 return static_cast<int>(i);
596std::string WasmControlApi::SwitchEditor(
const std::string& editor_name) {
597 nlohmann::json result;
600 result[
"success"] =
false;
601 result[
"error"] =
"Control API not initialized";
602 return result.dump();
605 int editor_type = StringToEditorType(editor_name);
606 if (editor_type == 0 && editor_name !=
"Unknown") {
607 result[
"success"] =
false;
608 result[
"error"] =
"Unknown editor: " + editor_name;
609 return result.dump();
614 result[
"success"] =
true;
615 result[
"editor"] = editor_name;
616 return result.dump();
619std::string WasmControlApi::GetCurrentEditor() {
620 nlohmann::json result;
623 result[
"error"] =
"Control API not initialized";
624 return result.dump();
627 auto* current = editor_manager_->GetCurrentEditor();
629 result[
"name"] = EditorTypeToString(
static_cast<int>(current->type()));
630 result[
"type"] =
static_cast<int>(current->type());
631 result[
"active"] = *current->active();
633 result[
"name"] =
"None";
635 result[
"active"] =
false;
638 return result.dump();
641std::string WasmControlApi::GetAvailableEditors() {
642 nlohmann::json result = nlohmann::json::array();
645 nlohmann::json editor_info;
647 editor_info[
"type"] =
static_cast<int>(i);
648 result.push_back(editor_info);
651 return result.dump();
658std::string WasmControlApi::OpenWindow(
const std::string& card_id) {
659 nlohmann::json result;
662 result[
"success"] =
false;
663 result[
"error"] =
"Control API not initialized";
664 return result.dump();
667 auto* registry = GetWindowManager();
670 constexpr size_t session_id = 0;
671 bool found = registry->OpenWindow(session_id, card_id);
673 result[
"success"] = found;
674 result[
"card_id"] = card_id;
675 result[
"visible"] =
true;
677 result[
"error"] =
"Window not found";
680 result[
"success"] =
false;
681 result[
"error"] =
"Window manager not available";
684 LOG_INFO(
"WasmControlApi",
"OpenWindow: %s", card_id.c_str());
685 return result.dump();
688std::string WasmControlApi::OpenPanel(
const std::string& card_id) {
689 return OpenWindow(card_id);
692std::string WasmControlApi::CloseWindow(
const std::string& card_id) {
693 nlohmann::json result;
696 result[
"success"] =
false;
697 result[
"error"] =
"Control API not initialized";
698 return result.dump();
701 auto* registry = GetWindowManager();
703 constexpr size_t session_id = 0;
704 bool found = registry->CloseWindow(session_id, card_id);
706 result[
"success"] = found;
707 result[
"card_id"] = card_id;
708 result[
"visible"] =
false;
710 result[
"error"] =
"Window not found";
713 result[
"success"] =
false;
714 result[
"error"] =
"Window manager not available";
717 LOG_INFO(
"WasmControlApi",
"CloseWindow: %s", card_id.c_str());
718 return result.dump();
721std::string WasmControlApi::ClosePanel(
const std::string& card_id) {
722 return CloseWindow(card_id);
725std::string WasmControlApi::ToggleWindow(
const std::string& card_id) {
726 nlohmann::json result;
729 result[
"success"] =
false;
730 result[
"error"] =
"Control API not initialized";
731 return result.dump();
734 auto* registry = GetWindowManager();
736 constexpr size_t session_id = 0;
737 bool found = registry->ToggleWindow(session_id, card_id);
739 result[
"success"] = found;
740 result[
"card_id"] = card_id;
742 result[
"error"] =
"Window not found";
744 result[
"visible"] = registry->IsWindowOpen(session_id, card_id);
747 result[
"success"] =
false;
748 result[
"error"] =
"Window manager not available";
751 LOG_INFO(
"WasmControlApi",
"ToggleWindow: %s", card_id.c_str());
752 return result.dump();
755std::string WasmControlApi::TogglePanel(
const std::string& card_id) {
756 return ToggleWindow(card_id);
759std::string WasmControlApi::GetVisibleWindows() {
760 nlohmann::json result = nlohmann::json::array();
763 return result.dump();
766 auto* registry = GetWindowManager();
768 return result.dump();
772 constexpr size_t session_id = 0;
773 auto card_ids = registry->GetWindowsInSession(session_id);
774 for (
const auto& card_id : card_ids) {
776 std::string base_id = card_id;
777 if (base_id.size() > 3 && base_id[0] ==
's' && base_id[2] ==
'.') {
778 base_id = base_id.substr(3);
780 if (registry->IsWindowOpen(session_id, base_id)) {
781 result.push_back(base_id);
785 return result.dump();
788std::string WasmControlApi::GetVisiblePanels() {
789 return GetVisibleWindows();
792std::string WasmControlApi::GetAvailableWindows() {
793 nlohmann::json result = nlohmann::json::array();
796 return result.dump();
799 auto* registry = GetWindowManager();
801 return result.dump();
805 constexpr size_t session_id = 0;
806 auto categories = registry->GetAllWindowCategories(session_id);
808 for (
const auto& category : categories) {
809 auto panels = registry->GetWindowsInCategory(session_id, category);
810 for (
const auto& panel : panels) {
811 nlohmann::json card_json;
812 card_json[
"id"] = panel.card_id;
813 card_json[
"display_name"] = panel.display_name;
814 card_json[
"window_title"] = panel.window_title;
815 card_json[
"icon"] = panel.icon;
816 card_json[
"category"] = panel.category;
817 card_json[
"priority"] = panel.priority;
818 card_json[
"visible"] = registry->IsWindowOpen(session_id, panel.card_id);
819 card_json[
"shortcut_hint"] = panel.shortcut_hint;
820 if (panel.enabled_condition) {
821 card_json[
"enabled"] = panel.enabled_condition();
823 card_json[
"enabled"] =
true;
825 result.push_back(card_json);
829 return result.dump();
832std::string WasmControlApi::GetAvailablePanels() {
833 return GetAvailableWindows();
836std::string WasmControlApi::GetWindowsInCategory(
const std::string& category) {
837 nlohmann::json result = nlohmann::json::array();
840 return result.dump();
843 auto* registry = GetWindowManager();
845 return result.dump();
849 constexpr size_t session_id = 0;
850 auto panels = registry->GetWindowsInCategory(session_id, category);
852 for (
const auto& panel : panels) {
853 nlohmann::json card_json;
854 card_json[
"id"] = panel.card_id;
855 card_json[
"display_name"] = panel.display_name;
856 card_json[
"window_title"] = panel.window_title;
857 card_json[
"icon"] = panel.icon;
858 card_json[
"category"] = panel.category;
859 card_json[
"priority"] = panel.priority;
860 card_json[
"visible"] = registry->IsWindowOpen(session_id, panel.card_id);
861 result.push_back(card_json);
864 return result.dump();
867std::string WasmControlApi::GetPanelsInCategory(
const std::string& category) {
868 return GetWindowsInCategory(category);
871std::string WasmControlApi::ShowAllWindows() {
872 nlohmann::json result;
875 result[
"success"] =
false;
876 result[
"error"] =
"Control API not initialized";
877 return result.dump();
880 auto* registry = GetWindowManager();
882 constexpr size_t session_id = 0;
883 registry->ShowAllWindowsInSession(session_id);
884 result[
"success"] =
true;
886 result[
"success"] =
false;
887 result[
"error"] =
"Window manager not available";
890 return result.dump();
893std::string WasmControlApi::ShowAllPanels() {
894 return ShowAllWindows();
897std::string WasmControlApi::HideAllWindows() {
898 nlohmann::json result;
901 result[
"success"] =
false;
902 result[
"error"] =
"Control API not initialized";
903 return result.dump();
906 auto* registry = GetWindowManager();
908 constexpr size_t session_id = 0;
909 registry->HideAllWindowsInSession(session_id);
910 result[
"success"] =
true;
912 result[
"success"] =
false;
913 result[
"error"] =
"Window manager not available";
916 return result.dump();
919std::string WasmControlApi::HideAllPanels() {
920 return HideAllWindows();
923std::string WasmControlApi::ShowAllWindowsInCategory(
const std::string& category) {
924 nlohmann::json result;
927 result[
"success"] =
false;
928 result[
"error"] =
"Control API not initialized";
929 return result.dump();
932 auto* registry = GetWindowManager();
934 constexpr size_t session_id = 0;
935 registry->ShowAllWindowsInCategory(session_id, category);
936 result[
"success"] =
true;
939 result[
"success"] =
false;
940 result[
"error"] =
"Panel registry not available";
943 return result.dump();
946std::string WasmControlApi::HideAllWindowsInCategory(
const std::string& category) {
947 nlohmann::json result;
950 result[
"success"] =
false;
951 result[
"error"] =
"Control API not initialized";
952 return result.dump();
955 auto* registry = GetWindowManager();
957 constexpr size_t session_id = 0;
958 registry->HideAllWindowsInCategory(session_id, category);
959 result[
"success"] =
true;
962 result[
"success"] =
false;
963 result[
"error"] =
"Panel registry not available";
966 return result.dump();
969std::string WasmControlApi::ShowOnlyWindow(
const std::string& card_id) {
970 nlohmann::json result;
973 result[
"success"] =
false;
974 result[
"error"] =
"Control API not initialized";
975 return result.dump();
978 auto* registry = GetWindowManager();
980 constexpr size_t session_id = 0;
981 registry->ShowOnlyWindow(session_id, card_id);
982 result[
"success"] =
true;
983 result[
"card_id"] = card_id;
985 result[
"success"] =
false;
986 result[
"error"] =
"Panel registry not available";
989 return result.dump();
996std::string WasmControlApi::SetPanelLayout(
const std::string& layout_name) {
997 nlohmann::json result;
1000 result[
"success"] =
false;
1001 result[
"error"] =
"Control API not initialized";
1002 return result.dump();
1005 auto* registry = GetWindowManager();
1007 result[
"success"] =
false;
1008 result[
"error"] =
"Panel registry not available";
1009 return result.dump();
1012 size_t session_id = registry->GetActiveSessionId();
1015 if (layout_name ==
"overworld_default") {
1016 registry->HideAllWindowsInSession(session_id);
1017 registry->ShowAllWindowsInCategory(session_id,
"Overworld");
1018 registry->SetActiveCategory(
"Overworld");
1019 }
else if (layout_name ==
"dungeon_default") {
1020 registry->HideAllWindowsInSession(session_id);
1021 registry->ShowAllWindowsInCategory(session_id,
"Dungeon");
1022 registry->SetActiveCategory(
"Dungeon");
1023 }
else if (layout_name ==
"graphics_default") {
1024 registry->HideAllWindowsInSession(session_id);
1025 registry->ShowAllWindowsInCategory(session_id,
"Graphics");
1026 registry->SetActiveCategory(
"Graphics");
1027 }
else if (layout_name ==
"debug_default") {
1028 registry->HideAllWindowsInSession(session_id);
1029 registry->ShowAllWindowsInCategory(session_id,
"Debug");
1030 registry->SetActiveCategory(
"Debug");
1031 }
else if (layout_name ==
"minimal") {
1032 registry->HideAllWindowsInSession(session_id);
1034 }
else if (layout_name ==
"all_cards") {
1035 registry->ShowAllWindowsInSession(session_id);
1038 if (!registry->LoadPreset(layout_name)) {
1039 result[
"success"] =
false;
1040 result[
"error"] =
"Unknown layout: " + layout_name;
1041 return result.dump();
1045 result[
"success"] =
true;
1046 result[
"layout"] = layout_name;
1048 LOG_INFO(
"WasmControlApi",
"SetPanelLayout: %s", layout_name.c_str());
1049 return result.dump();
1052std::string WasmControlApi::GetAvailableLayouts() {
1053 nlohmann::json result = nlohmann::json::array();
1056 result.push_back(
"overworld_default");
1057 result.push_back(
"dungeon_default");
1058 result.push_back(
"graphics_default");
1059 result.push_back(
"debug_default");
1060 result.push_back(
"minimal");
1061 result.push_back(
"all_cards");
1063 return result.dump();
1066std::string WasmControlApi::SaveCurrentLayout(
const std::string& layout_name) {
1067 nlohmann::json result;
1070 result[
"success"] =
false;
1071 result[
"error"] =
"Control API not initialized";
1072 return result.dump();
1076 result[
"success"] =
true;
1077 result[
"layout"] = layout_name;
1079 return result.dump();
1086std::string WasmControlApi::TriggerMenuAction(
const std::string& action_path) {
1087 nlohmann::json result;
1090 result[
"success"] =
false;
1091 result[
"error"] =
"Control API not initialized";
1092 return result.dump();
1095 auto* registry = GetWindowManager();
1098 if (action_path ==
"File.Save") {
1099 auto status = editor_manager_->SaveRom();
1100 result[
"success"] = status.ok();
1102 result[
"error"] = status.ToString();
1104 }
else if (action_path ==
"File.Open") {
1106 registry->TriggerOpenRom();
1107 result[
"success"] =
true;
1109 result[
"success"] =
false;
1110 result[
"error"] =
"Panel registry not available";
1114 else if (action_path ==
"Edit.Undo") {
1116 registry->TriggerUndo();
1117 result[
"success"] =
true;
1119 result[
"success"] =
false;
1120 result[
"error"] =
"Panel registry not available";
1122 }
else if (action_path ==
"Edit.Redo") {
1124 registry->TriggerRedo();
1125 result[
"success"] =
true;
1127 result[
"success"] =
false;
1128 result[
"error"] =
"Panel registry not available";
1132 else if (action_path ==
"View.ShowEmulator") {
1133 editor_manager_->ui_coordinator()->SetEmulatorVisible(
true);
1134 result[
"success"] =
true;
1135 }
else if (action_path ==
"View.HideEmulator") {
1136 editor_manager_->ui_coordinator()->SetEmulatorVisible(
false);
1137 result[
"success"] =
true;
1138 }
else if (action_path ==
"View.ToggleEmulator") {
1139 auto* ui = editor_manager_->ui_coordinator();
1140 ui->SetEmulatorVisible(!ui->IsEmulatorVisible());
1141 result[
"success"] =
true;
1142 result[
"visible"] = ui->IsEmulatorVisible();
1143 }
else if (action_path ==
"View.ShowWelcome") {
1144 editor_manager_->ui_coordinator()->SetWelcomeScreenVisible(
true);
1145 result[
"success"] =
true;
1146 }
else if (action_path ==
"View.ShowPanelBrowser") {
1148 registry->TriggerShowWindowBrowser();
1149 result[
"success"] =
true;
1151 result[
"success"] =
false;
1152 result[
"error"] =
"Panel registry not available";
1154 }
else if (action_path ==
"View.ShowSettings") {
1156 registry->TriggerShowSettings();
1157 result[
"success"] =
true;
1159 result[
"success"] =
false;
1160 result[
"error"] =
"Panel registry not available";
1164 else if (action_path ==
"Tools.GlobalSearch") {
1166 registry->TriggerShowSearch();
1167 result[
"success"] =
true;
1169 result[
"success"] =
false;
1170 result[
"error"] =
"Panel registry not available";
1172 }
else if (action_path ==
"Tools.CommandPalette") {
1174 registry->TriggerShowCommandPalette();
1175 result[
"success"] =
true;
1177 result[
"success"] =
false;
1178 result[
"error"] =
"Panel registry not available";
1180 }
else if (action_path ==
"Tools.ShowShortcuts") {
1182 registry->TriggerShowShortcuts();
1183 result[
"success"] =
true;
1185 result[
"success"] =
false;
1186 result[
"error"] =
"Panel registry not available";
1190 else if (action_path ==
"Help.ShowHelp") {
1192 registry->TriggerShowHelp();
1193 result[
"success"] =
true;
1195 result[
"success"] =
false;
1196 result[
"error"] =
"Panel registry not available";
1201 result[
"success"] =
false;
1202 result[
"error"] =
"Unknown action: " + action_path;
1205 return result.dump();
1208std::string WasmControlApi::GetAvailableMenuActions() {
1209 nlohmann::json result = nlohmann::json::array();
1212 result.push_back(
"File.Open");
1213 result.push_back(
"File.Save");
1214 result.push_back(
"File.SaveAs");
1215 result.push_back(
"File.NewProject");
1216 result.push_back(
"File.OpenProject");
1219 result.push_back(
"Edit.Undo");
1220 result.push_back(
"Edit.Redo");
1221 result.push_back(
"Edit.Cut");
1222 result.push_back(
"Edit.Copy");
1223 result.push_back(
"Edit.Paste");
1226 result.push_back(
"View.ShowEmulator");
1227 result.push_back(
"View.ShowWelcome");
1228 result.push_back(
"View.ShowPanelBrowser");
1229 result.push_back(
"View.ShowMemoryEditor");
1230 result.push_back(
"View.ShowHexEditor");
1233 result.push_back(
"Tools.GlobalSearch");
1234 result.push_back(
"Tools.CommandPalette");
1236 return result.dump();
1243std::string WasmControlApi::GetSessionInfo() {
1244 nlohmann::json result;
1247 result[
"error"] =
"Control API not initialized";
1248 return result.dump();
1251 result[
"session_index"] = editor_manager_->GetCurrentSessionIndex();
1252 result[
"session_count"] = editor_manager_->GetActiveSessionCount();
1254 auto*
rom = editor_manager_->GetCurrentRom();
1256 result[
"rom_loaded"] =
true;
1258 result[
"rom_title"] =
rom->
title();
1260 result[
"rom_loaded"] =
false;
1264 if (current_editor) {
1265 result[
"current_editor"] = EditorTypeToString(
static_cast<int>(
current_editor->
type()));
1268 return result.dump();
1271std::string WasmControlApi::CreateSession() {
1272 nlohmann::json result;
1275 result[
"success"] =
false;
1276 result[
"error"] =
"Control API not initialized";
1277 return result.dump();
1280 editor_manager_->CreateNewSession();
1281 result[
"success"] =
true;
1282 result[
"session_index"] = editor_manager_->GetCurrentSessionIndex();
1284 return result.dump();
1287std::string WasmControlApi::SwitchSession(
int session_index) {
1288 nlohmann::json result;
1291 result[
"success"] =
false;
1292 result[
"error"] =
"Control API not initialized";
1293 return result.dump();
1296 if (session_index < 0 ||
static_cast<size_t>(session_index) >= editor_manager_->GetActiveSessionCount()) {
1297 result[
"success"] =
false;
1298 result[
"error"] =
"Invalid session index";
1299 return result.dump();
1302 editor_manager_->SwitchToSession(
static_cast<size_t>(session_index));
1303 result[
"success"] =
true;
1304 result[
"session_index"] = session_index;
1306 return result.dump();
1313std::string WasmControlApi::GetRomStatus() {
1314 nlohmann::json result;
1317 result[
"error"] =
"Control API not initialized";
1318 return result.dump();
1321 auto*
rom = editor_manager_->GetCurrentRom();
1323 result[
"loaded"] =
true;
1329 result[
"loaded"] =
false;
1332 return result.dump();
1335std::string WasmControlApi::ReadRomBytes(
int address,
int count) {
1336 nlohmann::json result;
1339 result[
"error"] =
"Control API not initialized";
1340 return result.dump();
1343 auto*
rom = editor_manager_->GetCurrentRom();
1345 result[
"error"] =
"No ROM loaded";
1346 return result.dump();
1350 count = std::min(count, 256);
1352 if (address < 0 ||
static_cast<size_t>(address + count) >
rom->
size()) {
1353 result[
"error"] =
"Address out of range";
1354 return result.dump();
1357 result[
"address"] = address;
1358 result[
"count"] = count;
1360 nlohmann::json bytes = nlohmann::json::array();
1361 for (
int i = 0; i < count; ++i) {
1363 if (byte_result.ok()) {
1364 bytes.push_back(*byte_result);
1369 result[
"bytes"] = bytes;
1371 return result.dump();
1374std::string WasmControlApi::WriteRomBytes(
int address,
const std::string& bytes_json) {
1375 nlohmann::json result;
1378 result[
"success"] =
false;
1379 result[
"error"] =
"Control API not initialized";
1380 return result.dump();
1383 auto*
rom = editor_manager_->GetCurrentRom();
1385 result[
"success"] =
false;
1386 result[
"error"] =
"No ROM loaded";
1387 return result.dump();
1391 auto bytes = nlohmann::json::parse(bytes_json);
1392 if (!bytes.is_array()) {
1393 result[
"success"] =
false;
1394 result[
"error"] =
"Invalid bytes format - expected array";
1395 return result.dump();
1398 for (
size_t i = 0; i < bytes.size(); ++i) {
1399 uint8_t value = bytes[i].get<uint8_t>();
1400 auto status =
rom->
WriteByte(address +
static_cast<int>(i), value);
1402 result[
"success"] =
false;
1403 result[
"error"] = status.ToString();
1404 return result.dump();
1408 result[
"success"] =
true;
1409 result[
"bytes_written"] = bytes.size();
1411 }
catch (
const std::exception& e) {
1412 result[
"success"] =
false;
1413 result[
"error"] = e.what();
1416 return result.dump();
1419std::string WasmControlApi::SaveRom() {
1420 nlohmann::json result;
1423 result[
"success"] =
false;
1424 result[
"error"] =
"Control API not initialized";
1425 return result.dump();
1428 auto status = editor_manager_->SaveRom();
1429 result[
"success"] = status.ok();
1431 result[
"error"] = status.ToString();
1434 return result.dump();
1441std::string WasmControlApi::GetEditorSnapshot() {
1442 nlohmann::json result;
1445 result[
"error"] =
"Control API not initialized";
1446 return result.dump();
1449 auto* current = editor_manager_->GetCurrentEditor();
1451 result[
"editor_type"] =
"none";
1452 result[
"active"] =
false;
1453 return result.dump();
1456 result[
"editor_type"] = EditorTypeToString(
static_cast<int>(current->type()));
1457 result[
"editor_type_id"] =
static_cast<int>(current->type());
1458 result[
"active"] = *current->active();
1461 auto*
rom = editor_manager_->GetCurrentRom();
1463 result[
"rom_loaded"] =
true;
1464 result[
"rom_title"] =
rom->
title();
1466 result[
"rom_loaded"] =
false;
1470 nlohmann::json active_data;
1471 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1474 auto* dungeon = editor_set->GetDungeonEditor();
1476 active_data[
"current_room_id"] = dungeon->current_room_id();
1478 nlohmann::json active_rooms = nlohmann::json::array();
1479 for (
int i = 0; i < dungeon->active_rooms().size(); ++i) {
1480 active_rooms.push_back(dungeon->active_rooms()[i]);
1482 active_data[
"active_rooms"] = active_rooms;
1483 active_data[
"room_count"] = dungeon->active_rooms().size();
1487 auto* overworld = editor_set->GetOverworldEditor();
1489 active_data[
"current_map"] = overworld->overworld().current_map_id();
1490 active_data[
"current_world"] = overworld->overworld().current_world();
1495 result[
"active_data"] = active_data;
1497 return result.dump();
1500std::string WasmControlApi::GetCurrentDungeonRoom() {
1501 nlohmann::json result;
1504 result[
"error"] =
"Control API not initialized";
1505 return result.dump();
1508 auto* current = editor_manager_->GetCurrentEditor();
1510 result[
"error"] =
"Dungeon editor not active";
1511 result[
"editor_type"] = current ? EditorTypeToString(
static_cast<int>(current->type())) :
"none";
1512 return result.dump();
1515 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1517 result[
"error"] =
"No editor set available";
1518 return result.dump();
1521 auto* dungeon = editor_set->GetDungeonEditor();
1523 result[
"error"] =
"Dungeon editor not available";
1524 return result.dump();
1526 result[
"room_id"] = dungeon->current_room_id();
1529 nlohmann::json active_rooms = nlohmann::json::array();
1530 for (
int i = 0; i < dungeon->active_rooms().size(); ++i) {
1531 active_rooms.push_back(dungeon->active_rooms()[i]);
1533 result[
"active_rooms"] = active_rooms;
1534 result[
"room_count"] = dungeon->active_rooms().size();
1537 nlohmann::json cards;
1547 result[
"visible_cards"] = cards;
1549 return result.dump();
1552std::string WasmControlApi::GetCurrentOverworldMap() {
1553 nlohmann::json result;
1556 result[
"error"] =
"Control API not initialized";
1557 return result.dump();
1560 auto* current = editor_manager_->GetCurrentEditor();
1562 result[
"error"] =
"Overworld editor not active";
1563 result[
"editor_type"] = current ? EditorTypeToString(
static_cast<int>(current->type())) :
"none";
1564 return result.dump();
1567 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1569 result[
"error"] =
"No editor set available";
1570 return result.dump();
1573 auto* overworld = editor_set->GetOverworldEditor();
1575 result[
"error"] =
"Overworld editor not available";
1576 return result.dump();
1578 auto& ow_data = overworld->overworld();
1580 result[
"map_id"] = ow_data.current_map_id();
1581 result[
"world"] = ow_data.current_world();
1582 result[
"world_name"] = ow_data.current_world() == 0 ?
"Light World" :
1583 (ow_data.current_world() == 1 ?
"Dark World" :
"Special World");
1586 return result.dump();
1589std::string WasmControlApi::GetEditorSelection() {
1590 nlohmann::json result;
1593 result[
"error"] =
"Control API not initialized";
1594 return result.dump();
1597 auto* current = editor_manager_->GetCurrentEditor();
1599 result[
"error"] =
"No editor active";
1600 return result.dump();
1603 result[
"editor_type"] = EditorTypeToString(
static_cast<int>(current->type()));
1604 result[
"selection"] = nlohmann::json::array();
1608 result[
"has_selection"] =
false;
1610 return result.dump();
1617std::string WasmControlApi::GetRoomTileData(
int room_id) {
1618 nlohmann::json result;
1621 result[
"error"] =
"Control API not initialized";
1622 return result.dump();
1625 if (room_id < 0 || room_id >= 296) {
1626 result[
"error"] =
"Invalid room ID (must be 0-295)";
1627 return result.dump();
1630 auto*
rom = editor_manager_->GetCurrentRom();
1632 result[
"error"] =
"ROM not loaded";
1633 return result.dump();
1638 auto*
game_data = editor_manager_->GetCurrentGameData();
1640 room.SetGameData(game_data);
1642 room.LoadRoomGraphics();
1645 result[
"room_id"] = room_id;
1646 result[
"width"] = 512;
1647 result[
"height"] = 512;
1650 const auto& layout = room.GetLayout();
1651 const auto& layout_objects = layout.GetObjects();
1654 nlohmann::json layer1_tiles = nlohmann::json::array();
1655 nlohmann::json layer2_tiles = nlohmann::json::array();
1657 for (
const auto& obj : layout_objects) {
1658 nlohmann::json tile_obj;
1659 tile_obj[
"x"] = obj.x();
1660 tile_obj[
"y"] = obj.y();
1662 auto tile_result = obj.GetTile(0);
1663 if (tile_result.ok()) {
1664 const auto* tile_info = tile_result.value();
1665 tile_obj[
"tile_id"] = tile_info->id_;
1666 tile_obj[
"palette"] = tile_info->palette_;
1667 tile_obj[
"priority"] = tile_info->over_;
1668 tile_obj[
"h_flip"] = tile_info->horizontal_mirror_;
1669 tile_obj[
"v_flip"] = tile_info->vertical_mirror_;
1671 if (obj.GetLayerValue() == 1) {
1672 layer2_tiles.push_back(tile_obj);
1674 layer1_tiles.push_back(tile_obj);
1679 result[
"layer1"] = layer1_tiles;
1680 result[
"layer2"] = layer2_tiles;
1681 result[
"layer1_count"] = layer1_tiles.size();
1682 result[
"layer2_count"] = layer2_tiles.size();
1684 return result.dump();
1687std::string WasmControlApi::GetRoomObjects(
int room_id) {
1688 nlohmann::json result = nlohmann::json::array();
1691 nlohmann::json error;
1692 error[
"error"] =
"Control API not initialized";
1693 return error.dump();
1696 if (room_id < 0 || room_id >= 296) {
1697 nlohmann::json error;
1698 error[
"error"] =
"Invalid room ID (must be 0-295)";
1699 return error.dump();
1702 auto*
rom = editor_manager_->GetCurrentRom();
1704 nlohmann::json error;
1705 error[
"error"] =
"ROM not loaded";
1706 return error.dump();
1713 const auto& tile_objects = room.GetTileObjects();
1715 for (
const auto& obj : tile_objects) {
1716 nlohmann::json obj_data;
1717 obj_data[
"id"] = obj.id_;
1718 obj_data[
"x"] = obj.x();
1719 obj_data[
"y"] = obj.y();
1720 obj_data[
"size"] = obj.size();
1721 obj_data[
"layer"] = obj.GetLayerValue();
1724 auto options =
static_cast<int>(obj.options());
1731 result.push_back(obj_data);
1734 return result.dump();
1737std::string WasmControlApi::GetRoomProperties(
int room_id) {
1738 nlohmann::json result;
1741 result[
"error"] =
"Control API not initialized";
1742 return result.dump();
1745 if (room_id < 0 || room_id >= 296) {
1746 result[
"error"] =
"Invalid room ID (must be 0-295)";
1747 return result.dump();
1750 auto*
rom = editor_manager_->GetCurrentRom();
1752 result[
"error"] =
"ROM not loaded";
1753 return result.dump();
1759 result[
"room_id"] = room_id;
1760 result[
"blockset"] = room.blockset();
1761 result[
"spriteset"] = room.spriteset();
1762 result[
"palette"] = room.palette();
1763 result[
"floor1"] = room.floor1();
1764 result[
"floor2"] = room.floor2();
1765 result[
"layout"] = room.layout_id();
1766 result[
"holewarp"] = room.holewarp();
1767 result[
"message_id"] = room.message_id();
1770 result[
"effect"] =
static_cast<int>(room.effect());
1771 result[
"tag1"] =
static_cast<int>(room.tag1());
1772 result[
"tag2"] =
static_cast<int>(room.tag2());
1773 result[
"collision"] =
static_cast<int>(room.collision());
1776 const auto& layer_merge = room.layer_merging();
1777 result[
"layer_merging"] = {
1778 {
"id", layer_merge.ID},
1779 {
"name", layer_merge.Name},
1780 {
"layer2_visible", layer_merge.Layer2Visible},
1781 {
"layer2_on_top", layer_merge.Layer2OnTop},
1782 {
"layer2_translucent", layer_merge.Layer2Translucent}
1785 result[
"is_light"] = room.IsLight();
1786 result[
"is_loaded"] = room.IsLoaded();
1788 return result.dump();
1791std::string WasmControlApi::GetMapTileData(
int map_id) {
1792 nlohmann::json result;
1795 result[
"error"] =
"Control API not initialized";
1796 return result.dump();
1800 result[
"error"] =
"Invalid map ID (must be 0-159)";
1801 return result.dump();
1804 auto* overworld = editor_manager_->overworld();
1806 result[
"error"] =
"Overworld not loaded";
1807 return result.dump();
1810 auto* map = overworld->overworld_map(map_id);
1812 result[
"error"] =
"Map not found";
1813 return result.dump();
1816 result[
"map_id"] = map_id;
1817 result[
"width"] = 32;
1818 result[
"height"] = 32;
1821 auto blockset = map->current_tile16_blockset();
1824 result[
"has_tile_data"] = !blockset.empty();
1825 result[
"tile_count"] = blockset.size();
1826 result[
"is_built"] = map->is_built();
1827 result[
"is_large_map"] = map->is_large_map();
1831 if (blockset.size() >= 64) {
1832 nlohmann::json sample_tiles = nlohmann::json::array();
1834 for (
int i = 0; i < 64; i++) {
1835 sample_tiles.push_back(
static_cast<int>(blockset[i]));
1837 result[
"sample_tiles"] = sample_tiles;
1838 result[
"sample_note"] =
"First 8x8 tiles from top-left corner";
1841 return result.dump();
1844std::string WasmControlApi::GetMapEntities(
int map_id) {
1845 nlohmann::json result;
1848 result[
"error"] =
"Control API not initialized";
1849 return result.dump();
1853 result[
"error"] =
"Invalid map ID (must be 0-159)";
1854 return result.dump();
1857 auto* overworld = editor_manager_->overworld();
1859 result[
"error"] =
"Overworld not loaded";
1860 return result.dump();
1863 result[
"map_id"] = map_id;
1864 result[
"entrances"] = nlohmann::json::array();
1865 result[
"exits"] = nlohmann::json::array();
1866 result[
"items"] = nlohmann::json::array();
1867 result[
"sprites"] = nlohmann::json::array();
1870 for (
const auto& entrance : overworld->entrances()) {
1871 if (entrance.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1873 e[
"id"] = entrance.entrance_id_;
1874 e[
"x"] = entrance.x_;
1875 e[
"y"] = entrance.y_;
1876 e[
"map_id"] = entrance.map_id_;
1877 result[
"entrances"].push_back(e);
1882 auto* exits = overworld->exits();
1884 for (
const auto& exit : *exits) {
1885 if (exit.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1889 ex[
"map_id"] = exit.map_id_;
1890 ex[
"room_id"] = exit.room_id_;
1891 result[
"exits"].push_back(ex);
1897 for (
const auto& item : overworld->all_items()) {
1898 if (!item.deleted && item.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1903 result[
"items"].push_back(i);
1907 return result.dump();
1910std::string WasmControlApi::GetMapProperties(
int map_id) {
1911 nlohmann::json result;
1914 result[
"error"] =
"Control API not initialized";
1915 return result.dump();
1919 result[
"error"] =
"Invalid map ID (must be 0-159)";
1920 return result.dump();
1923 auto* overworld = editor_manager_->overworld();
1925 result[
"error"] =
"Overworld not loaded";
1926 return result.dump();
1929 auto* map = overworld->overworld_map(map_id);
1931 result[
"error"] =
"Map not found";
1932 return result.dump();
1935 result[
"map_id"] = map_id;
1936 result[
"world"] = map_id / 64;
1937 result[
"parent_id"] = map->parent();
1938 result[
"area_graphics"] = map->area_graphics();
1939 result[
"area_palette"] = map->area_palette();
1940 result[
"sprite_graphics"] = {map->sprite_graphics(0), map->sprite_graphics(1), map->sprite_graphics(2)};
1941 result[
"sprite_palette"] = {map->sprite_palette(0), map->sprite_palette(1), map->sprite_palette(2)};
1942 result[
"message_id"] = map->message_id();
1943 result[
"is_large_map"] = map->is_large_map();
1945 return result.dump();
1948std::string WasmControlApi::GetPaletteData(
const std::string& group_name,
int palette_id) {
1949 nlohmann::json result;
1952 result[
"error"] =
"Control API not initialized";
1953 return result.dump();
1956 auto*
rom = editor_manager_->GetCurrentRom();
1958 result[
"error"] =
"ROM not loaded";
1959 return result.dump();
1962 result[
"group"] = group_name;
1963 result[
"palette_id"] = palette_id;
1966 auto*
game_data = editor_manager_->GetCurrentGameData();
1968 result[
"error"] =
"GameData not available";
1969 return result.dump();
1974 result[
"error"] =
"Invalid palette group name";
1975 return result.dump();
1978 if (palette_id < 0 || palette_id >=
static_cast<int>(group->size())) {
1979 result[
"error"] =
"Invalid palette ID for this group";
1980 result[
"max_palette_id"] = group->
size() - 1;
1981 return result.dump();
1984 auto palette = (*group)[palette_id];
1985 nlohmann::json colors = nlohmann::json::array();
1988 for (
size_t i = 0; i < palette.size(); i++) {
1989 const auto& color = palette[i];
1990 nlohmann::json color_data;
1991 color_data[
"index"] = i;
1995 auto rgb_color = color.rgb();
1998 int r =
static_cast<int>(rgb_color.x * 255);
1999 int g =
static_cast<int>(rgb_color.y * 255);
2000 int b =
static_cast<int>(rgb_color.z * 255);
2001 color_data[
"r"] = r;
2002 color_data[
"g"] = g;
2003 color_data[
"b"] = b;
2004 color_data[
"hex"] = absl::StrFormat(
"#%02X%02X%02X", r, g, b);
2007 colors.push_back(color_data);
2010 result[
"colors"] = colors;
2011 result[
"color_count"] = palette.size();
2013 }
catch (
const std::exception& e) {
2014 result[
"error"] = std::string(
"Failed to extract palette: ") + e.what();
2017 return result.dump();
2020std::string WasmControlApi::ListPaletteGroups() {
2021 nlohmann::json result = nlohmann::json::array();
2024 result.push_back(
"ow_main");
2025 result.push_back(
"ow_aux");
2026 result.push_back(
"ow_animated");
2027 result.push_back(
"hud");
2028 result.push_back(
"global_sprites");
2029 result.push_back(
"armors");
2030 result.push_back(
"swords");
2031 result.push_back(
"shields");
2032 result.push_back(
"sprites_aux1");
2033 result.push_back(
"sprites_aux2");
2034 result.push_back(
"sprites_aux3");
2035 result.push_back(
"dungeon_main");
2036 result.push_back(
"grass");
2037 result.push_back(
"3d_object");
2038 result.push_back(
"ow_mini_map");
2040 return result.dump();
2043std::string WasmControlApi::LoadFont(
const std::string& name,
const std::string& data,
float size) {
2044 nlohmann::json result;
2045 auto status = yaze::platform::WasmSettings::LoadUserFont(name, data, size);
2047 result[
"success"] =
true;
2049 result[
"success"] =
false;
2050 result[
"error"] = status.ToString();
2052 return result.dump();
2059std::string WasmControlApi::GetUIElementTree() {
2060 nlohmann::json result;
2063 result[
"error"] =
"Control API not initialized";
2064 result[
"elements"] = nlohmann::json::array();
2065 return result.dump();
2070 const auto& all_widgets = registry.GetAllWidgets();
2072 nlohmann::json elements = nlohmann::json::array();
2075 for (
const auto& [path, info] : all_widgets) {
2076 nlohmann::json elem;
2077 elem[
"id"] = info.full_path;
2078 elem[
"type"] = info.type;
2079 elem[
"label"] = info.label;
2080 elem[
"enabled"] = info.enabled;
2081 elem[
"visible"] = info.visible;
2082 elem[
"window"] = info.window_name;
2085 if (info.bounds.valid) {
2087 {
"x", info.bounds.min_x},
2088 {
"y", info.bounds.min_y},
2089 {
"width", info.bounds.max_x - info.bounds.min_x},
2090 {
"height", info.bounds.max_y - info.bounds.min_y}
2094 {
"x", 0}, {
"y", 0}, {
"width", 0}, {
"height", 0}
2099 if (!info.description.empty()) {
2100 elem[
"description"] = info.description;
2102 elem[
"imgui_id"] =
static_cast<uint32_t
>(info.imgui_id);
2103 elem[
"last_seen_frame"] = info.last_seen_frame;
2105 elements.push_back(elem);
2108 result[
"elements"] = elements;
2109 result[
"count"] = elements.size();
2110 result[
"source"] =
"WidgetIdRegistry";
2112 return result.dump();
2115std::string WasmControlApi::GetUIElementBounds(
const std::string& element_id) {
2116 nlohmann::json result;
2119 result[
"error"] =
"Control API not initialized";
2120 return result.dump();
2125 const auto* widget_info = registry.GetWidgetInfo(element_id);
2127 result[
"id"] = element_id;
2129 if (widget_info ==
nullptr) {
2130 result[
"found"] =
false;
2131 result[
"error"] =
"Element not found: " + element_id;
2132 return result.dump();
2135 result[
"found"] =
true;
2136 result[
"visible"] = widget_info->visible;
2137 result[
"enabled"] = widget_info->enabled;
2138 result[
"type"] = widget_info->type;
2139 result[
"label"] = widget_info->label;
2140 result[
"window"] = widget_info->window_name;
2143 if (widget_info->bounds.valid) {
2144 result[
"x"] = widget_info->bounds.min_x;
2145 result[
"y"] = widget_info->bounds.min_y;
2146 result[
"width"] = widget_info->bounds.max_x - widget_info->bounds.min_x;
2147 result[
"height"] = widget_info->bounds.max_y - widget_info->bounds.min_y;
2148 result[
"bounds_valid"] =
true;
2152 result[
"width"] = 0;
2153 result[
"height"] = 0;
2154 result[
"bounds_valid"] =
false;
2158 result[
"imgui_id"] =
static_cast<uint32_t
>(widget_info->imgui_id);
2159 result[
"last_seen_frame"] = widget_info->last_seen_frame;
2161 if (!widget_info->description.empty()) {
2162 result[
"description"] = widget_info->description;
2165 return result.dump();
2168std::string WasmControlApi::SetSelection(
const std::string& ids_json) {
2169 nlohmann::json result;
2172 result[
"success"] =
false;
2173 result[
"error"] =
"Control API not initialized";
2174 return result.dump();
2178 auto ids = nlohmann::json::parse(ids_json);
2182 result[
"success"] =
true;
2183 result[
"selected_ids"] = ids;
2184 result[
"note"] =
"Selection setting not yet fully implemented";
2186 }
catch (
const std::exception& e) {
2187 result[
"success"] =
false;
2188 result[
"error"] = std::string(
"Invalid JSON: ") + e.what();
2191 return result.dump();
2198std::string WasmControlApi::GetPlatformInfo() {
2199 nlohmann::json result;
2207 result[
"platform"] =
"Windows";
2210 result[
"platform"] =
"macOS";
2213 result[
"platform"] =
"Linux";
2216 result[
"platform"] =
"WebMac";
2219 result[
"platform"] =
"WebOther";
2222 result[
"platform"] =
"Unknown";
2230 result[
"shift_display"] =
"Shift";
2237 return result.dump();
2244bool WasmControlApi::AgentIsReady() {
2245 if (!initialized_ || !editor_manager_) {
2249 auto* agent_editor = editor_manager_->GetAgentEditor();
2250 return agent_editor !=
nullptr;
2253std::string WasmControlApi::AgentSendMessage(
const std::string& message) {
2254 nlohmann::json result;
2256 if (!initialized_ || !editor_manager_) {
2257 result[
"success"] =
false;
2258 result[
"error"] =
"API not initialized";
2259 return result.dump();
2262 auto* agent_editor = editor_manager_->GetAgentEditor();
2263 if (!agent_editor) {
2264 result[
"success"] =
false;
2265 result[
"error"] =
"Agent editor not available";
2266 return result.dump();
2269 auto* agent_chat = agent_editor->GetAgentChat();
2271 result[
"success"] =
false;
2272 result[
"error"] =
"Agent chat not available";
2273 return result.dump();
2278 result[
"success"] =
true;
2279 result[
"status"] =
"queued";
2280 result[
"message"] = message;
2285 return result.dump();
2288std::string WasmControlApi::AgentGetChatHistory() {
2289 nlohmann::json result = nlohmann::json::array();
2291 if (!initialized_ || !editor_manager_) {
2292 return result.dump();
2295 auto* agent_editor = editor_manager_->GetAgentEditor();
2296 if (!agent_editor) {
2297 return result.dump();
2300 auto* agent_chat = agent_editor->GetAgentChat();
2302 return result.dump();
2309 return result.dump();
2312std::string WasmControlApi::AgentGetConfig() {
2313 nlohmann::json result;
2315 if (!initialized_ || !editor_manager_) {
2316 result[
"error"] =
"API not initialized";
2317 return result.dump();
2320 auto* agent_editor = editor_manager_->GetAgentEditor();
2321 if (!agent_editor) {
2322 result[
"error"] =
"Agent editor not available";
2323 return result.dump();
2326 auto config = agent_editor->GetCurrentConfig();
2327 result[
"provider"] = config.provider;
2328 result[
"model"] = config.model;
2329 result[
"ollama_host"] = config.ollama_host;
2330 result[
"verbose"] = config.verbose;
2331 result[
"show_reasoning"] = config.show_reasoning;
2332 result[
"max_tool_iterations"] = config.max_tool_iterations;
2334 return result.dump();
2337std::string WasmControlApi::AgentSetConfig(
const std::string& config_json) {
2338 nlohmann::json result;
2340 if (!initialized_ || !editor_manager_) {
2341 result[
"success"] =
false;
2342 result[
"error"] =
"API not initialized";
2343 return result.dump();
2346 auto* agent_editor = editor_manager_->GetAgentEditor();
2347 if (!agent_editor) {
2348 result[
"success"] =
false;
2349 result[
"error"] =
"Agent editor not available";
2350 return result.dump();
2354 auto config_data = nlohmann::json::parse(config_json);
2356 editor::AgentEditor::AgentConfig config;
2357 if (config_data.contains(
"provider")) {
2358 config.provider = config_data[
"provider"].get<std::string>();
2360 if (config_data.contains(
"model")) {
2361 config.model = config_data[
"model"].get<std::string>();
2363 if (config_data.contains(
"ollama_host")) {
2364 config.ollama_host = config_data[
"ollama_host"].get<std::string>();
2366 if (config_data.contains(
"verbose")) {
2367 config.verbose = config_data[
"verbose"].get<
bool>();
2369 if (config_data.contains(
"show_reasoning")) {
2370 config.show_reasoning = config_data[
"show_reasoning"].get<
bool>();
2372 if (config_data.contains(
"max_tool_iterations")) {
2373 config.max_tool_iterations = config_data[
"max_tool_iterations"].get<
int>();
2376 agent_editor->ApplyConfig(config);
2377 result[
"success"] =
true;
2378 }
catch (
const std::exception& e) {
2379 result[
"success"] =
false;
2380 result[
"error"] = e.what();
2383 return result.dump();
2386std::string WasmControlApi::AgentGetProviders() {
2387 nlohmann::json result = nlohmann::json::array();
2392 {
"name",
"Mock Provider"},
2393 {
"description",
"Testing provider that echoes messages"}
2398 {
"description",
"Local Ollama server"},
2399 {
"requires_host",
true}
2403 {
"name",
"Google Gemini"},
2404 {
"description",
"Google's Gemini API"},
2405 {
"requires_api_key",
true}
2408 return result.dump();
2411std::string WasmControlApi::AgentGetProposals() {
2412 nlohmann::json result = nlohmann::json::array();
2414 if (!initialized_ || !editor_manager_) {
2415 return result.dump();
2421 return result.dump();
2424std::string WasmControlApi::AgentAcceptProposal(
const std::string& proposal_id) {
2425 nlohmann::json result;
2427 if (!initialized_ || !editor_manager_) {
2428 result[
"success"] =
false;
2429 result[
"error"] =
"API not initialized";
2430 return result.dump();
2434 result[
"success"] =
false;
2435 result[
"error"] =
"Proposal system not yet integrated";
2436 result[
"proposal_id"] = proposal_id;
2438 return result.dump();
2441std::string WasmControlApi::AgentRejectProposal(
const std::string& proposal_id) {
2442 nlohmann::json result;
2444 if (!initialized_ || !editor_manager_) {
2445 result[
"success"] =
false;
2446 result[
"error"] =
"API not initialized";
2447 return result.dump();
2451 result[
"success"] =
false;
2452 result[
"error"] =
"Proposal system not yet integrated";
2453 result[
"proposal_id"] = proposal_id;
2455 return result.dump();
2458std::string WasmControlApi::AgentGetProposalDetails(
const std::string& proposal_id) {
2459 nlohmann::json result;
2461 if (!initialized_ || !editor_manager_) {
2462 result[
"error"] =
"API not initialized";
2463 return result.dump();
2467 result[
"error"] =
"Proposal system not yet integrated";
2468 result[
"proposal_id"] = proposal_id;
2470 return result.dump();
2473std::string WasmControlApi::AgentOpenSidebar() {
2474 nlohmann::json result;
2476 if (!initialized_ || !editor_manager_) {
2477 result[
"success"] =
false;
2478 result[
"error"] =
"API not initialized";
2479 return result.dump();
2482 auto* agent_editor = editor_manager_->GetAgentEditor();
2483 if (!agent_editor) {
2484 result[
"success"] =
false;
2485 result[
"error"] =
"Agent editor not available";
2486 return result.dump();
2489 agent_editor->SetChatActive(
true);
2490 result[
"success"] =
true;
2491 result[
"sidebar_open"] =
true;
2493 return result.dump();
2496std::string WasmControlApi::AgentCloseSidebar() {
2497 nlohmann::json result;
2499 if (!initialized_ || !editor_manager_) {
2500 result[
"success"] =
false;
2501 result[
"error"] =
"API not initialized";
2502 return result.dump();
2505 auto* agent_editor = editor_manager_->GetAgentEditor();
2506 if (!agent_editor) {
2507 result[
"success"] =
false;
2508 result[
"error"] =
"Agent editor not available";
2509 return result.dump();
2512 agent_editor->SetChatActive(
false);
2513 result[
"success"] =
true;
2514 result[
"sidebar_open"] =
false;
2516 return result.dump();
2524 emscripten::function(
"controlIsReady", &WasmControlApi::IsReady);
2525 emscripten::function(
"controlSwitchEditor", &WasmControlApi::SwitchEditor);
2526 emscripten::function(
"controlGetCurrentEditor", &WasmControlApi::GetCurrentEditor);
2527 emscripten::function(
"controlGetAvailableEditors", &WasmControlApi::GetAvailableEditors);
2528 emscripten::function(
"controlOpenWindow", &WasmControlApi::OpenWindow);
2529 emscripten::function(
"controlOpenPanel", &WasmControlApi::OpenPanel);
2530 emscripten::function(
"controlCloseWindow", &WasmControlApi::CloseWindow);
2531 emscripten::function(
"controlClosePanel", &WasmControlApi::ClosePanel);
2532 emscripten::function(
"controlToggleWindow", &WasmControlApi::ToggleWindow);
2533 emscripten::function(
"controlTogglePanel", &WasmControlApi::TogglePanel);
2534 emscripten::function(
"controlGetVisibleWindows", &WasmControlApi::GetVisibleWindows);
2535 emscripten::function(
"controlGetVisiblePanels", &WasmControlApi::GetVisiblePanels);
2536 emscripten::function(
"controlGetAvailableWindows", &WasmControlApi::GetAvailableWindows);
2537 emscripten::function(
"controlGetAvailablePanels", &WasmControlApi::GetAvailablePanels);
2538 emscripten::function(
"controlGetWindowsInCategory", &WasmControlApi::GetWindowsInCategory);
2539 emscripten::function(
"controlGetPanelsInCategory", &WasmControlApi::GetPanelsInCategory);
2540 emscripten::function(
"controlShowAllWindows", &WasmControlApi::ShowAllWindows);
2541 emscripten::function(
"controlHideAllWindows", &WasmControlApi::HideAllWindows);
2542 emscripten::function(
"controlSetPanelLayout", &WasmControlApi::SetPanelLayout);
2543 emscripten::function(
"controlGetAvailableLayouts", &WasmControlApi::GetAvailableLayouts);
2544 emscripten::function(
"controlSaveCurrentLayout", &WasmControlApi::SaveCurrentLayout);
2545 emscripten::function(
"controlGetAvailableMenuActions", &WasmControlApi::GetAvailableMenuActions);
2546 emscripten::function(
"controlToggleMenuBar", &WasmControlApi::ToggleMenuBar);
2547 emscripten::function(
"controlGetSessionInfo", &WasmControlApi::GetSessionInfo);
2548 emscripten::function(
"controlCreateSession", &WasmControlApi::CreateSession);
2549 emscripten::function(
"controlSwitchSession", &WasmControlApi::SwitchSession);
2550 emscripten::function(
"controlGetRomStatus", &WasmControlApi::GetRomStatus);
2551 emscripten::function(
"controlReadRomBytes", &WasmControlApi::ReadRomBytes);
2552 emscripten::function(
"controlWriteRomBytes", &WasmControlApi::WriteRomBytes);
2553 emscripten::function(
"controlSaveRom", &WasmControlApi::SaveRom);
2556 emscripten::function(
"editorGetSnapshot", &WasmControlApi::GetEditorSnapshot);
2557 emscripten::function(
"editorGetCurrentDungeonRoom", &WasmControlApi::GetCurrentDungeonRoom);
2558 emscripten::function(
"editorGetCurrentOverworldMap", &WasmControlApi::GetCurrentOverworldMap);
2559 emscripten::function(
"editorGetSelection", &WasmControlApi::GetEditorSelection);
2562 emscripten::function(
"dataGetRoomTileData", &WasmControlApi::GetRoomTileData);
2563 emscripten::function(
"dataGetRoomObjects", &WasmControlApi::GetRoomObjects);
2564 emscripten::function(
"dataGetRoomProperties", &WasmControlApi::GetRoomProperties);
2565 emscripten::function(
"dataGetMapTileData", &WasmControlApi::GetMapTileData);
2566 emscripten::function(
"dataGetMapEntities", &WasmControlApi::GetMapEntities);
2567 emscripten::function(
"dataGetMapProperties", &WasmControlApi::GetMapProperties);
2568 emscripten::function(
"dataGetPaletteData", &WasmControlApi::GetPaletteData);
2569 emscripten::function(
"dataListPaletteGroups", &WasmControlApi::ListPaletteGroups);
2572 emscripten::function(
"guiGetUIElementTree", &WasmControlApi::GetUIElementTree);
2573 emscripten::function(
"guiGetUIElementBounds", &WasmControlApi::GetUIElementBounds);
2574 emscripten::function(
"guiSetSelection", &WasmControlApi::SetSelection);
2577 emscripten::function(
"settingsGetCurrentThemeData", &yaze::platform::WasmSettings::GetCurrentThemeData);
2578 emscripten::function(
"settingsLoadFont", &WasmControlApi::LoadFont);
2581 emscripten::function(
"controlGetPlatformInfo", &WasmControlApi::GetPlatformInfo);
2584 emscripten::function(
"agentIsReady", &WasmControlApi::AgentIsReady);
2585 emscripten::function(
"agentSendMessage", &WasmControlApi::AgentSendMessage);
2586 emscripten::function(
"agentGetChatHistory", &WasmControlApi::AgentGetChatHistory);
2587 emscripten::function(
"agentGetConfig", &WasmControlApi::AgentGetConfig);
2588 emscripten::function(
"agentSetConfig", &WasmControlApi::AgentSetConfig);
2589 emscripten::function(
"agentGetProviders", &WasmControlApi::AgentGetProviders);
2590 emscripten::function(
"agentGetProposals", &WasmControlApi::AgentGetProposals);
2591 emscripten::function(
"agentAcceptProposal", &WasmControlApi::AgentAcceptProposal);
2592 emscripten::function(
"agentRejectProposal", &WasmControlApi::AgentRejectProposal);
2593 emscripten::function(
"agentGetProposalDetails", &WasmControlApi::AgentGetProposalDetails);
2594 emscripten::function(
"agentOpenSidebar", &WasmControlApi::AgentOpenSidebar);
2595 emscripten::function(
"agentCloseSidebar", &WasmControlApi::AgentCloseSidebar);
absl::Status WriteByte(int addr, uint8_t value)
absl::StatusOr< uint8_t > ReadByte(int offset) const
#define LOG_INFO(category, format,...)
EM_JS(void, CallJsAiDriver,(const char *history_json), { if(window.yaze &&window.yaze.ai &&window.yaze.ai.processAgentRequest) { window.yaze.ai.processAgentRequest(UTF8ToString(history_json));} else { console.error("AI Driver not found in window.yaze.ai.processAgentRequest");} })
Rom * rom()
Get the current ROM instance.
Editor * current_editor()
Get the currently active editor.
::yaze::zelda3::GameData * game_data()
Get the current game data instance.
constexpr std::array< const char *, 14 > kEditorNames
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
std::string FormatCtrlShiftShortcut(ImGuiKey key)
Convenience function for Ctrl+Shift+key shortcuts.
Platform GetCurrentPlatform()
Get the current platform at runtime.
bool IsMacPlatform()
Check if running on macOS (native or web)
const char * GetAltDisplayName()
Get the display name for the secondary modifier key.
std::string FormatCtrlShortcut(ImGuiKey key)
Convenience function for Ctrl+key shortcuts.
constexpr int kNumOverworldMaps
Room LoadRoomFromRom(Rom *rom, int room_id)
SNES color in 15-bit RGB format (BGR555)
PaletteGroup * get_group(const std::string &group_name)
gfx::PaletteGroupMap palette_groups
std::string togglePanel(std::string card_id)
Toggle a card's visibility.
std::string getPanelsInCategory(std::string category)
Get cards in a specific category.
std::string getRomStatus()
EMSCRIPTEN_BINDINGS(yaze_debug_inspector)
std::string readRomBytes(int address, int count)
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)