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 openPanel: function(cardId) {
77 if (Module.controlOpenPanel) {
78 try {
return JSON.parse(Module.controlOpenPanel(cardId)); }
79 catch(e) {
return {error: e.message}; }
81 return {error:
"API not ready"};
84 closePanel: function(cardId) {
85 if (Module.controlClosePanel) {
86 try {
return JSON.parse(Module.controlClosePanel(cardId)); }
87 catch(e) {
return {error: e.message}; }
89 return {error:
"API not ready"};
93 if (Module.controlTogglePanel) {
94 try {
return JSON.parse(Module.controlTogglePanel(cardId)); }
95 catch(e) {
return {error: e.message}; }
97 return {error:
"API not ready"};
100 getVisiblePanels: function() {
101 if (Module.controlGetVisiblePanels) {
102 try {
return JSON.parse(Module.controlGetVisiblePanels()); }
103 catch(e) {
return {error: e.message}; }
105 return {error:
"API not ready"};
108 getAvailablePanels: function() {
109 if (Module.controlGetAvailablePanels) {
110 try {
return JSON.parse(Module.controlGetAvailablePanels()); }
111 catch(e) {
return {error: e.message}; }
113 return {error:
"API not ready"};
117 if (Module.controlGetPanelsInCategory) {
118 try {
return JSON.parse(Module.controlGetPanelsInCategory(category)); }
119 catch(e) {
return {error: e.message}; }
121 return {error:
"API not ready"};
124 showAllPanels: function() {
125 if (Module.controlShowAllPanels) {
126 try {
return JSON.parse(Module.controlShowAllPanels()); }
127 catch(e) {
return {error: e.message}; }
129 return {error:
"API not ready"};
132 hideAllPanels: function() {
133 if (Module.controlHideAllPanels) {
134 try {
return JSON.parse(Module.controlHideAllPanels()); }
135 catch(e) {
return {error: e.message}; }
137 return {error:
"API not ready"};
140 showAllPanelsInCategory: function(category) {
141 if (Module.controlShowAllPanelsInCategory) {
142 try {
return JSON.parse(Module.controlShowAllPanelsInCategory(category)); }
143 catch(e) {
return {error: e.message}; }
145 return {error:
"API not ready"};
148 hideAllPanelsInCategory: function(category) {
149 if (Module.controlHideAllPanelsInCategory) {
150 try {
return JSON.parse(Module.controlHideAllPanelsInCategory(category)); }
151 catch(e) {
return {error: e.message}; }
153 return {error:
"API not ready"};
156 showOnlyPanel: function(cardId) {
157 if (Module.controlShowOnlyPanel) {
158 try {
return JSON.parse(Module.controlShowOnlyPanel(cardId)); }
159 catch(e) {
return {error: e.message}; }
161 return {error:
"API not ready"};
165 setPanelLayout: function(layoutName) {
166 if (Module.controlSetPanelLayout) {
167 try {
return JSON.parse(Module.controlSetPanelLayout(layoutName)); }
168 catch(e) {
return {error: e.message}; }
170 return {error:
"API not ready"};
173 getAvailableLayouts: function() {
174 if (Module.controlGetAvailableLayouts) {
175 try {
return JSON.parse(Module.controlGetAvailableLayouts()); }
176 catch(e) {
return {error: e.message}; }
178 return {error:
"API not ready"};
181 saveCurrentLayout: function(layoutName) {
182 if (Module.controlSaveCurrentLayout) {
183 try {
return JSON.parse(Module.controlSaveCurrentLayout(layoutName)); }
184 catch(e) {
return {error: e.message}; }
186 return {error:
"API not ready"};
190 triggerMenuAction: function(actionPath) {
191 if (Module.controlTriggerMenuAction) {
192 try {
return JSON.parse(Module.controlTriggerMenuAction(actionPath)); }
193 catch(e) {
return {error: e.message}; }
195 return {error:
"API not ready"};
198 getAvailableMenuActions: function() {
199 if (Module.controlGetAvailableMenuActions) {
200 try {
return JSON.parse(Module.controlGetAvailableMenuActions()); }
201 catch(e) {
return {error: e.message}; }
203 return {error:
"API not ready"};
206 toggleMenuBar: function() {
207 if (Module.controlToggleMenuBar) {
208 try {
return JSON.parse(Module.controlToggleMenuBar()); }
209 catch(e) {
return {error: e.message}; }
211 return {error:
"API not ready"};
215 getSessionInfo: function() {
216 if (Module.controlGetSessionInfo) {
217 try {
return JSON.parse(Module.controlGetSessionInfo()); }
218 catch(e) {
return {error: e.message}; }
220 return {error:
"API not ready"};
223 createSession: function() {
224 if (Module.controlCreateSession) {
225 try {
return JSON.parse(Module.controlCreateSession()); }
226 catch(e) {
return {error: e.message}; }
228 return {error:
"API not ready"};
231 switchSession: function(sessionIndex) {
232 if (Module.controlSwitchSession) {
233 try {
return JSON.parse(Module.controlSwitchSession(sessionIndex)); }
234 catch(e) {
return {error: e.message}; }
236 return {error:
"API not ready"};
241 if (Module.controlGetRomStatus) {
242 try {
return JSON.parse(Module.controlGetRomStatus()); }
243 catch(e) {
return {error: e.message}; }
245 return {error:
"API not ready"};
250 if (Module.controlReadRomBytes) {
251 try {
return JSON.parse(Module.controlReadRomBytes(address, count)); }
252 catch(e) {
return {error: e.message}; }
254 return {error:
"API not ready"};
257 writeRomBytes: function(address, bytes) {
258 if (Module.controlWriteRomBytes) {
259 try {
return JSON.parse(Module.controlWriteRomBytes(address, JSON.stringify(bytes))); }
260 catch(e) {
return {error: e.message}; }
262 return {error:
"API not ready"};
265 saveRom: function() {
266 if (Module.controlSaveRom) {
267 try {
return JSON.parse(Module.controlSaveRom()); }
268 catch(e) {
return {error: e.message}; }
270 return {error:
"API not ready"};
274 isReady: function() {
275 return Module.controlIsReady ? Module.controlIsReady() :
false;
279 getPlatformInfo: function() {
280 if (Module.controlGetPlatformInfo) {
281 try {
return JSON.parse(Module.controlGetPlatformInfo()); }
282 catch(e) {
return {error: e.message}; }
284 return {error:
"API not ready"};
287 waitUntilReady: function() {
288 return new Promise(function(resolve) {
289 var check = function() {
290 if (Module.controlIsReady && Module.controlIsReady()) {
293 setTimeout(check, 100);
302 window.yaze.editor = {
303 getSnapshot: function() {
304 if (Module.editorGetSnapshot) {
305 try {
return JSON.parse(Module.editorGetSnapshot()); }
306 catch(e) {
return {error: e.message}; }
308 return {error:
"API not ready"};
311 getCurrentRoom: function() {
312 if (Module.editorGetCurrentDungeonRoom) {
313 try {
return JSON.parse(Module.editorGetCurrentDungeonRoom()); }
314 catch(e) {
return {error: e.message}; }
316 return {error:
"API not ready"};
319 getCurrentMap: function() {
320 if (Module.editorGetCurrentOverworldMap) {
321 try {
return JSON.parse(Module.editorGetCurrentOverworldMap()); }
322 catch(e) {
return {error: e.message}; }
324 return {error:
"API not ready"};
327 getSelection: function() {
328 if (Module.editorGetSelection) {
329 try {
return JSON.parse(Module.editorGetSelection()); }
330 catch(e) {
return {error: e.message}; }
332 return {error:
"API not ready"};
339 getRoomTiles: function(roomId) {
340 if (Module.dataGetRoomTileData) {
341 try {
return JSON.parse(Module.dataGetRoomTileData(roomId)); }
342 catch(e) {
return {error: e.message}; }
344 return {error:
"API not ready"};
347 getRoomObjects: function(roomId) {
348 if (Module.dataGetRoomObjects) {
349 try {
return JSON.parse(Module.dataGetRoomObjects(roomId)); }
350 catch(e) {
return {error: e.message}; }
352 return {error:
"API not ready"};
355 getRoomProperties: function(roomId) {
356 if (Module.dataGetRoomProperties) {
357 try {
return JSON.parse(Module.dataGetRoomProperties(roomId)); }
358 catch(e) {
return {error: e.message}; }
360 return {error:
"API not ready"};
364 getMapTiles: function(mapId) {
365 if (Module.dataGetMapTileData) {
366 try {
return JSON.parse(Module.dataGetMapTileData(mapId)); }
367 catch(e) {
return {error: e.message}; }
369 return {error:
"API not ready"};
372 getMapEntities: function(mapId) {
373 if (Module.dataGetMapEntities) {
374 try {
return JSON.parse(Module.dataGetMapEntities(mapId)); }
375 catch(e) {
return {error: e.message}; }
377 return {error:
"API not ready"};
380 getMapProperties: function(mapId) {
381 if (Module.dataGetMapProperties) {
382 try {
return JSON.parse(Module.dataGetMapProperties(mapId)); }
383 catch(e) {
return {error: e.message}; }
385 return {error:
"API not ready"};
389 getPalette: function(groupName, paletteId) {
390 if (Module.dataGetPaletteData) {
391 try {
return JSON.parse(Module.dataGetPaletteData(groupName, paletteId)); }
392 catch(e) {
return {error: e.message}; }
394 return {error:
"API not ready"};
397 getPaletteGroups: function() {
398 if (Module.dataListPaletteGroups) {
399 try {
return JSON.parse(Module.dataListPaletteGroups()); }
400 catch(e) {
return {error: e.message}; }
402 return {error:
"API not ready"};
407 window.yaze.agent = {
409 sendMessage: function(message) {
410 if (Module.agentSendMessage) {
411 try {
return JSON.parse(Module.agentSendMessage(message)); }
412 catch(e) {
return {error: e.message}; }
414 return {error:
"API not ready"};
418 getChatHistory: function() {
419 if (Module.agentGetChatHistory) {
420 try {
return JSON.parse(Module.agentGetChatHistory()); }
421 catch(e) {
return {error: e.message}; }
423 return {error:
"API not ready"};
427 getConfig: function() {
428 if (Module.agentGetConfig) {
429 try {
return JSON.parse(Module.agentGetConfig()); }
430 catch(e) {
return {error: e.message}; }
432 return {error:
"API not ready"};
436 setConfig: function(config) {
437 if (Module.agentSetConfig) {
438 try {
return JSON.parse(Module.agentSetConfig(JSON.stringify(config))); }
439 catch(e) {
return {error: e.message}; }
441 return {error:
"API not ready"};
445 getProviders: function() {
446 if (Module.agentGetProviders) {
447 try {
return JSON.parse(Module.agentGetProviders()); }
448 catch(e) {
return {error: e.message}; }
450 return {error:
"API not ready"};
454 getProposals: function() {
455 if (Module.agentGetProposals) {
456 try {
return JSON.parse(Module.agentGetProposals()); }
457 catch(e) {
return {error: e.message}; }
459 return {error:
"API not ready"};
463 acceptProposal: function(proposalId) {
464 if (Module.agentAcceptProposal) {
465 try {
return JSON.parse(Module.agentAcceptProposal(proposalId)); }
466 catch(e) {
return {error: e.message}; }
468 return {error:
"API not ready"};
472 rejectProposal: function(proposalId) {
473 if (Module.agentRejectProposal) {
474 try {
return JSON.parse(Module.agentRejectProposal(proposalId)); }
475 catch(e) {
return {error: e.message}; }
477 return {error:
"API not ready"};
481 getProposalDetails: function(proposalId) {
482 if (Module.agentGetProposalDetails) {
483 try {
return JSON.parse(Module.agentGetProposalDetails(proposalId)); }
484 catch(e) {
return {error: e.message}; }
486 return {error:
"API not ready"};
490 openSidebar: function() {
491 if (Module.agentOpenSidebar) {
492 try {
return JSON.parse(Module.agentOpenSidebar()); }
493 catch(e) {
return {error: e.message}; }
495 return {error:
"API not ready"};
498 closeSidebar: function() {
499 if (Module.agentCloseSidebar) {
500 try {
return JSON.parse(Module.agentCloseSidebar()); }
501 catch(e) {
return {error: e.message}; }
503 return {error:
"API not ready"};
507 isReady: function() {
508 return Module.agentIsReady ? Module.agentIsReady() :
false;
512 console.log(
"[yaze] window.yaze.control API initialized");
513 console.log(
"[yaze] window.yaze.editor API initialized");
514 console.log(
"[yaze] window.yaze.data API initialized");
515 console.log(
"[yaze] window.yaze.agent API initialized");
522void WasmControlApi::Initialize(editor::EditorManager* editor_manager) {
523 editor_manager_ = editor_manager;
524 initialized_ = (editor_manager_ !=
nullptr);
527 SetupJavaScriptBindings();
528 LOG_INFO(
"WasmControlApi",
"Control API initialized");
532bool WasmControlApi::IsReady() {
533 return initialized_ && editor_manager_ !=
nullptr;
536std::string WasmControlApi::ToggleMenuBar() {
537 nlohmann::json result;
539 result[
"success"] =
false;
540 result[
"error"] =
"Control API not initialized";
541 return result.dump();
544 auto* ui = editor_manager_->ui_coordinator();
545 ui->SetMenuBarVisible(!ui->IsMenuBarVisible());
547 result[
"success"] =
true;
548 result[
"visible"] = ui->IsMenuBarVisible();
550 return result.dump();
553void WasmControlApi::SetupJavaScriptBindings() {
554 SetupYazeControlApi();
561editor::PanelManager* WasmControlApi::GetPanelRegistry() {
562 if (!IsReady() || !editor_manager_) {
565 return &editor_manager_->card_registry();
568std::string WasmControlApi::EditorTypeToString(
int type) {
575int WasmControlApi::StringToEditorType(
const std::string& name) {
578 return static_cast<int>(i);
588std::string WasmControlApi::SwitchEditor(
const std::string& editor_name) {
589 nlohmann::json result;
592 result[
"success"] =
false;
593 result[
"error"] =
"Control API not initialized";
594 return result.dump();
597 int editor_type = StringToEditorType(editor_name);
598 if (editor_type == 0 && editor_name !=
"Unknown") {
599 result[
"success"] =
false;
600 result[
"error"] =
"Unknown editor: " + editor_name;
601 return result.dump();
606 result[
"success"] =
true;
607 result[
"editor"] = editor_name;
608 return result.dump();
611std::string WasmControlApi::GetCurrentEditor() {
612 nlohmann::json result;
615 result[
"error"] =
"Control API not initialized";
616 return result.dump();
619 auto* current = editor_manager_->GetCurrentEditor();
621 result[
"name"] = EditorTypeToString(
static_cast<int>(current->type()));
622 result[
"type"] =
static_cast<int>(current->type());
623 result[
"active"] = *current->active();
625 result[
"name"] =
"None";
627 result[
"active"] =
false;
630 return result.dump();
633std::string WasmControlApi::GetAvailableEditors() {
634 nlohmann::json result = nlohmann::json::array();
637 nlohmann::json editor_info;
639 editor_info[
"type"] =
static_cast<int>(i);
640 result.push_back(editor_info);
643 return result.dump();
650std::string WasmControlApi::OpenPanel(
const std::string& card_id) {
651 nlohmann::json result;
654 result[
"success"] =
false;
655 result[
"error"] =
"Control API not initialized";
656 return result.dump();
659 auto* registry = GetPanelRegistry();
662 constexpr size_t session_id = 0;
663 bool found = registry->ShowPanel(session_id, card_id);
665 result[
"success"] = found;
666 result[
"card_id"] = card_id;
667 result[
"visible"] =
true;
669 result[
"error"] =
"Panel not found";
672 result[
"success"] =
false;
673 result[
"error"] =
"Panel registry not available";
676 LOG_INFO(
"WasmControlApi",
"OpenPanel: %s", card_id.c_str());
677 return result.dump();
680std::string WasmControlApi::ClosePanel(
const std::string& card_id) {
681 nlohmann::json result;
684 result[
"success"] =
false;
685 result[
"error"] =
"Control API not initialized";
686 return result.dump();
689 auto* registry = GetPanelRegistry();
691 constexpr size_t session_id = 0;
692 bool found = registry->HidePanel(session_id, card_id);
694 result[
"success"] = found;
695 result[
"card_id"] = card_id;
696 result[
"visible"] =
false;
698 result[
"error"] =
"Panel not found";
701 result[
"success"] =
false;
702 result[
"error"] =
"Panel registry not available";
705 LOG_INFO(
"WasmControlApi",
"ClosePanel: %s", card_id.c_str());
706 return result.dump();
709std::string WasmControlApi::TogglePanel(
const std::string& card_id) {
710 nlohmann::json result;
713 result[
"success"] =
false;
714 result[
"error"] =
"Control API not initialized";
715 return result.dump();
718 auto* registry = GetPanelRegistry();
720 constexpr size_t session_id = 0;
721 bool found = registry->TogglePanel(session_id, card_id);
723 result[
"success"] = found;
724 result[
"card_id"] = card_id;
726 result[
"error"] =
"Panel not found";
728 result[
"visible"] = registry->IsPanelVisible(session_id, card_id);
731 result[
"success"] =
false;
732 result[
"error"] =
"Panel registry not available";
735 LOG_INFO(
"WasmControlApi",
"TogglePanel: %s", card_id.c_str());
736 return result.dump();
739std::string WasmControlApi::GetVisiblePanels() {
740 nlohmann::json result = nlohmann::json::array();
743 return result.dump();
746 auto* registry = GetPanelRegistry();
748 return result.dump();
752 constexpr size_t session_id = 0;
753 auto card_ids = registry->GetPanelsInSession(session_id);
754 for (
const auto& card_id : card_ids) {
756 std::string base_id = card_id;
757 if (base_id.size() > 3 && base_id[0] ==
's' && base_id[2] ==
'.') {
758 base_id = base_id.substr(3);
760 if (registry->IsPanelVisible(session_id, base_id)) {
761 result.push_back(base_id);
765 return result.dump();
768std::string WasmControlApi::GetAvailablePanels() {
769 nlohmann::json result = nlohmann::json::array();
772 return result.dump();
775 auto* registry = GetPanelRegistry();
777 return result.dump();
781 constexpr size_t session_id = 0;
782 auto categories = registry->GetAllCategories(session_id);
784 for (
const auto& category : categories) {
785 auto panels = registry->GetPanelsInCategory(session_id, category);
786 for (
const auto& panel : panels) {
787 nlohmann::json card_json;
788 card_json[
"id"] = panel.card_id;
789 card_json[
"display_name"] = panel.display_name;
790 card_json[
"window_title"] = panel.window_title;
791 card_json[
"icon"] = panel.icon;
792 card_json[
"category"] = panel.category;
793 card_json[
"priority"] = panel.priority;
794 card_json[
"visible"] = registry->IsPanelVisible(session_id, panel.card_id);
795 card_json[
"shortcut_hint"] = panel.shortcut_hint;
796 if (panel.enabled_condition) {
797 card_json[
"enabled"] = panel.enabled_condition();
799 card_json[
"enabled"] =
true;
801 result.push_back(card_json);
805 return result.dump();
808std::string WasmControlApi::GetPanelsInCategory(
const std::string& category) {
809 nlohmann::json result = nlohmann::json::array();
812 return result.dump();
815 auto* registry = GetPanelRegistry();
817 return result.dump();
821 constexpr size_t session_id = 0;
822 auto panels = registry->GetPanelsInCategory(session_id, category);
824 for (
const auto& panel : panels) {
825 nlohmann::json card_json;
826 card_json[
"id"] = panel.card_id;
827 card_json[
"display_name"] = panel.display_name;
828 card_json[
"window_title"] = panel.window_title;
829 card_json[
"icon"] = panel.icon;
830 card_json[
"category"] = panel.category;
831 card_json[
"priority"] = panel.priority;
832 card_json[
"visible"] = registry->IsPanelVisible(session_id, panel.card_id);
833 result.push_back(card_json);
836 return result.dump();
839std::string WasmControlApi::ShowAllPanels() {
840 nlohmann::json result;
843 result[
"success"] =
false;
844 result[
"error"] =
"Control API not initialized";
845 return result.dump();
848 auto* registry = GetPanelRegistry();
850 constexpr size_t session_id = 0;
851 registry->ShowAllPanelsInSession(session_id);
852 result[
"success"] =
true;
854 result[
"success"] =
false;
855 result[
"error"] =
"Panel registry not available";
858 return result.dump();
861std::string WasmControlApi::HideAllPanels() {
862 nlohmann::json result;
865 result[
"success"] =
false;
866 result[
"error"] =
"Control API not initialized";
867 return result.dump();
870 auto* registry = GetPanelRegistry();
872 constexpr size_t session_id = 0;
873 registry->HideAllPanelsInSession(session_id);
874 result[
"success"] =
true;
876 result[
"success"] =
false;
877 result[
"error"] =
"Panel registry not available";
880 return result.dump();
883std::string WasmControlApi::ShowAllPanelsInCategory(
const std::string& category) {
884 nlohmann::json result;
887 result[
"success"] =
false;
888 result[
"error"] =
"Control API not initialized";
889 return result.dump();
892 auto* registry = GetPanelRegistry();
894 constexpr size_t session_id = 0;
895 registry->ShowAllPanelsInCategory(session_id, category);
896 result[
"success"] =
true;
899 result[
"success"] =
false;
900 result[
"error"] =
"Panel registry not available";
903 return result.dump();
906std::string WasmControlApi::HideAllPanelsInCategory(
const std::string& category) {
907 nlohmann::json result;
910 result[
"success"] =
false;
911 result[
"error"] =
"Control API not initialized";
912 return result.dump();
915 auto* registry = GetPanelRegistry();
917 constexpr size_t session_id = 0;
918 registry->HideAllPanelsInCategory(session_id, category);
919 result[
"success"] =
true;
922 result[
"success"] =
false;
923 result[
"error"] =
"Panel registry not available";
926 return result.dump();
929std::string WasmControlApi::ShowOnlyPanel(
const std::string& card_id) {
930 nlohmann::json result;
933 result[
"success"] =
false;
934 result[
"error"] =
"Control API not initialized";
935 return result.dump();
938 auto* registry = GetPanelRegistry();
940 constexpr size_t session_id = 0;
941 registry->ShowOnlyPanel(session_id, card_id);
942 result[
"success"] =
true;
943 result[
"card_id"] = card_id;
945 result[
"success"] =
false;
946 result[
"error"] =
"Panel registry not available";
949 return result.dump();
956std::string WasmControlApi::SetPanelLayout(
const std::string& layout_name) {
957 nlohmann::json result;
960 result[
"success"] =
false;
961 result[
"error"] =
"Control API not initialized";
962 return result.dump();
965 auto* registry = GetPanelRegistry();
967 result[
"success"] =
false;
968 result[
"error"] =
"Panel registry not available";
969 return result.dump();
972 size_t session_id = registry->GetActiveSessionId();
975 if (layout_name ==
"overworld_default") {
976 registry->HideAllPanelsInSession(session_id);
977 registry->ShowAllPanelsInCategory(session_id,
"Overworld");
978 registry->SetActiveCategory(
"Overworld");
979 }
else if (layout_name ==
"dungeon_default") {
980 registry->HideAllPanelsInSession(session_id);
981 registry->ShowAllPanelsInCategory(session_id,
"Dungeon");
982 registry->SetActiveCategory(
"Dungeon");
983 }
else if (layout_name ==
"graphics_default") {
984 registry->HideAllPanelsInSession(session_id);
985 registry->ShowAllPanelsInCategory(session_id,
"Graphics");
986 registry->SetActiveCategory(
"Graphics");
987 }
else if (layout_name ==
"debug_default") {
988 registry->HideAllPanelsInSession(session_id);
989 registry->ShowAllPanelsInCategory(session_id,
"Debug");
990 registry->SetActiveCategory(
"Debug");
991 }
else if (layout_name ==
"minimal") {
992 registry->HideAllPanelsInSession(session_id);
994 }
else if (layout_name ==
"all_cards") {
995 registry->ShowAllPanelsInSession(session_id);
998 if (!registry->LoadPreset(layout_name)) {
999 result[
"success"] =
false;
1000 result[
"error"] =
"Unknown layout: " + layout_name;
1001 return result.dump();
1005 result[
"success"] =
true;
1006 result[
"layout"] = layout_name;
1008 LOG_INFO(
"WasmControlApi",
"SetPanelLayout: %s", layout_name.c_str());
1009 return result.dump();
1012std::string WasmControlApi::GetAvailableLayouts() {
1013 nlohmann::json result = nlohmann::json::array();
1016 result.push_back(
"overworld_default");
1017 result.push_back(
"dungeon_default");
1018 result.push_back(
"graphics_default");
1019 result.push_back(
"debug_default");
1020 result.push_back(
"minimal");
1021 result.push_back(
"all_cards");
1023 return result.dump();
1026std::string WasmControlApi::SaveCurrentLayout(
const std::string& layout_name) {
1027 nlohmann::json result;
1030 result[
"success"] =
false;
1031 result[
"error"] =
"Control API not initialized";
1032 return result.dump();
1036 result[
"success"] =
true;
1037 result[
"layout"] = layout_name;
1039 return result.dump();
1046std::string WasmControlApi::TriggerMenuAction(
const std::string& action_path) {
1047 nlohmann::json result;
1050 result[
"success"] =
false;
1051 result[
"error"] =
"Control API not initialized";
1052 return result.dump();
1055 auto* registry = GetPanelRegistry();
1058 if (action_path ==
"File.Save") {
1059 auto status = editor_manager_->SaveRom();
1060 result[
"success"] = status.ok();
1062 result[
"error"] = status.ToString();
1064 }
else if (action_path ==
"File.Open") {
1066 registry->TriggerOpenRom();
1067 result[
"success"] =
true;
1069 result[
"success"] =
false;
1070 result[
"error"] =
"Panel registry not available";
1074 else if (action_path ==
"Edit.Undo") {
1076 registry->TriggerUndo();
1077 result[
"success"] =
true;
1079 result[
"success"] =
false;
1080 result[
"error"] =
"Panel registry not available";
1082 }
else if (action_path ==
"Edit.Redo") {
1084 registry->TriggerRedo();
1085 result[
"success"] =
true;
1087 result[
"success"] =
false;
1088 result[
"error"] =
"Panel registry not available";
1092 else if (action_path ==
"View.ShowEmulator") {
1093 editor_manager_->ui_coordinator()->SetEmulatorVisible(
true);
1094 result[
"success"] =
true;
1095 }
else if (action_path ==
"View.HideEmulator") {
1096 editor_manager_->ui_coordinator()->SetEmulatorVisible(
false);
1097 result[
"success"] =
true;
1098 }
else if (action_path ==
"View.ToggleEmulator") {
1099 auto* ui = editor_manager_->ui_coordinator();
1100 ui->SetEmulatorVisible(!ui->IsEmulatorVisible());
1101 result[
"success"] =
true;
1102 result[
"visible"] = ui->IsEmulatorVisible();
1103 }
else if (action_path ==
"View.ShowWelcome") {
1104 editor_manager_->ui_coordinator()->SetWelcomeScreenVisible(
true);
1105 result[
"success"] =
true;
1106 }
else if (action_path ==
"View.ShowPanelBrowser") {
1108 registry->TriggerShowPanelBrowser();
1109 result[
"success"] =
true;
1111 result[
"success"] =
false;
1112 result[
"error"] =
"Panel registry not available";
1114 }
else if (action_path ==
"View.ShowSettings") {
1116 registry->TriggerShowSettings();
1117 result[
"success"] =
true;
1119 result[
"success"] =
false;
1120 result[
"error"] =
"Panel registry not available";
1124 else if (action_path ==
"Tools.GlobalSearch") {
1126 registry->TriggerShowSearch();
1127 result[
"success"] =
true;
1129 result[
"success"] =
false;
1130 result[
"error"] =
"Panel registry not available";
1132 }
else if (action_path ==
"Tools.CommandPalette") {
1134 registry->TriggerShowCommandPalette();
1135 result[
"success"] =
true;
1137 result[
"success"] =
false;
1138 result[
"error"] =
"Panel registry not available";
1140 }
else if (action_path ==
"Tools.ShowShortcuts") {
1142 registry->TriggerShowShortcuts();
1143 result[
"success"] =
true;
1145 result[
"success"] =
false;
1146 result[
"error"] =
"Panel registry not available";
1150 else if (action_path ==
"Help.ShowHelp") {
1152 registry->TriggerShowHelp();
1153 result[
"success"] =
true;
1155 result[
"success"] =
false;
1156 result[
"error"] =
"Panel registry not available";
1161 result[
"success"] =
false;
1162 result[
"error"] =
"Unknown action: " + action_path;
1165 return result.dump();
1168std::string WasmControlApi::GetAvailableMenuActions() {
1169 nlohmann::json result = nlohmann::json::array();
1172 result.push_back(
"File.Open");
1173 result.push_back(
"File.Save");
1174 result.push_back(
"File.SaveAs");
1175 result.push_back(
"File.NewProject");
1176 result.push_back(
"File.OpenProject");
1179 result.push_back(
"Edit.Undo");
1180 result.push_back(
"Edit.Redo");
1181 result.push_back(
"Edit.Cut");
1182 result.push_back(
"Edit.Copy");
1183 result.push_back(
"Edit.Paste");
1186 result.push_back(
"View.ShowEmulator");
1187 result.push_back(
"View.ShowWelcome");
1188 result.push_back(
"View.ShowPanelBrowser");
1189 result.push_back(
"View.ShowMemoryEditor");
1190 result.push_back(
"View.ShowHexEditor");
1193 result.push_back(
"Tools.GlobalSearch");
1194 result.push_back(
"Tools.CommandPalette");
1196 return result.dump();
1203std::string WasmControlApi::GetSessionInfo() {
1204 nlohmann::json result;
1207 result[
"error"] =
"Control API not initialized";
1208 return result.dump();
1211 result[
"session_index"] = editor_manager_->GetCurrentSessionIndex();
1212 result[
"session_count"] = editor_manager_->GetActiveSessionCount();
1214 auto* rom = editor_manager_->GetCurrentRom();
1215 if (rom && rom->is_loaded()) {
1216 result[
"rom_loaded"] =
true;
1217 result[
"rom_filename"] = rom->filename();
1218 result[
"rom_title"] = rom->title();
1220 result[
"rom_loaded"] =
false;
1223 auto* current_editor = editor_manager_->GetCurrentEditor();
1224 if (current_editor) {
1225 result[
"current_editor"] = EditorTypeToString(
static_cast<int>(current_editor->type()));
1228 return result.dump();
1231std::string WasmControlApi::CreateSession() {
1232 nlohmann::json result;
1235 result[
"success"] =
false;
1236 result[
"error"] =
"Control API not initialized";
1237 return result.dump();
1240 editor_manager_->CreateNewSession();
1241 result[
"success"] =
true;
1242 result[
"session_index"] = editor_manager_->GetCurrentSessionIndex();
1244 return result.dump();
1247std::string WasmControlApi::SwitchSession(
int session_index) {
1248 nlohmann::json result;
1251 result[
"success"] =
false;
1252 result[
"error"] =
"Control API not initialized";
1253 return result.dump();
1256 if (session_index < 0 ||
static_cast<size_t>(session_index) >= editor_manager_->GetActiveSessionCount()) {
1257 result[
"success"] =
false;
1258 result[
"error"] =
"Invalid session index";
1259 return result.dump();
1262 editor_manager_->SwitchToSession(
static_cast<size_t>(session_index));
1263 result[
"success"] =
true;
1264 result[
"session_index"] = session_index;
1266 return result.dump();
1273std::string WasmControlApi::GetRomStatus() {
1274 nlohmann::json result;
1277 result[
"error"] =
"Control API not initialized";
1278 return result.dump();
1281 auto* rom = editor_manager_->GetCurrentRom();
1282 if (rom && rom->is_loaded()) {
1283 result[
"loaded"] =
true;
1284 result[
"filename"] = rom->filename();
1285 result[
"title"] = rom->title();
1286 result[
"size"] = rom->size();
1287 result[
"dirty"] = rom->dirty();
1289 result[
"loaded"] =
false;
1292 return result.dump();
1295std::string WasmControlApi::ReadRomBytes(
int address,
int count) {
1296 nlohmann::json result;
1299 result[
"error"] =
"Control API not initialized";
1300 return result.dump();
1303 auto* rom = editor_manager_->GetCurrentRom();
1304 if (!rom || !rom->is_loaded()) {
1305 result[
"error"] =
"No ROM loaded";
1306 return result.dump();
1310 count = std::min(count, 256);
1312 if (address < 0 ||
static_cast<size_t>(address + count) > rom->size()) {
1313 result[
"error"] =
"Address out of range";
1314 return result.dump();
1317 result[
"address"] = address;
1318 result[
"count"] = count;
1320 nlohmann::json bytes = nlohmann::json::array();
1321 for (
int i = 0; i < count; ++i) {
1322 auto byte_result = rom->ReadByte(address + i);
1323 if (byte_result.ok()) {
1324 bytes.push_back(*byte_result);
1329 result[
"bytes"] = bytes;
1331 return result.dump();
1334std::string WasmControlApi::WriteRomBytes(
int address,
const std::string& bytes_json) {
1335 nlohmann::json result;
1338 result[
"success"] =
false;
1339 result[
"error"] =
"Control API not initialized";
1340 return result.dump();
1343 auto* rom = editor_manager_->GetCurrentRom();
1344 if (!rom || !rom->is_loaded()) {
1345 result[
"success"] =
false;
1346 result[
"error"] =
"No ROM loaded";
1347 return result.dump();
1351 auto bytes = nlohmann::json::parse(bytes_json);
1352 if (!bytes.is_array()) {
1353 result[
"success"] =
false;
1354 result[
"error"] =
"Invalid bytes format - expected array";
1355 return result.dump();
1358 for (
size_t i = 0; i < bytes.size(); ++i) {
1359 uint8_t value = bytes[i].get<uint8_t>();
1360 auto status = rom->WriteByte(address +
static_cast<int>(i), value);
1362 result[
"success"] =
false;
1363 result[
"error"] = status.ToString();
1364 return result.dump();
1368 result[
"success"] =
true;
1369 result[
"bytes_written"] = bytes.size();
1371 }
catch (
const std::exception& e) {
1372 result[
"success"] =
false;
1373 result[
"error"] = e.what();
1376 return result.dump();
1379std::string WasmControlApi::SaveRom() {
1380 nlohmann::json result;
1383 result[
"success"] =
false;
1384 result[
"error"] =
"Control API not initialized";
1385 return result.dump();
1388 auto status = editor_manager_->SaveRom();
1389 result[
"success"] = status.ok();
1391 result[
"error"] = status.ToString();
1394 return result.dump();
1401std::string WasmControlApi::GetEditorSnapshot() {
1402 nlohmann::json result;
1405 result[
"error"] =
"Control API not initialized";
1406 return result.dump();
1409 auto* current = editor_manager_->GetCurrentEditor();
1411 result[
"editor_type"] =
"none";
1412 result[
"active"] =
false;
1413 return result.dump();
1416 result[
"editor_type"] = EditorTypeToString(
static_cast<int>(current->type()));
1417 result[
"editor_type_id"] =
static_cast<int>(current->type());
1418 result[
"active"] = *current->active();
1421 auto* rom = editor_manager_->GetCurrentRom();
1422 if (rom && rom->is_loaded()) {
1423 result[
"rom_loaded"] =
true;
1424 result[
"rom_title"] = rom->title();
1426 result[
"rom_loaded"] =
false;
1430 nlohmann::json active_data;
1431 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1434 auto* dungeon = editor_set->GetDungeonEditor();
1436 active_data[
"current_room_id"] = dungeon->current_room_id();
1438 nlohmann::json active_rooms = nlohmann::json::array();
1439 for (
int i = 0; i < dungeon->active_rooms().size(); ++i) {
1440 active_rooms.push_back(dungeon->active_rooms()[i]);
1442 active_data[
"active_rooms"] = active_rooms;
1443 active_data[
"room_count"] = dungeon->active_rooms().size();
1447 auto* overworld = editor_set->GetOverworldEditor();
1449 active_data[
"current_map"] = overworld->overworld().current_map_id();
1450 active_data[
"current_world"] = overworld->overworld().current_world();
1455 result[
"active_data"] = active_data;
1457 return result.dump();
1460std::string WasmControlApi::GetCurrentDungeonRoom() {
1461 nlohmann::json result;
1464 result[
"error"] =
"Control API not initialized";
1465 return result.dump();
1468 auto* current = editor_manager_->GetCurrentEditor();
1470 result[
"error"] =
"Dungeon editor not active";
1471 result[
"editor_type"] = current ? EditorTypeToString(
static_cast<int>(current->type())) :
"none";
1472 return result.dump();
1475 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1477 result[
"error"] =
"No editor set available";
1478 return result.dump();
1481 auto* dungeon = editor_set->GetDungeonEditor();
1483 result[
"error"] =
"Dungeon editor not available";
1484 return result.dump();
1486 result[
"room_id"] = dungeon->current_room_id();
1489 nlohmann::json active_rooms = nlohmann::json::array();
1490 for (
int i = 0; i < dungeon->active_rooms().size(); ++i) {
1491 active_rooms.push_back(dungeon->active_rooms()[i]);
1493 result[
"active_rooms"] = active_rooms;
1494 result[
"room_count"] = dungeon->active_rooms().size();
1497 nlohmann::json cards;
1507 result[
"visible_cards"] = cards;
1509 return result.dump();
1512std::string WasmControlApi::GetCurrentOverworldMap() {
1513 nlohmann::json result;
1516 result[
"error"] =
"Control API not initialized";
1517 return result.dump();
1520 auto* current = editor_manager_->GetCurrentEditor();
1522 result[
"error"] =
"Overworld editor not active";
1523 result[
"editor_type"] = current ? EditorTypeToString(
static_cast<int>(current->type())) :
"none";
1524 return result.dump();
1527 auto* editor_set = editor_manager_->GetCurrentEditorSet();
1529 result[
"error"] =
"No editor set available";
1530 return result.dump();
1533 auto* overworld = editor_set->GetOverworldEditor();
1535 result[
"error"] =
"Overworld editor not available";
1536 return result.dump();
1538 auto& ow_data = overworld->overworld();
1540 result[
"map_id"] = ow_data.current_map_id();
1541 result[
"world"] = ow_data.current_world();
1542 result[
"world_name"] = ow_data.current_world() == 0 ?
"Light World" :
1543 (ow_data.current_world() == 1 ?
"Dark World" :
"Special World");
1546 return result.dump();
1549std::string WasmControlApi::GetEditorSelection() {
1550 nlohmann::json result;
1553 result[
"error"] =
"Control API not initialized";
1554 return result.dump();
1557 auto* current = editor_manager_->GetCurrentEditor();
1559 result[
"error"] =
"No editor active";
1560 return result.dump();
1563 result[
"editor_type"] = EditorTypeToString(
static_cast<int>(current->type()));
1564 result[
"selection"] = nlohmann::json::array();
1568 result[
"has_selection"] =
false;
1570 return result.dump();
1577std::string WasmControlApi::GetRoomTileData(
int room_id) {
1578 nlohmann::json result;
1581 result[
"error"] =
"Control API not initialized";
1582 return result.dump();
1585 if (room_id < 0 || room_id >= 296) {
1586 result[
"error"] =
"Invalid room ID (must be 0-295)";
1587 return result.dump();
1590 auto* rom = editor_manager_->GetCurrentRom();
1591 if (!rom || !rom->is_loaded()) {
1592 result[
"error"] =
"ROM not loaded";
1593 return result.dump();
1598 auto* game_data = editor_manager_->GetCurrentGameData();
1600 room.SetGameData(game_data);
1602 room.LoadRoomGraphics();
1605 result[
"room_id"] = room_id;
1606 result[
"width"] = 512;
1607 result[
"height"] = 512;
1610 const auto& layout = room.GetLayout();
1611 const auto& layout_objects = layout.GetObjects();
1614 nlohmann::json layer1_tiles = nlohmann::json::array();
1615 nlohmann::json layer2_tiles = nlohmann::json::array();
1617 for (
const auto& obj : layout_objects) {
1618 nlohmann::json tile_obj;
1619 tile_obj[
"x"] = obj.x();
1620 tile_obj[
"y"] = obj.y();
1622 auto tile_result = obj.GetTile(0);
1623 if (tile_result.ok()) {
1624 const auto* tile_info = tile_result.value();
1625 tile_obj[
"tile_id"] = tile_info->id_;
1626 tile_obj[
"palette"] = tile_info->palette_;
1627 tile_obj[
"priority"] = tile_info->over_;
1628 tile_obj[
"h_flip"] = tile_info->horizontal_mirror_;
1629 tile_obj[
"v_flip"] = tile_info->vertical_mirror_;
1631 if (obj.GetLayerValue() == 1) {
1632 layer2_tiles.push_back(tile_obj);
1634 layer1_tiles.push_back(tile_obj);
1639 result[
"layer1"] = layer1_tiles;
1640 result[
"layer2"] = layer2_tiles;
1641 result[
"layer1_count"] = layer1_tiles.size();
1642 result[
"layer2_count"] = layer2_tiles.size();
1644 return result.dump();
1647std::string WasmControlApi::GetRoomObjects(
int room_id) {
1648 nlohmann::json result = nlohmann::json::array();
1651 nlohmann::json error;
1652 error[
"error"] =
"Control API not initialized";
1653 return error.dump();
1656 if (room_id < 0 || room_id >= 296) {
1657 nlohmann::json error;
1658 error[
"error"] =
"Invalid room ID (must be 0-295)";
1659 return error.dump();
1662 auto* rom = editor_manager_->GetCurrentRom();
1663 if (!rom || !rom->is_loaded()) {
1664 nlohmann::json error;
1665 error[
"error"] =
"ROM not loaded";
1666 return error.dump();
1674 const auto& tile_objects = room.GetTileObjects();
1676 for (
const auto& obj : tile_objects) {
1677 nlohmann::json obj_data;
1678 obj_data[
"id"] = obj.id_;
1679 obj_data[
"x"] = obj.x();
1680 obj_data[
"y"] = obj.y();
1681 obj_data[
"size"] = obj.size();
1682 obj_data[
"layer"] = obj.GetLayerValue();
1685 auto options =
static_cast<int>(obj.options());
1692 result.push_back(obj_data);
1695 return result.dump();
1698std::string WasmControlApi::GetRoomProperties(
int room_id) {
1699 nlohmann::json result;
1702 result[
"error"] =
"Control API not initialized";
1703 return result.dump();
1706 if (room_id < 0 || room_id >= 296) {
1707 result[
"error"] =
"Invalid room ID (must be 0-295)";
1708 return result.dump();
1711 auto* rom = editor_manager_->GetCurrentRom();
1712 if (!rom || !rom->is_loaded()) {
1713 result[
"error"] =
"ROM not loaded";
1714 return result.dump();
1720 result[
"room_id"] = room_id;
1721 result[
"blockset"] = room.blockset;
1722 result[
"spriteset"] = room.spriteset;
1723 result[
"palette"] = room.palette;
1724 result[
"floor1"] = room.floor1();
1725 result[
"floor2"] = room.floor2();
1726 result[
"layout"] = room.layout;
1727 result[
"holewarp"] = room.holewarp;
1728 result[
"message_id"] = room.message_id_;
1731 result[
"effect"] =
static_cast<int>(room.effect());
1732 result[
"tag1"] =
static_cast<int>(room.tag1());
1733 result[
"tag2"] =
static_cast<int>(room.tag2());
1734 result[
"collision"] =
static_cast<int>(room.collision());
1737 const auto& layer_merge = room.layer_merging();
1738 result[
"layer_merging"] = {
1739 {
"id", layer_merge.ID},
1740 {
"name", layer_merge.Name},
1741 {
"layer2_visible", layer_merge.Layer2Visible},
1742 {
"layer2_on_top", layer_merge.Layer2OnTop},
1743 {
"layer2_translucent", layer_merge.Layer2Translucent}
1746 result[
"is_light"] = room.IsLight();
1747 result[
"is_loaded"] = room.IsLoaded();
1749 return result.dump();
1752std::string WasmControlApi::GetMapTileData(
int map_id) {
1753 nlohmann::json result;
1756 result[
"error"] =
"Control API not initialized";
1757 return result.dump();
1761 result[
"error"] =
"Invalid map ID (must be 0-159)";
1762 return result.dump();
1765 auto* overworld = editor_manager_->overworld();
1767 result[
"error"] =
"Overworld not loaded";
1768 return result.dump();
1771 auto* map = overworld->overworld_map(map_id);
1773 result[
"error"] =
"Map not found";
1774 return result.dump();
1777 result[
"map_id"] = map_id;
1778 result[
"width"] = 32;
1779 result[
"height"] = 32;
1782 auto blockset = map->current_tile16_blockset();
1785 result[
"has_tile_data"] = !blockset.empty();
1786 result[
"tile_count"] = blockset.size();
1787 result[
"is_built"] = map->is_built();
1788 result[
"is_large_map"] = map->is_large_map();
1792 if (blockset.size() >= 64) {
1793 nlohmann::json sample_tiles = nlohmann::json::array();
1795 for (
int i = 0; i < 64; i++) {
1796 sample_tiles.push_back(
static_cast<int>(blockset[i]));
1798 result[
"sample_tiles"] = sample_tiles;
1799 result[
"sample_note"] =
"First 8x8 tiles from top-left corner";
1802 return result.dump();
1805std::string WasmControlApi::GetMapEntities(
int map_id) {
1806 nlohmann::json result;
1809 result[
"error"] =
"Control API not initialized";
1810 return result.dump();
1814 result[
"error"] =
"Invalid map ID (must be 0-159)";
1815 return result.dump();
1818 auto* overworld = editor_manager_->overworld();
1820 result[
"error"] =
"Overworld not loaded";
1821 return result.dump();
1824 result[
"map_id"] = map_id;
1825 result[
"entrances"] = nlohmann::json::array();
1826 result[
"exits"] = nlohmann::json::array();
1827 result[
"items"] = nlohmann::json::array();
1828 result[
"sprites"] = nlohmann::json::array();
1831 for (
const auto& entrance : overworld->entrances()) {
1832 if (entrance.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1834 e[
"id"] = entrance.entrance_id_;
1835 e[
"x"] = entrance.x_;
1836 e[
"y"] = entrance.y_;
1837 e[
"map_id"] = entrance.map_id_;
1838 result[
"entrances"].push_back(e);
1843 auto* exits = overworld->exits();
1845 for (
const auto& exit : *exits) {
1846 if (exit.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1850 ex[
"map_id"] = exit.map_id_;
1851 ex[
"room_id"] = exit.room_id_;
1852 result[
"exits"].push_back(ex);
1858 for (
const auto& item : overworld->all_items()) {
1859 if (item.map_id_ ==
static_cast<uint16_t
>(map_id)) {
1864 result[
"items"].push_back(i);
1868 return result.dump();
1871std::string WasmControlApi::GetMapProperties(
int map_id) {
1872 nlohmann::json result;
1875 result[
"error"] =
"Control API not initialized";
1876 return result.dump();
1880 result[
"error"] =
"Invalid map ID (must be 0-159)";
1881 return result.dump();
1884 auto* overworld = editor_manager_->overworld();
1886 result[
"error"] =
"Overworld not loaded";
1887 return result.dump();
1890 auto* map = overworld->overworld_map(map_id);
1892 result[
"error"] =
"Map not found";
1893 return result.dump();
1896 result[
"map_id"] = map_id;
1897 result[
"world"] = map_id / 64;
1898 result[
"parent_id"] = map->parent();
1899 result[
"area_graphics"] = map->area_graphics();
1900 result[
"area_palette"] = map->area_palette();
1901 result[
"sprite_graphics"] = {map->sprite_graphics(0), map->sprite_graphics(1), map->sprite_graphics(2)};
1902 result[
"sprite_palette"] = {map->sprite_palette(0), map->sprite_palette(1), map->sprite_palette(2)};
1903 result[
"message_id"] = map->message_id();
1904 result[
"is_large_map"] = map->is_large_map();
1906 return result.dump();
1909std::string WasmControlApi::GetPaletteData(
const std::string& group_name,
int palette_id) {
1910 nlohmann::json result;
1913 result[
"error"] =
"Control API not initialized";
1914 return result.dump();
1917 auto* rom = editor_manager_->GetCurrentRom();
1918 if (!rom || !rom->is_loaded()) {
1919 result[
"error"] =
"ROM not loaded";
1920 return result.dump();
1923 result[
"group"] = group_name;
1924 result[
"palette_id"] = palette_id;
1927 auto* game_data = editor_manager_->GetCurrentGameData();
1929 result[
"error"] =
"GameData not available";
1930 return result.dump();
1932 auto* group = game_data->palette_groups.get_group(group_name);
1935 result[
"error"] =
"Invalid palette group name";
1936 return result.dump();
1939 if (palette_id < 0 || palette_id >=
static_cast<int>(group->size())) {
1940 result[
"error"] =
"Invalid palette ID for this group";
1941 result[
"max_palette_id"] = group->size() - 1;
1942 return result.dump();
1945 auto palette = (*group)[palette_id];
1946 nlohmann::json colors = nlohmann::json::array();
1949 for (
size_t i = 0; i < palette.size(); i++) {
1950 const auto& color = palette[i];
1951 nlohmann::json color_data;
1952 color_data[
"index"] = i;
1956 auto rgb_color = color.rgb();
1959 int r =
static_cast<int>(rgb_color.x * 255);
1960 int g =
static_cast<int>(rgb_color.y * 255);
1961 int b =
static_cast<int>(rgb_color.z * 255);
1962 color_data[
"r"] = r;
1963 color_data[
"g"] = g;
1964 color_data[
"b"] = b;
1965 color_data[
"hex"] = absl::StrFormat(
"#%02X%02X%02X", r, g, b);
1968 colors.push_back(color_data);
1971 result[
"colors"] = colors;
1972 result[
"color_count"] = palette.size();
1974 }
catch (
const std::exception& e) {
1975 result[
"error"] = std::string(
"Failed to extract palette: ") + e.what();
1978 return result.dump();
1981std::string WasmControlApi::ListPaletteGroups() {
1982 nlohmann::json result = nlohmann::json::array();
1985 result.push_back(
"ow_main");
1986 result.push_back(
"ow_aux");
1987 result.push_back(
"ow_animated");
1988 result.push_back(
"hud");
1989 result.push_back(
"global_sprites");
1990 result.push_back(
"armors");
1991 result.push_back(
"swords");
1992 result.push_back(
"shields");
1993 result.push_back(
"sprites_aux1");
1994 result.push_back(
"sprites_aux2");
1995 result.push_back(
"sprites_aux3");
1996 result.push_back(
"dungeon_main");
1997 result.push_back(
"grass");
1998 result.push_back(
"3d_object");
1999 result.push_back(
"ow_mini_map");
2001 return result.dump();
2004std::string WasmControlApi::LoadFont(
const std::string& name,
const std::string& data,
float size) {
2005 nlohmann::json result;
2006 auto status = yaze::platform::WasmSettings::LoadUserFont(name, data, size);
2008 result[
"success"] =
true;
2010 result[
"success"] =
false;
2011 result[
"error"] = status.ToString();
2013 return result.dump();
2020std::string WasmControlApi::GetUIElementTree() {
2021 nlohmann::json result;
2024 result[
"error"] =
"Control API not initialized";
2025 result[
"elements"] = nlohmann::json::array();
2026 return result.dump();
2031 const auto& all_widgets = registry.GetAllWidgets();
2033 nlohmann::json elements = nlohmann::json::array();
2036 for (
const auto& [path, info] : all_widgets) {
2037 nlohmann::json elem;
2038 elem[
"id"] = info.full_path;
2039 elem[
"type"] = info.type;
2040 elem[
"label"] = info.label;
2041 elem[
"enabled"] = info.enabled;
2042 elem[
"visible"] = info.visible;
2043 elem[
"window"] = info.window_name;
2046 if (info.bounds.valid) {
2048 {
"x", info.bounds.min_x},
2049 {
"y", info.bounds.min_y},
2050 {
"width", info.bounds.max_x - info.bounds.min_x},
2051 {
"height", info.bounds.max_y - info.bounds.min_y}
2055 {
"x", 0}, {
"y", 0}, {
"width", 0}, {
"height", 0}
2060 if (!info.description.empty()) {
2061 elem[
"description"] = info.description;
2063 elem[
"imgui_id"] =
static_cast<uint32_t
>(info.imgui_id);
2064 elem[
"last_seen_frame"] = info.last_seen_frame;
2066 elements.push_back(elem);
2069 result[
"elements"] = elements;
2070 result[
"count"] = elements.size();
2071 result[
"source"] =
"WidgetIdRegistry";
2073 return result.dump();
2076std::string WasmControlApi::GetUIElementBounds(
const std::string& element_id) {
2077 nlohmann::json result;
2080 result[
"error"] =
"Control API not initialized";
2081 return result.dump();
2086 const auto* widget_info = registry.GetWidgetInfo(element_id);
2088 result[
"id"] = element_id;
2090 if (widget_info ==
nullptr) {
2091 result[
"found"] =
false;
2092 result[
"error"] =
"Element not found: " + element_id;
2093 return result.dump();
2096 result[
"found"] =
true;
2097 result[
"visible"] = widget_info->visible;
2098 result[
"enabled"] = widget_info->enabled;
2099 result[
"type"] = widget_info->type;
2100 result[
"label"] = widget_info->label;
2101 result[
"window"] = widget_info->window_name;
2104 if (widget_info->bounds.valid) {
2105 result[
"x"] = widget_info->bounds.min_x;
2106 result[
"y"] = widget_info->bounds.min_y;
2107 result[
"width"] = widget_info->bounds.max_x - widget_info->bounds.min_x;
2108 result[
"height"] = widget_info->bounds.max_y - widget_info->bounds.min_y;
2109 result[
"bounds_valid"] =
true;
2113 result[
"width"] = 0;
2114 result[
"height"] = 0;
2115 result[
"bounds_valid"] =
false;
2119 result[
"imgui_id"] =
static_cast<uint32_t
>(widget_info->imgui_id);
2120 result[
"last_seen_frame"] = widget_info->last_seen_frame;
2122 if (!widget_info->description.empty()) {
2123 result[
"description"] = widget_info->description;
2126 return result.dump();
2129std::string WasmControlApi::SetSelection(
const std::string& ids_json) {
2130 nlohmann::json result;
2133 result[
"success"] =
false;
2134 result[
"error"] =
"Control API not initialized";
2135 return result.dump();
2139 auto ids = nlohmann::json::parse(ids_json);
2143 result[
"success"] =
true;
2144 result[
"selected_ids"] = ids;
2145 result[
"note"] =
"Selection setting not yet fully implemented";
2147 }
catch (
const std::exception& e) {
2148 result[
"success"] =
false;
2149 result[
"error"] = std::string(
"Invalid JSON: ") + e.what();
2152 return result.dump();
2159std::string WasmControlApi::GetPlatformInfo() {
2160 nlohmann::json result;
2168 result[
"platform"] =
"Windows";
2171 result[
"platform"] =
"macOS";
2174 result[
"platform"] =
"Linux";
2177 result[
"platform"] =
"WebMac";
2180 result[
"platform"] =
"WebOther";
2183 result[
"platform"] =
"Unknown";
2191 result[
"shift_display"] =
"Shift";
2198 return result.dump();
2205bool WasmControlApi::AgentIsReady() {
2206 if (!initialized_ || !editor_manager_) {
2210 auto* agent_editor = editor_manager_->GetAgentEditor();
2211 return agent_editor !=
nullptr;
2214std::string WasmControlApi::AgentSendMessage(
const std::string& message) {
2215 nlohmann::json result;
2217 if (!initialized_ || !editor_manager_) {
2218 result[
"success"] =
false;
2219 result[
"error"] =
"API not initialized";
2220 return result.dump();
2223 auto* agent_editor = editor_manager_->GetAgentEditor();
2224 if (!agent_editor) {
2225 result[
"success"] =
false;
2226 result[
"error"] =
"Agent editor not available";
2227 return result.dump();
2230 auto* agent_chat = agent_editor->GetAgentChat();
2232 result[
"success"] =
false;
2233 result[
"error"] =
"Agent chat not available";
2234 return result.dump();
2239 result[
"success"] =
true;
2240 result[
"status"] =
"queued";
2241 result[
"message"] = message;
2246 return result.dump();
2249std::string WasmControlApi::AgentGetChatHistory() {
2250 nlohmann::json result = nlohmann::json::array();
2252 if (!initialized_ || !editor_manager_) {
2253 return result.dump();
2256 auto* agent_editor = editor_manager_->GetAgentEditor();
2257 if (!agent_editor) {
2258 return result.dump();
2261 auto* agent_chat = agent_editor->GetAgentChat();
2263 return result.dump();
2270 return result.dump();
2273std::string WasmControlApi::AgentGetConfig() {
2274 nlohmann::json result;
2276 if (!initialized_ || !editor_manager_) {
2277 result[
"error"] =
"API not initialized";
2278 return result.dump();
2281 auto* agent_editor = editor_manager_->GetAgentEditor();
2282 if (!agent_editor) {
2283 result[
"error"] =
"Agent editor not available";
2284 return result.dump();
2287 auto config = agent_editor->GetCurrentConfig();
2288 result[
"provider"] = config.provider;
2289 result[
"model"] = config.model;
2290 result[
"ollama_host"] = config.ollama_host;
2291 result[
"verbose"] = config.verbose;
2292 result[
"show_reasoning"] = config.show_reasoning;
2293 result[
"max_tool_iterations"] = config.max_tool_iterations;
2295 return result.dump();
2298std::string WasmControlApi::AgentSetConfig(
const std::string& config_json) {
2299 nlohmann::json result;
2301 if (!initialized_ || !editor_manager_) {
2302 result[
"success"] =
false;
2303 result[
"error"] =
"API not initialized";
2304 return result.dump();
2307 auto* agent_editor = editor_manager_->GetAgentEditor();
2308 if (!agent_editor) {
2309 result[
"success"] =
false;
2310 result[
"error"] =
"Agent editor not available";
2311 return result.dump();
2315 auto config_data = nlohmann::json::parse(config_json);
2317 editor::AgentEditor::AgentConfig config;
2318 if (config_data.contains(
"provider")) {
2319 config.provider = config_data[
"provider"].get<std::string>();
2321 if (config_data.contains(
"model")) {
2322 config.model = config_data[
"model"].get<std::string>();
2324 if (config_data.contains(
"ollama_host")) {
2325 config.ollama_host = config_data[
"ollama_host"].get<std::string>();
2327 if (config_data.contains(
"verbose")) {
2328 config.verbose = config_data[
"verbose"].get<
bool>();
2330 if (config_data.contains(
"show_reasoning")) {
2331 config.show_reasoning = config_data[
"show_reasoning"].get<
bool>();
2333 if (config_data.contains(
"max_tool_iterations")) {
2334 config.max_tool_iterations = config_data[
"max_tool_iterations"].get<
int>();
2337 agent_editor->ApplyConfig(config);
2338 result[
"success"] =
true;
2339 }
catch (
const std::exception& e) {
2340 result[
"success"] =
false;
2341 result[
"error"] = e.what();
2344 return result.dump();
2347std::string WasmControlApi::AgentGetProviders() {
2348 nlohmann::json result = nlohmann::json::array();
2353 {
"name",
"Mock Provider"},
2354 {
"description",
"Testing provider that echoes messages"}
2359 {
"description",
"Local Ollama server"},
2360 {
"requires_host",
true}
2364 {
"name",
"Google Gemini"},
2365 {
"description",
"Google's Gemini API"},
2366 {
"requires_api_key",
true}
2369 return result.dump();
2372std::string WasmControlApi::AgentGetProposals() {
2373 nlohmann::json result = nlohmann::json::array();
2375 if (!initialized_ || !editor_manager_) {
2376 return result.dump();
2382 return result.dump();
2385std::string WasmControlApi::AgentAcceptProposal(
const std::string& proposal_id) {
2386 nlohmann::json result;
2388 if (!initialized_ || !editor_manager_) {
2389 result[
"success"] =
false;
2390 result[
"error"] =
"API not initialized";
2391 return result.dump();
2395 result[
"success"] =
false;
2396 result[
"error"] =
"Proposal system not yet integrated";
2397 result[
"proposal_id"] = proposal_id;
2399 return result.dump();
2402std::string WasmControlApi::AgentRejectProposal(
const std::string& proposal_id) {
2403 nlohmann::json result;
2405 if (!initialized_ || !editor_manager_) {
2406 result[
"success"] =
false;
2407 result[
"error"] =
"API not initialized";
2408 return result.dump();
2412 result[
"success"] =
false;
2413 result[
"error"] =
"Proposal system not yet integrated";
2414 result[
"proposal_id"] = proposal_id;
2416 return result.dump();
2419std::string WasmControlApi::AgentGetProposalDetails(
const std::string& proposal_id) {
2420 nlohmann::json result;
2422 if (!initialized_ || !editor_manager_) {
2423 result[
"error"] =
"API not initialized";
2424 return result.dump();
2428 result[
"error"] =
"Proposal system not yet integrated";
2429 result[
"proposal_id"] = proposal_id;
2431 return result.dump();
2434std::string WasmControlApi::AgentOpenSidebar() {
2435 nlohmann::json result;
2437 if (!initialized_ || !editor_manager_) {
2438 result[
"success"] =
false;
2439 result[
"error"] =
"API not initialized";
2440 return result.dump();
2443 auto* agent_editor = editor_manager_->GetAgentEditor();
2444 if (!agent_editor) {
2445 result[
"success"] =
false;
2446 result[
"error"] =
"Agent editor not available";
2447 return result.dump();
2450 agent_editor->SetChatActive(
true);
2451 result[
"success"] =
true;
2452 result[
"sidebar_open"] =
true;
2454 return result.dump();
2457std::string WasmControlApi::AgentCloseSidebar() {
2458 nlohmann::json result;
2460 if (!initialized_ || !editor_manager_) {
2461 result[
"success"] =
false;
2462 result[
"error"] =
"API not initialized";
2463 return result.dump();
2466 auto* agent_editor = editor_manager_->GetAgentEditor();
2467 if (!agent_editor) {
2468 result[
"success"] =
false;
2469 result[
"error"] =
"Agent editor not available";
2470 return result.dump();
2473 agent_editor->SetChatActive(
false);
2474 result[
"success"] =
true;
2475 result[
"sidebar_open"] =
false;
2477 return result.dump();
2485 emscripten::function(
"controlIsReady", &WasmControlApi::IsReady);
2486 emscripten::function(
"controlSwitchEditor", &WasmControlApi::SwitchEditor);
2487 emscripten::function(
"controlGetCurrentEditor", &WasmControlApi::GetCurrentEditor);
2488 emscripten::function(
"controlGetAvailableEditors", &WasmControlApi::GetAvailableEditors);
2489 emscripten::function(
"controlOpenPanel", &WasmControlApi::OpenPanel);
2490 emscripten::function(
"controlClosePanel", &WasmControlApi::ClosePanel);
2491 emscripten::function(
"controlTogglePanel", &WasmControlApi::TogglePanel);
2492 emscripten::function(
"controlGetVisiblePanels", &WasmControlApi::GetVisiblePanels);
2493 emscripten::function(
"controlGetAvailablePanels", &WasmControlApi::GetAvailablePanels);
2494 emscripten::function(
"controlGetPanelsInCategory", &WasmControlApi::GetPanelsInCategory);
2495 emscripten::function(
"controlSetPanelLayout", &WasmControlApi::SetPanelLayout);
2496 emscripten::function(
"controlGetAvailableLayouts", &WasmControlApi::GetAvailableLayouts);
2497 emscripten::function(
"controlSaveCurrentLayout", &WasmControlApi::SaveCurrentLayout);
2498 emscripten::function(
"controlGetAvailableMenuActions", &WasmControlApi::GetAvailableMenuActions);
2499 emscripten::function(
"controlToggleMenuBar", &WasmControlApi::ToggleMenuBar);
2500 emscripten::function(
"controlGetSessionInfo", &WasmControlApi::GetSessionInfo);
2501 emscripten::function(
"controlCreateSession", &WasmControlApi::CreateSession);
2502 emscripten::function(
"controlSwitchSession", &WasmControlApi::SwitchSession);
2503 emscripten::function(
"controlGetRomStatus", &WasmControlApi::GetRomStatus);
2504 emscripten::function(
"controlReadRomBytes", &WasmControlApi::ReadRomBytes);
2505 emscripten::function(
"controlWriteRomBytes", &WasmControlApi::WriteRomBytes);
2506 emscripten::function(
"controlSaveRom", &WasmControlApi::SaveRom);
2509 emscripten::function(
"editorGetSnapshot", &WasmControlApi::GetEditorSnapshot);
2510 emscripten::function(
"editorGetCurrentDungeonRoom", &WasmControlApi::GetCurrentDungeonRoom);
2511 emscripten::function(
"editorGetCurrentOverworldMap", &WasmControlApi::GetCurrentOverworldMap);
2512 emscripten::function(
"editorGetSelection", &WasmControlApi::GetEditorSelection);
2515 emscripten::function(
"dataGetRoomTileData", &WasmControlApi::GetRoomTileData);
2516 emscripten::function(
"dataGetRoomObjects", &WasmControlApi::GetRoomObjects);
2517 emscripten::function(
"dataGetRoomProperties", &WasmControlApi::GetRoomProperties);
2518 emscripten::function(
"dataGetMapTileData", &WasmControlApi::GetMapTileData);
2519 emscripten::function(
"dataGetMapEntities", &WasmControlApi::GetMapEntities);
2520 emscripten::function(
"dataGetMapProperties", &WasmControlApi::GetMapProperties);
2521 emscripten::function(
"dataGetPaletteData", &WasmControlApi::GetPaletteData);
2522 emscripten::function(
"dataListPaletteGroups", &WasmControlApi::ListPaletteGroups);
2525 emscripten::function(
"guiGetUIElementTree", &WasmControlApi::GetUIElementTree);
2526 emscripten::function(
"guiGetUIElementBounds", &WasmControlApi::GetUIElementBounds);
2527 emscripten::function(
"guiSetSelection", &WasmControlApi::SetSelection);
2530 emscripten::function(
"settingsGetCurrentThemeData", &yaze::platform::WasmSettings::GetCurrentThemeData);
2531 emscripten::function(
"settingsLoadFont", &WasmControlApi::LoadFont);
2534 emscripten::function(
"controlGetPlatformInfo", &WasmControlApi::GetPlatformInfo);
2537 emscripten::function(
"agentIsReady", &WasmControlApi::AgentIsReady);
2538 emscripten::function(
"agentSendMessage", &WasmControlApi::AgentSendMessage);
2539 emscripten::function(
"agentGetChatHistory", &WasmControlApi::AgentGetChatHistory);
2540 emscripten::function(
"agentGetConfig", &WasmControlApi::AgentGetConfig);
2541 emscripten::function(
"agentSetConfig", &WasmControlApi::AgentSetConfig);
2542 emscripten::function(
"agentGetProviders", &WasmControlApi::AgentGetProviders);
2543 emscripten::function(
"agentGetProposals", &WasmControlApi::AgentGetProposals);
2544 emscripten::function(
"agentAcceptProposal", &WasmControlApi::AgentAcceptProposal);
2545 emscripten::function(
"agentRejectProposal", &WasmControlApi::AgentRejectProposal);
2546 emscripten::function(
"agentGetProposalDetails", &WasmControlApi::AgentGetProposalDetails);
2547 emscripten::function(
"agentOpenSidebar", &WasmControlApi::AgentOpenSidebar);
2548 emscripten::function(
"agentCloseSidebar", &WasmControlApi::AgentCloseSidebar);
struct snes_color snes_color
SNES color in 15-bit RGB format (BGR555)
#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");} })
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)
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)