From 00e22246f894fff87ffff78c48e8326924a2a2fa Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Mon, 29 Sep 2025 21:57:12 -0400 Subject: [PATCH 1/5] Implement rudimentary dump_scene command --- mm/2s2h/DeveloperTools/DebugConsole.cpp | 110 ++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/mm/2s2h/DeveloperTools/DebugConsole.cpp b/mm/2s2h/DeveloperTools/DebugConsole.cpp index 65e7a2837e..1b1b496251 100644 --- a/mm/2s2h/DeveloperTools/DebugConsole.cpp +++ b/mm/2s2h/DeveloperTools/DebugConsole.cpp @@ -4,8 +4,17 @@ #include "Window.h" #include "ConsoleWindow.h" #include "2s2h/BenPort.h" +#include "2s2h/resource/type/Scene.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "2s2h/resource/type/scenecommand/SetActorList.h" +#include "2s2h/resource/type/scenecommand/SetRoomList.h" #include #include +#include +#include +#include +#include +#include extern "C" { #include @@ -17,6 +26,11 @@ extern "C" { #include "overlays/gamestates/ovl_title/z_title.h" } +extern std::unordered_map actorNames; +extern std::unordered_map sceneNames; + +extern Ship::IResource* OTRPlay_LoadFile(PlayState* play, const char* fileName); + #define CMD_REGISTER Ship::Context::GetInstance()->GetConsole()->AddCommand // TODO: Commands should be using the output passed in. #define ERROR_MESSAGE \ @@ -259,6 +273,99 @@ static bool QuitHandler(std::shared_ptr Console, const std::vecto return 0; } +void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::set* sceneSet, + nlohmann::json* actorsJson, std::string* output) { + if (scene == nullptr) { + return; + } + for (auto& sceneCmd : scene->commands) { + switch ((SceneCommandTypeId)sceneCmd->cmdId) { + case SCENE_CMD_ID_ACTOR_LIST: { + SOH::SetActorList* actorList = (SOH::SetActorList*)sceneCmd.get(); + std::string locationName = sceneName; + if (roomName != "") { + int roomNum = roomName.find("_room"); + locationName += ", " + roomName.substr(roomNum + 1, 7); // roomName; + } + for (auto& actorSpawn : actorList->actorList) { + actorSpawn.id &= 0x1FFF; // Mask out rotation flags + // SPDLOG_INFO("Actor spawn: {}", actorSpawn.id); + if (actorSpawn.id >= ACTOR_ID_MAX || actorSpawn.id < ACTOR_PLAYER) + continue; + // SPDLOG_INFO("Actor spawn: {}, params: {}", actorNames[actorSpawn.id], actorSpawn.params); + // *output += fmt::format("\t\t{} {}\n", actorNames[actorSpawn.id], actorSpawn.params); + // TODO: Take half day bit into account + sceneSet->emplace(actorNames[actorSpawn.id]); // TODO: No, put rooms. maybe + std::set actorSceneSet; + if (!actorsJson->contains(actorNames[actorSpawn.id])) { + (*actorsJson)[actorNames[actorSpawn.id]] = actorSceneSet = {}; + } + actorSceneSet = (*actorsJson)[actorNames[actorSpawn.id]]; + actorSceneSet.emplace(locationName); + (*actorsJson)[actorNames[actorSpawn.id]] = actorSceneSet; + } + } break; + case SCENE_CMD_ID_ROOM_LIST: { + SOH::SetRoomList* roomList = (SOH::SetRoomList*)sceneCmd.get(); + for (auto& room : roomList->rooms) { + // SPDLOG_INFO("Room: {}", room.fileName); + // *output += fmt::format("\tRoom: {} \n", room.fileName); + SOH::Scene* sceneRoom = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, room.fileName); + traverseScene(sceneName, room.fileName, sceneRoom, sceneSet, actorsJson, output); + } + } break; + default: + break; + } + } +} + +static bool SceneDumpHandler(std::shared_ptr Console, const std::vector& args, + std::string* output) { + nlohmann::json scenesJson = {}; + nlohmann::json actorsJson = {}; + for (int sceneId = SCENE_20SICHITAI2; sceneId < SCENE_MAX; sceneId++) { + SceneTableEntry* sceneTableEntry = &gSceneTable[sceneId]; + if (sceneTableEntry->segment.fileName == nullptr) { + continue; + } + std::string scenePath = StringHelper::Sprintf("scenes/nonmq/%s/%s", sceneTableEntry->segment.fileName, + sceneTableEntry->segment.fileName); + SOH::Scene* scene = + (SOH::Scene*)OTRPlay_LoadFile(gPlayState, scenePath.c_str()); // Takes PlayState arg, but does not use it + // SPDLOG_INFO("Scene: {}, titleTextId: {}, commands: {}", scenePath, sceneTableEntry->titleTextId, + // scene->commands.size()); *output += fmt::format("Scene: {}, titleTextId: {}, commands: {}", scenePath, + // sceneTableEntry->titleTextId, scene->commands.size()); + std::set sceneSet = {}; + traverseScene(sceneNames[sceneId], "", scene, &sceneSet, &actorsJson, output); + scenesJson[sceneNames[sceneId]] = sceneSet; + } + /* + * Structure: + * { + * "scenes": { + * "sceneId": [setOfActors] + * }, + * "actors": { + * "actorId": [setOfScenes] + * } + * } + */ + nlohmann::json result = { { "scenes", scenesJson }, { "actors", actorsJson } }; + + try { + std::ofstream o("sceneDump.json"); + o << std::setw(4) << result << std::endl; + o.close(); + } catch (...) { + *output = "Failed to write sceneDump file"; + SPDLOG_ERROR("Failed to write sceneDump file"); + return 1; + } + *output = "Dumped scene data to sceneDump.json"; + return 0; +} + void DebugConsole_Init(void) { // Console CMD_REGISTER("file_select", { FileSelectHandler, "Returns to the file select." }); @@ -295,4 +402,7 @@ void DebugConsole_Init(void) { { { "x", Ship::ArgumentType::NUMBER, true }, { "y", Ship::ArgumentType::NUMBER, true }, { "z", Ship::ArgumentType::NUMBER, true } } }); + + // Data + CMD_REGISTER("dump_scene", { SceneDumpHandler, "Dumps scene data, TBD" }); } From fab71ee568101224970dbbc758de414c2900cd8c Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:48:55 -0400 Subject: [PATCH 2/5] Handle half day bits, cleanup --- mm/2s2h/DeveloperTools/DebugConsole.cpp | 49 +++++++++++++------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/mm/2s2h/DeveloperTools/DebugConsole.cpp b/mm/2s2h/DeveloperTools/DebugConsole.cpp index 1b1b496251..c67cb8b4db 100644 --- a/mm/2s2h/DeveloperTools/DebugConsole.cpp +++ b/mm/2s2h/DeveloperTools/DebugConsole.cpp @@ -14,7 +14,6 @@ #include #include #include -#include extern "C" { #include @@ -273,8 +272,8 @@ static bool QuitHandler(std::shared_ptr Console, const std::vecto return 0; } -void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::set* sceneSet, - nlohmann::json* actorsJson, std::string* output) { +void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::set& sceneSet, + nlohmann::json& actorsJson, std::string* output) { if (scene == nullptr) { return; } @@ -285,31 +284,37 @@ void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scen std::string locationName = sceneName; if (roomName != "") { int roomNum = roomName.find("_room"); - locationName += ", " + roomName.substr(roomNum + 1, 7); // roomName; + locationName += ", " + roomName.substr(roomNum + 1, 7); } for (auto& actorSpawn : actorList->actorList) { - actorSpawn.id &= 0x1FFF; // Mask out rotation flags - // SPDLOG_INFO("Actor spawn: {}", actorSpawn.id); - if (actorSpawn.id >= ACTOR_ID_MAX || actorSpawn.id < ACTOR_PLAYER) + s16 actorId = actorSpawn.id & 0x1FFF; // Mask out rotation flags + if (actorId >= ACTOR_ID_MAX || actorId < ACTOR_PLAYER) continue; - // SPDLOG_INFO("Actor spawn: {}, params: {}", actorNames[actorSpawn.id], actorSpawn.params); - // *output += fmt::format("\t\t{} {}\n", actorNames[actorSpawn.id], actorSpawn.params); - // TODO: Take half day bit into account - sceneSet->emplace(actorNames[actorSpawn.id]); // TODO: No, put rooms. maybe + + // Handle half day spawns + s32 actorEntryHalfDayBit = ((actorSpawn.rot.x & 7) << 7) | (actorSpawn.rot.z & 0x7F); + s32 appearsDuringDay = actorEntryHalfDayBit & HALFDAYBIT_DAWNS; + s32 appearsDuringNight = actorEntryHalfDayBit & HALFDAYBIT_NIGHTS; + std::string timeLocation = ""; + if (appearsDuringDay && !appearsDuringNight) { + timeLocation += " (Day only)"; + } else if (!appearsDuringDay && appearsDuringNight) { + timeLocation += " (Night only)"; + } + + sceneSet.emplace(actorNames[actorId]); // TODO: No, put rooms. maybe std::set actorSceneSet; - if (!actorsJson->contains(actorNames[actorSpawn.id])) { - (*actorsJson)[actorNames[actorSpawn.id]] = actorSceneSet = {}; + if (!actorsJson.contains(actorNames[actorId])) { + actorsJson[actorNames[actorId]] = actorSceneSet = {}; } - actorSceneSet = (*actorsJson)[actorNames[actorSpawn.id]]; - actorSceneSet.emplace(locationName); - (*actorsJson)[actorNames[actorSpawn.id]] = actorSceneSet; + actorSceneSet = (std::set)actorsJson[actorNames[actorId]]; + actorSceneSet.emplace(locationName + timeLocation); + actorsJson[actorNames[actorId]] = actorSceneSet; } } break; case SCENE_CMD_ID_ROOM_LIST: { SOH::SetRoomList* roomList = (SOH::SetRoomList*)sceneCmd.get(); for (auto& room : roomList->rooms) { - // SPDLOG_INFO("Room: {}", room.fileName); - // *output += fmt::format("\tRoom: {} \n", room.fileName); SOH::Scene* sceneRoom = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, room.fileName); traverseScene(sceneName, room.fileName, sceneRoom, sceneSet, actorsJson, output); } @@ -333,11 +338,8 @@ static bool SceneDumpHandler(std::shared_ptr Console, const std:: sceneTableEntry->segment.fileName); SOH::Scene* scene = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, scenePath.c_str()); // Takes PlayState arg, but does not use it - // SPDLOG_INFO("Scene: {}, titleTextId: {}, commands: {}", scenePath, sceneTableEntry->titleTextId, - // scene->commands.size()); *output += fmt::format("Scene: {}, titleTextId: {}, commands: {}", scenePath, - // sceneTableEntry->titleTextId, scene->commands.size()); std::set sceneSet = {}; - traverseScene(sceneNames[sceneId], "", scene, &sceneSet, &actorsJson, output); + traverseScene(sceneNames[sceneId], "", scene, sceneSet, actorsJson, output); scenesJson[sceneNames[sceneId]] = sceneSet; } /* @@ -404,5 +406,6 @@ void DebugConsole_Init(void) { { "z", Ship::ArgumentType::NUMBER, true } } }); // Data - CMD_REGISTER("dump_scene", { SceneDumpHandler, "Dumps scene data, TBD" }); + CMD_REGISTER("dump_scenes", + { SceneDumpHandler, "Scans through all scenes and actor spawns and dumps them to a JSON file." }); } From a92c80de1b4ec9282de19153ccbb1d219878c1d7 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Sun, 12 Oct 2025 15:41:23 -0400 Subject: [PATCH 3/5] Dump actor spawn information --- mm/2s2h/DeveloperTools/DebugConsole.cpp | 27 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/mm/2s2h/DeveloperTools/DebugConsole.cpp b/mm/2s2h/DeveloperTools/DebugConsole.cpp index c67cb8b4db..e5331de14c 100644 --- a/mm/2s2h/DeveloperTools/DebugConsole.cpp +++ b/mm/2s2h/DeveloperTools/DebugConsole.cpp @@ -14,6 +14,7 @@ #include #include #include +#include extern "C" { #include @@ -272,7 +273,7 @@ static bool QuitHandler(std::shared_ptr Console, const std::vecto return 0; } -void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::set& sceneSet, +void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::vector& sceneSet, nlohmann::json& actorsJson, std::string* output) { if (scene == nullptr) { return; @@ -297,18 +298,26 @@ void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scen s32 appearsDuringNight = actorEntryHalfDayBit & HALFDAYBIT_NIGHTS; std::string timeLocation = ""; if (appearsDuringDay && !appearsDuringNight) { - timeLocation += " (Day only)"; + timeLocation = " (Day only)"; } else if (!appearsDuringDay && appearsDuringNight) { - timeLocation += " (Night only)"; + timeLocation = " (Night only)"; } - sceneSet.emplace(actorNames[actorId]); // TODO: No, put rooms. maybe - std::set actorSceneSet; + // TODO: Figure out how object dependency works + // Put room in its own child object? + sceneSet.emplace_back(fmt::format("{}{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", + roomName, actorNames[actorId], timeLocation, (u16)actorSpawn.params, + actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, + actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); + std::set actorSceneSet; // TODO: Figure out vector, so we know the actorlistindex. sets may not have deterministic order if (!actorsJson.contains(actorNames[actorId])) { actorsJson[actorNames[actorId]] = actorSceneSet = {}; } actorSceneSet = (std::set)actorsJson[actorNames[actorId]]; - actorSceneSet.emplace(locationName + timeLocation); + actorSceneSet.emplace(fmt::format("{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", + locationName, timeLocation, (u16)actorSpawn.params, + actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, + actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); actorsJson[actorNames[actorId]] = actorSceneSet; } } break; @@ -327,6 +336,10 @@ void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scen static bool SceneDumpHandler(std::shared_ptr Console, const std::vector& args, std::string* output) { + // TODO: if args(1), assume that's an actor id and only dump that info + // args(0) will always be dump_scenes + // Could get crazy with redefining the actor and scene tables so that the ids are human readable, then just find that in the list and do things that way + // for now, just take integer ids nlohmann::json scenesJson = {}; nlohmann::json actorsJson = {}; for (int sceneId = SCENE_20SICHITAI2; sceneId < SCENE_MAX; sceneId++) { @@ -338,7 +351,7 @@ static bool SceneDumpHandler(std::shared_ptr Console, const std:: sceneTableEntry->segment.fileName); SOH::Scene* scene = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, scenePath.c_str()); // Takes PlayState arg, but does not use it - std::set sceneSet = {}; + std::vector sceneSet = {}; traverseScene(sceneNames[sceneId], "", scene, sceneSet, actorsJson, output); scenesJson[sceneNames[sceneId]] = sceneSet; } From 83dbcd122c1b86308036b4e95497f85e87b58fbf Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Sun, 12 Oct 2025 21:30:55 -0400 Subject: [PATCH 4/5] Clean up, mark actors whose objects are not loaded --- mm/2s2h/DeveloperTools/DebugConsole.cpp | 146 +++++++++++++++--------- 1 file changed, 90 insertions(+), 56 deletions(-) diff --git a/mm/2s2h/DeveloperTools/DebugConsole.cpp b/mm/2s2h/DeveloperTools/DebugConsole.cpp index e5331de14c..e3a4cb54cb 100644 --- a/mm/2s2h/DeveloperTools/DebugConsole.cpp +++ b/mm/2s2h/DeveloperTools/DebugConsole.cpp @@ -7,7 +7,9 @@ #include "2s2h/resource/type/Scene.h" #include "2s2h/resource/type/scenecommand/SceneCommand.h" #include "2s2h/resource/type/scenecommand/SetActorList.h" +#include "2s2h/resource/type/scenecommand/SetObjectList.h" #include "2s2h/resource/type/scenecommand/SetRoomList.h" +#include "2s2h/resource/type/scenecommand/SetSpecialObjects.h" #include #include #include @@ -24,6 +26,7 @@ extern "C" { #include "overlays/gamestates/ovl_file_choose/z_file_select.h" #include "overlays/gamestates/ovl_title/z_title.h" +ActorInit* Actor_LoadOverlay(ActorContext* actorCtx, s16 index); } extern std::unordered_map actorNames; @@ -273,73 +276,104 @@ static bool QuitHandler(std::shared_ptr Console, const std::vecto return 0; } +template T* getCommandListById(SOH::Scene* scene, SceneCommandTypeId sceneCommandTypeId) { + for (auto& sceneCmd : scene->commands) { + if ((SceneCommandTypeId)sceneCmd->cmdId == sceneCommandTypeId) { + return (T*)sceneCmd.get(); + } + } + return nullptr; +} + +void processActorSpawns(std::string sceneName, std::string roomName, SOH::SetActorList* actorList, + SOH::SetObjectList* objectList, SOH::SetSpecialObjects* specialObjectList, + std::vector& sceneSet, nlohmann::json& actorsJson) { + std::string locationName = sceneName; + int roomNum = -1; + if (roomName != "") { + roomNum = roomName.find("_room"); + roomName = roomName.substr(roomNum + 1, 7); + locationName += ", " + roomName; + } + for (auto& actorSpawn : actorList->actorList) { + s16 actorId = actorSpawn.id & 0x1FFF; // Mask out rotation flags + if (actorId >= ACTOR_ID_MAX || actorId < ACTOR_PLAYER) + continue; + + // Handle half day spawns + s32 actorEntryHalfDayBit = ((actorSpawn.rot.x & 7) << 7) | (actorSpawn.rot.z & 0x7F); + s32 appearsDuringDay = actorEntryHalfDayBit & HALFDAYBIT_DAWNS; + s32 appearsDuringNight = actorEntryHalfDayBit & HALFDAYBIT_NIGHTS; + std::string timeLocation = ""; + if (appearsDuringDay && !appearsDuringNight) { + timeLocation = " (Day only)"; + } else if (!appearsDuringDay && appearsDuringNight) { + timeLocation = " (Night only)"; + } + + // Mark actors whose objects are not loaded + ActorInit* actorInit = Actor_LoadOverlay(&gPlayState->actorCtx, actorId); + static std::vector globalObjectIds = { GAMEPLAY_KEEP, GAMEPLAY_FIELD_KEEP, GAMEPLAY_DANGEON_KEEP, + OBJECT_STK }; + std::string objectStatus = " (OBJECT NOT FOUND)"; + if (std::find(globalObjectIds.begin(), globalObjectIds.end(), actorInit->objectId) != globalObjectIds.end()) { + objectStatus = ""; + } + if (objectList != nullptr) { + for (s16 object : objectList->objects) { + if (ABS_ALT(object) == actorInit->objectId) { + objectStatus = ""; + break; + } + } + } + if (specialObjectList != nullptr) { + if (ABS_ALT(specialObjectList->specialObjects.globalObject) == actorInit->objectId) { + objectStatus = ""; + break; + } + } + + sceneSet.emplace_back( + fmt::format("{}: {}{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", roomName, + actorNames[actorId], objectStatus, timeLocation, (u16)actorSpawn.params, actorSpawn.pos.x, + actorSpawn.pos.y, actorSpawn.pos.z, actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); + std::vector actorSceneList; + if (!actorsJson.contains(actorNames[actorId])) { + actorsJson[actorNames[actorId]] = nlohmann::json::array(); + } + actorSceneList = actorsJson[actorNames[actorId]].get>(); + actorSceneList.emplace_back( + fmt::format("{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", locationName, + timeLocation, (u16)actorSpawn.params, actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, + actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); + actorsJson[actorNames[actorId]] = actorSceneList; + } +} + void traverseScene(std::string sceneName, std::string roomName, SOH::Scene* scene, std::vector& sceneSet, nlohmann::json& actorsJson, std::string* output) { if (scene == nullptr) { return; } - for (auto& sceneCmd : scene->commands) { - switch ((SceneCommandTypeId)sceneCmd->cmdId) { - case SCENE_CMD_ID_ACTOR_LIST: { - SOH::SetActorList* actorList = (SOH::SetActorList*)sceneCmd.get(); - std::string locationName = sceneName; - if (roomName != "") { - int roomNum = roomName.find("_room"); - locationName += ", " + roomName.substr(roomNum + 1, 7); - } - for (auto& actorSpawn : actorList->actorList) { - s16 actorId = actorSpawn.id & 0x1FFF; // Mask out rotation flags - if (actorId >= ACTOR_ID_MAX || actorId < ACTOR_PLAYER) - continue; - - // Handle half day spawns - s32 actorEntryHalfDayBit = ((actorSpawn.rot.x & 7) << 7) | (actorSpawn.rot.z & 0x7F); - s32 appearsDuringDay = actorEntryHalfDayBit & HALFDAYBIT_DAWNS; - s32 appearsDuringNight = actorEntryHalfDayBit & HALFDAYBIT_NIGHTS; - std::string timeLocation = ""; - if (appearsDuringDay && !appearsDuringNight) { - timeLocation = " (Day only)"; - } else if (!appearsDuringDay && appearsDuringNight) { - timeLocation = " (Night only)"; - } - - // TODO: Figure out how object dependency works - // Put room in its own child object? - sceneSet.emplace_back(fmt::format("{}{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", - roomName, actorNames[actorId], timeLocation, (u16)actorSpawn.params, - actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, - actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); - std::set actorSceneSet; // TODO: Figure out vector, so we know the actorlistindex. sets may not have deterministic order - if (!actorsJson.contains(actorNames[actorId])) { - actorsJson[actorNames[actorId]] = actorSceneSet = {}; - } - actorSceneSet = (std::set)actorsJson[actorNames[actorId]]; - actorSceneSet.emplace(fmt::format("{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", - locationName, timeLocation, (u16)actorSpawn.params, - actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, - actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); - actorsJson[actorNames[actorId]] = actorSceneSet; - } - } break; - case SCENE_CMD_ID_ROOM_LIST: { - SOH::SetRoomList* roomList = (SOH::SetRoomList*)sceneCmd.get(); - for (auto& room : roomList->rooms) { - SOH::Scene* sceneRoom = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, room.fileName); - traverseScene(sceneName, room.fileName, sceneRoom, sceneSet, actorsJson, output); - } - } break; - default: - break; + SOH::SetObjectList* objectList = getCommandListById(scene, SCENE_CMD_ID_OBJECT_LIST); + SOH::SetSpecialObjects* specialObjectList = + getCommandListById(scene, SCENE_CMD_ID_SPECIAL_FILES); + SOH::SetActorList* actorList = getCommandListById(scene, SCENE_CMD_ID_ACTOR_LIST); + if (actorList != nullptr) { + processActorSpawns(sceneName, roomName, actorList, objectList, specialObjectList, sceneSet, actorsJson); + } + SOH::SetRoomList* roomList = getCommandListById(scene, SCENE_CMD_ID_ROOM_LIST); + if (roomList != nullptr) { + for (auto& room : roomList->rooms) { + SOH::Scene* sceneRoom = (SOH::Scene*)OTRPlay_LoadFile(gPlayState, room.fileName); + traverseScene(sceneName, room.fileName, sceneRoom, sceneSet, actorsJson, output); } } } static bool SceneDumpHandler(std::shared_ptr Console, const std::vector& args, std::string* output) { - // TODO: if args(1), assume that's an actor id and only dump that info - // args(0) will always be dump_scenes - // Could get crazy with redefining the actor and scene tables so that the ids are human readable, then just find that in the list and do things that way - // for now, just take integer ids nlohmann::json scenesJson = {}; nlohmann::json actorsJson = {}; for (int sceneId = SCENE_20SICHITAI2; sceneId < SCENE_MAX; sceneId++) { From 7d9f44ccda2b21b98983223f1fbb2acd66d736b3 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:11:55 -0400 Subject: [PATCH 5/5] Log actorListIndex --- mm/2s2h/DeveloperTools/DebugConsole.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mm/2s2h/DeveloperTools/DebugConsole.cpp b/mm/2s2h/DeveloperTools/DebugConsole.cpp index e3a4cb54cb..3187b0f934 100644 --- a/mm/2s2h/DeveloperTools/DebugConsole.cpp +++ b/mm/2s2h/DeveloperTools/DebugConsole.cpp @@ -295,6 +295,7 @@ void processActorSpawns(std::string sceneName, std::string roomName, SOH::SetAct roomName = roomName.substr(roomNum + 1, 7); locationName += ", " + roomName; } + int actorListIndex = 0; for (auto& actorSpawn : actorList->actorList) { s16 actorId = actorSpawn.id & 0x1FFF; // Mask out rotation flags if (actorId >= ACTOR_ID_MAX || actorId < ACTOR_PLAYER) @@ -334,19 +335,20 @@ void processActorSpawns(std::string sceneName, std::string roomName, SOH::SetAct } } - sceneSet.emplace_back( - fmt::format("{}: {}{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", roomName, - actorNames[actorId], objectStatus, timeLocation, (u16)actorSpawn.params, actorSpawn.pos.x, - actorSpawn.pos.y, actorSpawn.pos.z, actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); + sceneSet.emplace_back(fmt::format( + "{}: (actorListIndex: {}) {}{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", + roomName, actorListIndex++, actorNames[actorId], objectStatus, timeLocation, (u16)actorSpawn.params, + actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, actorSpawn.rot.x, actorSpawn.rot.y, + actorSpawn.rot.z)); std::vector actorSceneList; if (!actorsJson.contains(actorNames[actorId])) { actorsJson[actorNames[actorId]] = nlohmann::json::array(); } actorSceneList = actorsJson[actorNames[actorId]].get>(); actorSceneList.emplace_back( - fmt::format("{}{} (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", locationName, - timeLocation, (u16)actorSpawn.params, actorSpawn.pos.x, actorSpawn.pos.y, actorSpawn.pos.z, - actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); + fmt::format("{}{} (actorListIndex: {}) (params: {:#04x}), (pos x:{}, y:{}, z:{}), (rot: x:{}, y:{}, z:{})", + locationName, timeLocation, actorListIndex, (u16)actorSpawn.params, actorSpawn.pos.x, + actorSpawn.pos.y, actorSpawn.pos.z, actorSpawn.rot.x, actorSpawn.rot.y, actorSpawn.rot.z)); actorsJson[actorNames[actorId]] = actorSceneList; } }