diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp index e0e5e74b3..a9ddc4f41 100644 --- a/soh/soh/Extractor/Extract.cpp +++ b/soh/soh/Extractor/Extract.cpp @@ -54,10 +54,10 @@ static constexpr uint32_t OOT_PAL_GC_DBG2 = 0x87121EFE; // 03-13-2002 build static constexpr uint32_t OOT_PAL_GC_MQ_DBG = 0x917D18F6; static const std::unordered_map verMap = { - { OOT_PAL_GC, "Pal Gamecube" }, - { OOT_PAL_GC_DBG1, "PAL Debug 1" }, - { OOT_PAL_GC_DBG2, "PAL Debug 2" }, - { OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" }, + { OOT_PAL_GC, "PAL GameCube" }, + { OOT_PAL_GC_DBG1, "PAL GameCube Debug 1" }, + { OOT_PAL_GC_DBG2, "PAL GameCube Debug 2" }, + { OOT_PAL_GC_MQ_DBG, "PAL GameCube MQ Debug" }, }; // TODO only check the first 54MB of the rom. @@ -156,6 +156,40 @@ void Extractor::SetRomInfo(const std::string& path) { mCurRomSize = GetCurRomSize(); } +void Extractor::FilterRoms(std::vector& roms, RomSearchMode searchMode) { + std::ifstream inFile; + std::vector::iterator it = roms.begin(); + + while (it != roms.end()) { + std::string rom = *it; + SetRomInfo(rom); + + // Skip. We will handle rom size errors later on after filtering + if (!ValidateRomSize()) { + it++; + continue; + } + + inFile.open(rom, std::ios::in | std::ios::binary); + inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.clear(); + inFile.close(); + + RomToBigEndian(mRomData.get(), mCurRomSize); + + // Rom doesn't claim to be valid + // Game type doesn't match search mode + if (!verMap.contains(GetRomVerCrc()) || + (searchMode == RomSearchMode::Vanilla && IsMasterQuest()) || + (searchMode == RomSearchMode::MQ && !IsMasterQuest())) { + it = roms.erase(it); + continue; + } + + it++; + } +} + void Extractor::GetRoms(std::vector& roms) { #ifdef _WIN32 WIN32_FIND_DATAA ffd; @@ -258,6 +292,7 @@ bool Extractor::GetRomPathFromBox() { mCurRomSize = GetCurRomSize(); return true; } + uint32_t Extractor::GetRomVerCrc() const { return BSWAP32(((uint32_t*)mRomData.get())[4]); } @@ -303,28 +338,73 @@ bool Extractor::ValidateRom(bool skipCrcTextBox) { return true; } -bool Extractor::Run() { +bool Extractor::ManuallySearchForRom() { + std::ifstream inFile; + + if (!GetRomPathFromBox()) { + ShowErrorBox("No rom selected", "No Rom selected. Exiting"); + return false; + } + + inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary); + + if (!inFile.is_open()) { + return false; // TODO Handle error + } + + inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.close(); + RomToBigEndian(mRomData.get(), mCurRomSize); + + if (!ValidateRom()) { + return false; + } + + return true; +} + +bool Extractor::ManuallySearchForRomMatchingType(RomSearchMode searchMode) { + if (!ManuallySearchForRom()) { + return false; + } + + char msgBuf[150]; + snprintf(msgBuf, 150, "The selected rom does not match the expected game type\nExpected type: %s.\n\nDo you want to search again?", + searchMode == RomSearchMode::MQ ? "Master Quest" : "Vanilla"); + + while ((searchMode == RomSearchMode::Vanilla && IsMasterQuest()) || + (searchMode == RomSearchMode::MQ && !IsMasterQuest())) { + int ret = ShowYesNoBox("Wrong Game Type", msgBuf); + switch (ret) { + case IDYES: + if (!ManuallySearchForRom()) { + return false; + } + continue; + case IDNO: + return false; + default: + UNREACHABLE; + break; + } + } + + return true; +} + +bool Extractor::Run(RomSearchMode searchMode) { std::vector roms; std::ifstream inFile; - uint32_t verCrc; GetRoms(roms); + FilterRoms(roms, searchMode); if (roms.empty()) { int ret = ShowYesNoBox("No roms found", "No roms found. Look for one?"); switch (ret) { case IDYES: - if (!GetRomPathFromBox()) { - ShowErrorBox("No rom selected", "No rom selected. Exiting"); - return false; - } - inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary); - if (!inFile.is_open()) { - return false; // TODO Handle error - } - inFile.read((char*)mRomData.get(), mCurRomSize); - if (!ValidateRom()) { + if (!ManuallySearchForRomMatchingType(searchMode)) { return false; } break; @@ -338,27 +418,21 @@ bool Extractor::Run() { } for (const auto& rom : roms) { - int option; - SetRomInfo(rom); - if (inFile.is_open()) { - inFile.close(); - } - inFile.open(rom, std::ios::in | std::ios::binary); + if (!ValidateRomSize()) { ShowSizeErrorBox(); continue; } + + inFile.open(rom, std::ios::in | std::ios::binary); inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.clear(); + inFile.close(); RomToBigEndian(mRomData.get(), mCurRomSize); - verCrc = GetRomVerCrc(); - // Rom doesn't claim to be valid - if (!verMap.contains(verCrc)) { - continue; - } + int option = ShowRomPickBox(GetRomVerCrc()); - option = ShowRomPickBox(verCrc); if (option == (int)ButtonId::YES) { if (!ValidateRom(true)) { if (rom == roms.back()) { @@ -371,21 +445,11 @@ bool Extractor::Run() { } break; } else if (option == (int)ButtonId::FIND) { - if (!GetRomPathFromBox()) { - ShowErrorBox("No rom selected", "No Rom selected. Exiting"); - return false; - } - inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary); - if (!inFile.is_open()) { - return false; // TODO Handle error - } - inFile.read((char*)mRomData.get(), mCurRomSize); - if (!ValidateRom()) { + if (!ManuallySearchForRomMatchingType(searchMode)) { return false; } break; } else if (option == (int)ButtonId::NO) { - inFile.close(); if (rom == roms.back()) { ShowErrorBox("No rom provided", "No rom provided. Exiting"); return false; diff --git a/soh/soh/Extractor/Extract.h b/soh/soh/Extractor/Extract.h index 3ca23aaf3..e4eb2e5bb 100644 --- a/soh/soh/Extractor/Extract.h +++ b/soh/soh/Extractor/Extract.h @@ -19,6 +19,12 @@ static constexpr size_t MB32 = 32 * MB_BASE; static constexpr size_t MB54 = 54 * MB_BASE; static constexpr size_t MB64 = 64 * MB_BASE; +enum class RomSearchMode { + Both = 0, + Vanilla = 1, + MQ = 2, +}; + class Extractor { std::unique_ptr mRomData = std::make_unique(MB64); std::string mCurrentRomPath; @@ -33,21 +39,24 @@ class Extractor { bool ValidateRom(bool skipCrcBox = false); const char* GetZapdVerStr() const; - bool IsMasterQuest() const; - + void SetRomInfo(const std::string& path); + void FilterRoms(std::vector& roms, RomSearchMode searchMode); void GetRoms(std::vector& roms); void ShowSizeErrorBox() const; void ShowCrcErrorBox() const; int ShowRomPickBox(uint32_t verCrc) const; + bool ManuallySearchForRom(); + bool ManuallySearchForRomMatchingType(RomSearchMode searchMode); public: //TODO create some kind of abstraction for message boxes. static int ShowYesNoBox(const char* title, const char* text); static void ShowErrorBox(const char* title, const char* text); + bool IsMasterQuest() const; - bool Run(); + bool Run(RomSearchMode searchMode = RomSearchMode::Both); bool CallZapd(); const char* GetZapdStr(); }; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index ee76a234c..cab179baf 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -710,6 +710,7 @@ extern "C" void InitOTR() { #if not defined (__SWITCH__) && not defined(__WIIU__) if (!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr")) && !std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot.otr"))){ + bool generatedOtrIsMQ = false; if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) { Extractor extract; if (!extract.Run()) { @@ -717,12 +718,13 @@ extern "C" void InitOTR() { exit(1); } extract.CallZapd(); + generatedOtrIsMQ = extract.IsMasterQuest(); } else { exit(1); } if (Extractor::ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) { Extractor extract; - if (!extract.Run()) { + if (!extract.Run(generatedOtrIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ)) { Extractor::ShowErrorBox("Error", "An error occured, an OTR file may have been generated by a different step. Continuing..."); } else { extract.CallZapd();