From 5c6006ee0fdaf37879fac3a19a7899252a934e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Mon, 12 Oct 2026 02:08:14 +0000 Subject: [PATCH] Fix extracting from MQ rom padded to 64MB (#7376) Also show error message instead of just proceeding to start if vanilla o2r already extracted --- soh/soh/Extractor/Extract.cpp | 9 +++++- soh/soh/OTRGlobals.cpp | 58 ++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp index e21f83744b..de16a265aa 100644 --- a/soh/soh/Extractor/Extract.cpp +++ b/soh/soh/Extractor/Extract.cpp @@ -366,7 +366,7 @@ size_t Extractor::GetCurRomSize() const { bool Extractor::ValidateAndFixRom() { // The MQ debug rom sometimes has the header patched to look like a US rom. - // Check the crc as if it were changed back, but leave mRomData as the original dump for torch. + // Check the crc as if it were changed back. CallTorch changes it back for real. const uint8_t region = mRomData[0x3E]; if (GetRomVerCrc() == OOT_PAL_GC_MQ_DBG) { mRomData[0x3E] = 'P'; @@ -666,6 +666,13 @@ bool Extractor::CallTorch(std::string installPath, std::string exportdir, std::a *totalExtract = SohTorch::CountAssetFiles(srcDir + "/" + GetTorchVersionDir()); *extractCount = 0; + // MQ debug dumps only hold 54MB of data, the rest is dump-specific padding, and some have + // the region byte changed. Trim and restore it so every dump matches the one config.yml hash. + if (GetRomVerCrc() == OOT_PAL_GC_MQ_DBG && mRomData.size() == MB64) { + mRomData.resize(MB54); + mRomData[0x3E] = 'P'; + } + // config.yml decides whether this is oot.o2r or oot-mq.o2r. std::string archiveName = SohTorch::Extract(std::move(mRomData), srcDir, tempdir, portVersion, extractCount); bool success = !archiveName.empty(); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 1b4f62c475..67bd1777d5 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -430,7 +430,12 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) { Extractor extract; PromptSteps promptStep = PS_FILE_CHECK; bool generatedIsMQ = false; + // Whether generatedIsMQ is set, i.e. the first prompted rom extracted fine + bool generatedFirst = false; + bool lastExtractFailed = false; std::atomic extractCount = 0, totalExtract = 0; + // Set by the extraction thread, shown as a popup by the main thread once the task finishes + std::atomic extractFailed = false; std::string installPath = std::filesystem::absolute(Ship::Context::GetAppBundlePath()).string(); std::string dataPath = std::filesystem::absolute(Ship::Context::GetAppDirectoryPath(appShortName)).string(); @@ -613,15 +618,17 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) { std::string msg = "Archive for current ROM, " + archive + ", already exists.\nExtract again?"; SohGui::RegisterPopup("Confirm Re-extract", msg.c_str(), "Yes", "No", [&]() { extractionTask = threadPool->submit_task([&]() -> void { - extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), - &extractCount, &totalExtract); + extractFailed = + !extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), + &extractCount, &totalExtract); extractCount = totalExtract = 0; }); }); } else { extractionTask = threadPool->submit_task([&]() -> void { - extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), - &extractCount, &totalExtract); + extractFailed = + !extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), + &extractCount, &totalExtract); extractCount = totalExtract = 0; }); } @@ -677,9 +684,13 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) { continue; } extractionTask = threadPool->submit_task([&]() -> void { - extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), - &extractCount, &totalExtract); - generatedIsMQ = extract.IsMasterQuest(); + extractFailed = + !extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), + &extractCount, &totalExtract); + if (!extractFailed) { + generatedIsMQ = extract.IsMasterQuest(); + generatedFirst = true; + } promptStep = PS_SECOND; extractCount = 0; totalExtract = 0; @@ -687,17 +698,28 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) { continue; } case PS_SECOND: { + // Keep asking until the user says no, so a failed or cancelled rom can be retried SohGui::RegisterPopup( - "Extraction Complete", "ROM Extracted. Extract another?", "Yes", "No", + lastExtractFailed ? "Extract Another" : "Extraction Complete", + lastExtractFailed ? "Try extracting another ROM?" : "ROM Extracted. Extract another?", + "Yes", "No", [&]() { - if (!extract.ManuallySearchForRomMatchingType(generatedIsMQ ? RomSearchMode::Vanilla - : RomSearchMode::MQ)) { - extractStep = ES_VERIFY; - } else { + RomSearchMode mode = RomSearchMode::Both; + if (generatedFirst) { + mode = generatedIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ; + } + if (extract.ManuallySearchForRomMatchingType(mode)) { extractionTask = threadPool->submit_task([&]() -> void { - extract.CallTorch(installPath, Ship::Context::GetAppDirectoryPath(appShortName), - &extractCount, &totalExtract); - extractStep = ES_VERIFY; + extractFailed = !extract.CallTorch( + installPath, Ship::Context::GetAppDirectoryPath(appShortName), + &extractCount, &totalExtract); + if (!extractFailed && generatedFirst) { + extractStep = ES_VERIFY; + } else if (!extractFailed) { + // A retry of the first rom worked, so still offer the other type + generatedIsMQ = extract.IsMasterQuest(); + generatedFirst = true; + } extractCount = 0; totalExtract = 0; }); @@ -754,6 +776,12 @@ void OTRGlobals::RunExtract(int argc, char* argv[]) { } catch (const std::exception& e) { SohGui::RegisterPopup("Extraction Crashed", e.what(), "Close", "", []() { exit(1); }); } + lastExtractFailed = extractFailed; + if (extractFailed) { + SohGui::RegisterPopup("Extraction Failed", + "The ROM could not be extracted. Check the log for details.", "OK", ""); + extractFailed = false; + } extractionTask.reset(); } else { if (!ImGui::IsPopupOpen("ROM Extraction")) {