From e2875ef9a51bed19526a9d2beee65779227c2453 Mon Sep 17 00:00:00 2001 From: Lenny McLennington Date: Sat, 28 Oct 2023 20:28:35 +0100 Subject: [PATCH] fix hang when importing certain modpacks Modified findFolderOfFileInZip to use a breadth-first search and support searching for multiple file names in one pass. This should prevent or at least make it less likely to hang while importing certain packs. Signed-off-by: Lenny McLennington --- launcher/InstanceImportTask.cpp | 24 +++++++++++------------- launcher/MMCZip.cpp | 29 +++++++++++++++++------------ launcher/MMCZip.h | 6 +++--- launcher/minecraft/World.cpp | 2 +- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index b490620d..1102ab6e 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -164,23 +164,21 @@ void InstanceImportTask::processZipPack() } else { - QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg"); - QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json"); - - if (!mmcRoot.isNull()) - { - // process as MultiMC instance/pack - qDebug() << "MultiMC:" << mmcRoot; - root = mmcRoot; - m_modpackType = ModpackType::MultiMC; - } - else if(!flameRoot.isNull()) + auto [rootDirectory, fileName] = MMCZip::findFolderOfFileInZip(m_packZip.get(), {"manifest.json", "instance.cfg"}); + if(fileName == "manifest.json") { // process as Flame pack - qDebug() << "Flame:" << flameRoot; - root = flameRoot; + qDebug() << "Flame:" << rootDirectory; + root = rootDirectory; m_modpackType = ModpackType::Flame; } + else if (fileName == "instance.cfg") + { + // process as MultiMC instance/pack + qDebug() << "MultiMC:" << rootDirectory; + root = rootDirectory; + m_modpackType = ModpackType::MultiMC; + } } if(m_modpackType == ModpackType::Unknown) { diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index e94285d8..ce03691b 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -40,6 +40,7 @@ #include "FileSystem.h" #include +#include // ours bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, const FilterFunction filter) @@ -228,23 +229,27 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const } // ours -QString MMCZip::findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root) +std::pair MMCZip::findFolderOfFileInZip(QuaZip * zip, QSet what, const QString &root) { - QuaZipDir rootDir(zip, root); - for(auto fileName: rootDir.entryList(QDir::Files)) + std::deque pathsToTraverse; + pathsToTraverse.push_back(root); + while (!pathsToTraverse.empty()) { - if(fileName == what) - return root; - } - for(auto fileName: rootDir.entryList(QDir::Dirs)) - { - QString result = findFolderOfFileInZip(zip, what, root + fileName); - if(!result.isEmpty()) + QString currentPath = pathsToTraverse.front(); + pathsToTraverse.pop_front(); + QuaZipDir rootDir(zip, currentPath); + + for(auto fileName: rootDir.entryList(QDir::Files)) { - return result; + if (what.contains(fileName)) + return {currentPath, fileName}; + } + for(auto fileName: rootDir.entryList(QDir::Dirs)) + { + pathsToTraverse.push_back(root); } } - return QString(); + return {QString(), QString()}; } // ours diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index ce9775bd..2a38ecf4 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -78,11 +78,11 @@ namespace MMCZip bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods); /** - * Find a single file in archive by file name (not path) + * Breath-first find a single file in archive by a list of file names (not path) * - * \return the path prefix where the file is + * \return pair of {file parent directory, file name} */ - QString findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root = QString("")); + std::pair findFolderOfFileInZip(QuaZip * zip, QSet what, const QString &root = QString("")); /** * Find a multiple files of the same name in archive by file name diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp index 90fcf337..6be783c8 100644 --- a/launcher/minecraft/World.cpp +++ b/launcher/minecraft/World.cpp @@ -285,7 +285,7 @@ void World::readFromZip(const QFileInfo &file) { return; } - auto location = MMCZip::findFolderOfFileInZip(&zip, "level.dat"); + auto [location, _] = MMCZip::findFolderOfFileInZip(&zip, {"level.dat"}); is_valid = !location.isEmpty(); if (!is_valid) {