#include "ZRoom.h" #include #include #include #include #include #include "Commands/EndMarker.h" #include "Commands/SetActorCutsceneList.h" #include "Commands/SetActorList.h" #include "Commands/SetAlternateHeaders.h" #include "Commands/SetAnimatedMaterialList.h" #include "Commands/SetCameraSettings.h" #include "Commands/SetCollisionHeader.h" #include "Commands/SetCsCamera.h" #include "Commands/SetCutscenes.h" #include "Commands/SetEchoSettings.h" #include "Commands/SetEntranceList.h" #include "Commands/SetExitList.h" #include "Commands/SetLightList.h" #include "Commands/SetLightingSettings.h" #include "Commands/SetMesh.h" #include "Commands/SetMinimapChests.h" #include "Commands/SetMinimapList.h" #include "Commands/SetObjectList.h" #include "Commands/SetPathways.h" #include "Commands/SetRoomBehavior.h" #include "Commands/SetRoomList.h" #include "Commands/SetSkyboxModifier.h" #include "Commands/SetSkyboxSettings.h" #include "Commands/SetSoundSettings.h" #include "Commands/SetSpecialObjects.h" #include "Commands/SetStartPositionList.h" #include "Commands/SetTimeSettings.h" #include "Commands/SetTransitionActorList.h" #include "Commands/SetWind.h" #include "Commands/SetWorldMapVisited.h" #include "Commands/Unused09.h" #include "Commands/Unused1D.h" #include "Commands/ZRoomCommandUnk.h" #include "Globals.h" #include #include "Utils/Path.h" #include "Utils/StringHelper.h" #include "WarningHandler.h" #include "ZBlob.h" #include "ZCutscene.h" #include "ZFile.h" REGISTER_ZFILENODE(Room, ZRoom); REGISTER_ZFILENODE(Scene, ZRoom); REGISTER_ZFILENODE(AltHeader, ZRoom); ZRoom::ZRoom(ZFile* nParent) : ZResource(nParent) { roomCount = -1; canHaveInner = true; RegisterOptionalAttribute("HackMode"); } ZRoom::~ZRoom() { for (ZRoomCommand* cmd : commands) delete cmd; } void ZRoom::ExtractFromXML(tinyxml2::XMLElement* reader, uint32_t nRawDataIndex) { ZResource::ExtractFromXML(reader, nRawDataIndex); if (hackMode == "syotes_room") { SyotesRoomHack(); } else { DeclareVar(name, ""); } } void ZRoom::ExtractFromBinary(uint32_t nRawDataIndex, ZResourceType parentType) { rawDataIndex = nRawDataIndex; name = GetDefaultName(parent->GetName()); zroomType = ZResourceType::AltHeader; switch (parentType) { case ZResourceType::Scene: case ZResourceType::Room: case ZResourceType::AltHeader: parentZroomType = parentType; break; default: // TODO: error message or something assert(false); break; } ParseRawData(); DeclareVar(name, ""); } void ZRoom::ParseXML(tinyxml2::XMLElement* reader) { ZResource::ParseXML(reader); // TODO: HACK: remove this specific check when the repo uses the correct HackMode="syotes_room" if (name == "syotes_room_0") { hackMode = "syotes_room"; } std::string nodeName = std::string(reader->Name()); if (nodeName == "Scene") { zroomType = ZResourceType::Scene; } else if (nodeName == "Room") zroomType = ZResourceType::Room; else if (nodeName == "AltHeader") zroomType = ZResourceType::AltHeader; if (reader->Attribute("HackMode") != nullptr) { hackMode = std::string(reader->Attribute("HackMode")); if (hackMode != "syotes_room") { std::string headerError = StringHelper::Sprintf( "invalid value found for 'HackMode' attribute: '%s'", hackMode.c_str()); HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, headerError, ""); } } } void ZRoom::ParseRawData() { if (hackMode == "syotes_room") return; bool shouldContinue = true; uint32_t currentIndex = 0; uint32_t currentPtr = rawDataIndex; const auto& rawData = parent->GetRawData(); while (shouldContinue) { RoomCommand opcode = static_cast(rawData.at(currentPtr)); ZRoomCommand* cmd = nullptr; auto start = std::chrono::steady_clock::now(); switch (opcode) { case RoomCommand::SetStartPositionList: cmd = new SetStartPositionList(parent); break; // 0x00 case RoomCommand::SetActorList: cmd = new SetActorList(parent); break; // 0x01 case RoomCommand::SetCsCamera: cmd = new SetCsCamera(parent); break; // 0x02 (MM-ONLY) case RoomCommand::SetCollisionHeader: cmd = new SetCollisionHeader(parent); break; // 0x03 case RoomCommand::SetRoomList: cmd = new SetRoomList(parent); break; // 0x04 case RoomCommand::SetWind: cmd = new SetWind(parent); break; // 0x05 case RoomCommand::SetEntranceList: cmd = new SetEntranceList(parent); break; // 0x06 case RoomCommand::SetSpecialObjects: cmd = new SetSpecialObjects(parent); break; // 0x07 case RoomCommand::SetRoomBehavior: cmd = new SetRoomBehavior(parent); break; // 0x08 case RoomCommand::Unused09: cmd = new Unused09(parent); break; // 0x09 case RoomCommand::SetMesh: cmd = new SetMesh(parent); break; // 0x0A case RoomCommand::SetObjectList: cmd = new SetObjectList(parent); break; // 0x0B case RoomCommand::SetLightList: cmd = new SetLightList(parent); break; // 0x0C (MM-ONLY) case RoomCommand::SetPathways: cmd = new SetPathways(parent); break; // 0x0D case RoomCommand::SetTransitionActorList: cmd = new SetTransitionActorList(parent); break; // 0x0E case RoomCommand::SetLightingSettings: cmd = new SetLightingSettings(parent); break; // 0x0F case RoomCommand::SetTimeSettings: cmd = new SetTimeSettings(parent); break; // 0x10 case RoomCommand::SetSkyboxSettings: cmd = new SetSkyboxSettings(parent); break; // 0x11 case RoomCommand::SetSkyboxModifier: cmd = new SetSkyboxModifier(parent); break; // 0x12 case RoomCommand::SetExitList: cmd = new SetExitList(parent); break; // 0x13 case RoomCommand::EndMarker: cmd = new EndMarker(parent); break; // 0x14 case RoomCommand::SetSoundSettings: cmd = new SetSoundSettings(parent); break; // 0x15 case RoomCommand::SetEchoSettings: cmd = new SetEchoSettings(parent); break; // 0x16 case RoomCommand::SetCutscenes: cmd = new SetCutscenes(parent); break; // 0x17 case RoomCommand::SetAlternateHeaders: cmd = new SetAlternateHeaders(parent); break; // 0x18 case RoomCommand::SetCameraSettings: if (Globals::Instance->game == ZGame::MM_RETAIL) cmd = new SetWorldMapVisited(parent); else cmd = new SetCameraSettings(parent); break; // 0x19 case RoomCommand::SetAnimatedMaterialList: cmd = new SetAnimatedMaterialList(parent); break; // 0x1A (MM-ONLY) case RoomCommand::SetActorCutsceneList: cmd = new SetActorCutsceneList(parent); break; // 0x1B (MM-ONLY) case RoomCommand::SetMinimapList: cmd = new SetMinimapList(parent); break; // 0x1C (MM-ONLY) case RoomCommand::Unused1D: cmd = new Unused1D(parent); break; // 0x1D case RoomCommand::SetMinimapChests: cmd = new SetMinimapChests(parent); break; // 0x1E (MM-ONLY) default: cmd = new ZRoomCommandUnk(parent); } cmd->commandSet = rawDataIndex; cmd->ExtractCommandFromRoom(this, currentPtr); if (Globals::Instance->profile) { auto end = std::chrono::steady_clock::now(); int64_t diff = std::chrono::duration_cast(end - start).count(); if (diff > 50) printf("OP: %s, TIME: %" PRIi64 "ms\n", cmd->GetCommandCName().c_str(), diff); } cmd->cmdIndex = currentIndex; commands.push_back(cmd); if (opcode == RoomCommand::EndMarker) shouldContinue = false; currentPtr += 8; currentIndex++; } } void ZRoom::DeclareReferences(const std::string& prefix) { for (auto& cmd : commands) cmd->DeclareReferences(prefix); } void ZRoom::ParseRawDataLate() { for (auto& cmd : commands) cmd->ParseRawDataLate(); } void ZRoom::DeclareReferencesLate(const std::string& prefix) { for (auto& cmd : commands) cmd->DeclareReferencesLate(prefix); } Declaration* ZRoom::DeclareVar(const std::string& prefix, const std::string& body) { std::string auxName = name; if (auxName == "") auxName = GetDefaultName(prefix); if (zroomType == ZResourceType::Scene || zroomType == ZResourceType::Room) auxName = StringHelper::Sprintf("%sCommands", name.c_str()); Declaration* decl = parent->AddDeclarationArray(rawDataIndex, GetDeclarationAlignment(), GetRawDataSize(), GetSourceTypeName(), auxName, commands.size(), body); decl->staticConf = staticConf; return decl; } std::string ZRoom::GetBodySourceCode() const { std::string declaration; for (size_t i = 0; i < commands.size(); i++) { ZRoomCommand* cmd = commands[i]; declaration += StringHelper::Sprintf("\t%s,", cmd->GetBodySourceCode().c_str()); if (i + 1 < commands.size()) declaration += "\n"; } return declaration; } std::string ZRoom::GetDefaultName(const std::string& prefix) const { return StringHelper::Sprintf("%sSet_%06X", prefix.c_str(), rawDataIndex); } /* * There is one room in Ocarina of Time that lacks a header. Room 120, "Syotes", dates * back to very early in the game's development. Since this room is a special case, * declare automatically the data its contains whitout the need of a header. */ void ZRoom::SyotesRoomHack() { PolygonType2 poly(parent, 0, this); poly.ParseRawData(); poly.DeclareReferences(GetName()); parent->AddDeclaration(0, poly.GetDeclarationAlignment(), poly.GetRawDataSize(), poly.GetSourceTypeName(), poly.GetDefaultName(GetName()), poly.GetBodySourceCode()); } ZRoomCommand* ZRoom::FindCommandOfType(RoomCommand cmdType) { for (size_t i = 0; i < commands.size(); i++) { if (commands[i]->GetRoomCommand() == cmdType) return commands[i]; } return nullptr; } size_t ZRoom::GetDeclarationSizeFromNeighbor(uint32_t declarationAddress) { auto currentDecl = parent->declarations.find(declarationAddress); if (currentDecl == parent->declarations.end()) return 0; auto nextDecl = currentDecl; std::advance(nextDecl, 1); if (nextDecl == parent->declarations.end()) return parent->GetRawData().size() - currentDecl->first; return nextDecl->first - currentDecl->first; } size_t ZRoom::GetCommandSizeFromNeighbor(ZRoomCommand* cmd) { int32_t cmdIndex = -1; for (size_t i = 0; i < commands.size(); i++) { if (commands[i] == cmd) { cmdIndex = i; break; } } if (cmdIndex != -1) { if (cmdIndex + 1 < (int32_t)commands.size()) return commands[cmdIndex + 1]->cmdAddress - commands[cmdIndex]->cmdAddress; else return parent->GetRawData().size() - commands[cmdIndex]->cmdAddress; } return 0; } void ZRoom::GetSourceOutputCode([[maybe_unused]] const std::string& prefix) { if (hackMode != "syotes_room") DeclareVar(prefix, GetBodySourceCode()); } size_t ZRoom::GetRawDataSize() const { size_t size = 0; for (ZRoomCommand* cmd : commands) size += cmd->GetRawDataSize(); return size; } std::string ZRoom::GetSourceTypeName() const { return "SceneCmd"; } ZResourceType ZRoom::GetResourceType() const { assert(zroomType == ZResourceType::Scene || zroomType == ZResourceType::Room || zroomType == ZResourceType::AltHeader); return zroomType; }