NOISSUE fix multiple issues in ATLauncher integration

This commit is contained in:
Petr Mrázek 2021-02-09 05:04:23 +01:00
parent 434369ca7c
commit 13a7f8d3b7
11 changed files with 175 additions and 105 deletions

View File

@ -138,7 +138,7 @@ void InstanceImportTask::processZipPack()
void InstanceImportTask::extractFinished() void InstanceImportTask::extractFinished()
{ {
m_packZip.reset(); m_packZip.reset();
if (m_extractFuture.result().isEmpty()) if (!m_extractFuture.result())
{ {
emitFailed(tr("Failed to extract modpack")); emitFailed(tr("Failed to extract modpack"));
return; return;

View File

@ -24,6 +24,8 @@
#include "settings/SettingsObject.h" #include "settings/SettingsObject.h"
#include "QObjectPtr.h" #include "QObjectPtr.h"
#include <nonstd/optional>
class QuaZip; class QuaZip;
namespace Flame namespace Flame
{ {
@ -60,8 +62,8 @@ private: /* data */
QString m_archivePath; QString m_archivePath;
bool m_downloadRequired = false; bool m_downloadRequired = false;
std::unique_ptr<QuaZip> m_packZip; std::unique_ptr<QuaZip> m_packZip;
QFuture<QStringList> m_extractFuture; QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<QStringList> m_extractFutureWatcher; QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
enum class ModpackType{ enum class ModpackType{
Unknown, Unknown,
MultiMC, MultiMC,

View File

@ -208,16 +208,27 @@ bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & re
// ours // ours
QStringList MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target) nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
{ {
QDir directory(target); QDir directory(target);
QStringList extracted; QStringList extracted;
qDebug() << "Extracting subdir" << subdir << "from" << zip->getZipName() << "to" << target; qDebug() << "Extracting subdir" << subdir << "from" << zip->getZipName() << "to" << target;
if (!zip->goToFirstFile()) auto numEntries = zip->getEntriesCount();
if(numEntries < 0) {
qWarning() << "Failed to enumerate files in archive";
return nonstd::nullopt;
}
else if(numEntries == 0) {
qDebug() << "Extracting empty archives seems odd...";
return extracted;
}
else if (!zip->goToFirstFile())
{ {
qWarning() << "Failed to seek to first file in zip"; qWarning() << "Failed to seek to first file in zip";
return QStringList(); return nonstd::nullopt;
} }
do do
{ {
QString name = zip->getCurrentFileName(); QString name = zip->getCurrentFileName();
@ -235,7 +246,7 @@ QStringList MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QSt
{ {
qWarning() << "Failed to extract file" << name << "to" << absFilePath; qWarning() << "Failed to extract file" << name << "to" << absFilePath;
JlCompress::removeFile(extracted); JlCompress::removeFile(extracted);
return QStringList(); return nonstd::nullopt;
} }
extracted.append(absFilePath); extracted.append(absFilePath);
qDebug() << "Extracted file" << name; qDebug() << "Extracted file" << name;
@ -250,23 +261,35 @@ bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &tar
} }
// ours // ours
QStringList MMCZip::extractDir(QString fileCompressed, QString dir) nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
{ {
QuaZip zip(fileCompressed); QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip)) if (!zip.open(QuaZip::mdUnzip))
{ {
return {}; // check if this is a minimum size empty zip file...
QFileInfo fileInfo(fileCompressed);
if(fileInfo.size() == 22) {
return QStringList();
}
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
return nonstd::nullopt;
} }
return MMCZip::extractSubDir(&zip, "", dir); return MMCZip::extractSubDir(&zip, "", dir);
} }
// ours // ours
QStringList MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir) nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
{ {
QuaZip zip(fileCompressed); QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip)) if (!zip.open(QuaZip::mdUnzip))
{ {
return {}; // check if this is a minimum size empty zip file...
QFileInfo fileInfo(fileCompressed);
if(fileInfo.size() == 22) {
return QStringList();
}
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
return nonstd::nullopt;
} }
return MMCZip::extractSubDir(&zip, subdir, dir); return MMCZip::extractSubDir(&zip, subdir, dir);
} }
@ -277,7 +300,13 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target)
QuaZip zip(fileCompressed); QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip)) if (!zip.open(QuaZip::mdUnzip))
{ {
return {}; // check if this is a minimum size empty zip file...
QFileInfo fileInfo(fileCompressed);
if(fileInfo.size() == 22) {
return true;
}
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
return false;
} }
return MMCZip::extractRelFile(&zip, file, target); return MMCZip::extractRelFile(&zip, file, target);
} }

View File

@ -24,6 +24,7 @@
#include "multimc_logic_export.h" #include "multimc_logic_export.h"
#include <JlCompress.h> #include <JlCompress.h>
#include <nonstd/optional>
namespace MMCZip namespace MMCZip
{ {
@ -57,7 +58,7 @@ namespace MMCZip
/** /**
* Extract a subdirectory from an archive * Extract a subdirectory from an archive
*/ */
QStringList MULTIMC_LOGIC_EXPORT extractSubDir(QuaZip *zip, const QString & subdir, const QString &target); nonstd::optional<QStringList> MULTIMC_LOGIC_EXPORT extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
bool MULTIMC_LOGIC_EXPORT extractRelFile(QuaZip *zip, const QString & file, const QString &target); bool MULTIMC_LOGIC_EXPORT extractRelFile(QuaZip *zip, const QString & file, const QString &target);
@ -68,7 +69,7 @@ namespace MMCZip
* \param dir The directory to extract to, the current directory if left empty. * \param dir The directory to extract to, the current directory if left empty.
* \return The list of the full paths of the files extracted, empty on failure. * \return The list of the full paths of the files extracted, empty on failure.
*/ */
QStringList MULTIMC_LOGIC_EXPORT extractDir(QString fileCompressed, QString dir); nonstd::optional<QStringList> MULTIMC_LOGIC_EXPORT extractDir(QString fileCompressed, QString dir);
/** /**
* Extract a subdirectory from an archive * Extract a subdirectory from an archive
@ -78,7 +79,7 @@ namespace MMCZip
* \param dir The directory to extract to, the current directory if left empty. * \param dir The directory to extract to, the current directory if left empty.
* \return The list of the full paths of the files extracted, empty on failure. * \return The list of the full paths of the files extracted, empty on failure.
*/ */
QStringList MULTIMC_LOGIC_EXPORT extractDir(QString fileCompressed, QString subdir, QString dir); nonstd::optional<QStringList> MULTIMC_LOGIC_EXPORT extractDir(QString fileCompressed, QString subdir, QString dir);
/** /**
* Extract a single file from an archive into a directory * Extract a single file from an archive into a directory

View File

@ -289,7 +289,7 @@ bool World::install(const QString &to, const QString &name)
{ {
return false; return false;
} }
ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath).isEmpty(); ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath);
} }
else if(m_containerFile.isDir()) else if(m_containerFile.isDir())
{ {

View File

@ -31,6 +31,7 @@ bool PackInstallTask::abort()
void PackInstallTask::executeTask() void PackInstallTask::executeTask()
{ {
qDebug() << "PackInstallTask::executeTask: " << QThread::currentThreadId();
auto *netJob = new NetJob("ATLauncher::VersionFetch"); auto *netJob = new NetJob("ATLauncher::VersionFetch");
auto searchUrl = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json") auto searchUrl = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json")
.arg(m_pack).arg(m_version_name); .arg(m_pack).arg(m_version_name);
@ -44,6 +45,7 @@ void PackInstallTask::executeTask()
void PackInstallTask::onDownloadSucceeded() void PackInstallTask::onDownloadSucceeded()
{ {
qDebug() << "PackInstallTask::onDownloadSucceeded: " << QThread::currentThreadId();
jobPtr.reset(); jobPtr.reset();
QJsonParseError parse_error; QJsonParseError parse_error;
@ -84,7 +86,7 @@ void PackInstallTask::onDownloadSucceeded()
minecraftVersion = ver; minecraftVersion = ver;
if(m_version.noConfigs) { if(m_version.noConfigs) {
installMods(); downloadMods();
} }
else { else {
installConfigs(); installConfigs();
@ -93,6 +95,7 @@ void PackInstallTask::onDownloadSucceeded()
void PackInstallTask::onDownloadFailed(QString reason) void PackInstallTask::onDownloadFailed(QString reason)
{ {
qDebug() << "PackInstallTask::onDownloadFailed: " << QThread::currentThreadId();
jobPtr.reset(); jobPtr.reset();
emitFailed(reason); emitFailed(reason);
} }
@ -360,6 +363,7 @@ bool PackInstallTask::createPackComponent(QString instanceRoot, std::shared_ptr<
void PackInstallTask::installConfigs() void PackInstallTask::installConfigs()
{ {
qDebug() << "PackInstallTask::installConfigs: " << QThread::currentThreadId();
setStatus(tr("Downloading configs...")); setStatus(tr("Downloading configs..."));
jobPtr.reset(new NetJob(tr("Config download"))); jobPtr.reset(new NetJob(tr("Config download")));
@ -392,6 +396,7 @@ void PackInstallTask::installConfigs()
void PackInstallTask::extractConfigs() void PackInstallTask::extractConfigs()
{ {
qDebug() << "PackInstallTask::extractConfigs: " << QThread::currentThreadId();
setStatus(tr("Extracting configs...")); setStatus(tr("Extracting configs..."));
QDir extractDir(m_stagingPath); QDir extractDir(m_stagingPath);
@ -406,7 +411,7 @@ void PackInstallTask::extractConfigs()
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/minecraft"); m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/minecraft");
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, [&]() connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, [&]()
{ {
installMods(); downloadMods();
}); });
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [&]() connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [&]()
{ {
@ -415,8 +420,9 @@ void PackInstallTask::extractConfigs()
m_extractFutureWatcher.setFuture(m_extractFuture); m_extractFutureWatcher.setFuture(m_extractFuture);
} }
void PackInstallTask::installMods() void PackInstallTask::downloadMods()
{ {
qDebug() << "PackInstallTask::installMods: " << QThread::currentThreadId();
setStatus(tr("Downloading mods...")); setStatus(tr("Downloading mods..."));
jarmods.clear(); jarmods.clear();
@ -464,12 +470,17 @@ void PackInstallTask::installMods()
else { else {
auto relpath = getDirForModType(mod.type, mod.type_raw); auto relpath = getDirForModType(mod.type, mod.type_raw);
if(relpath == Q_NULLPTR) continue; if(relpath == Q_NULLPTR) continue;
auto path = FS::PathCombine(m_stagingPath, "minecraft", relpath, mod.file);
qDebug() << "Will download" << url << "to" << path; auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName);
auto dl = Net::Download::makeFile(url, path); entry->setStale(true);
auto dl = Net::Download::makeCached(url, entry);
jobPtr->addNetAction(dl); jobPtr->addNetAction(dl);
auto path = FS::PathCombine(m_stagingPath, "minecraft", relpath, mod.file);
qDebug() << "Will download" << url << "to" << path;
modsToCopy[entry->getFullPath()] = path;
if(mod.type == ModType::Forge) { if(mod.type == ModType::Forge) {
auto vlist = ENV.metadataIndex()->get("net.minecraftforge"); auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
if(vlist) if(vlist)
@ -493,11 +504,7 @@ void PackInstallTask::installMods()
} }
} }
connect(jobPtr.get(), &NetJob::succeeded, this, [&]() connect(jobPtr.get(), &NetJob::succeeded, this, &PackInstallTask::onModsDownloaded);
{
jobPtr.reset();
extractMods();
});
connect(jobPtr.get(), &NetJob::failed, [&](QString reason) connect(jobPtr.get(), &NetJob::failed, [&](QString reason)
{ {
jobPtr.reset(); jobPtr.reset();
@ -511,17 +518,45 @@ void PackInstallTask::installMods()
jobPtr->start(); jobPtr->start();
} }
void PackInstallTask::extractMods() void PackInstallTask::onModsDownloaded() {
{ qDebug() << "PackInstallTask::onModsDownloaded: " << QThread::currentThreadId();
setStatus(tr("Extracting mods...")); jobPtr.reset();
if(modsToExtract.isEmpty()) { if(modsToExtract.size() || modsToDecomp.size() || modsToCopy.size()) {
decompMods(); m_modExtractFuture = QtConcurrent::run(QThreadPool::globalInstance(), this, &PackInstallTask::extractMods, modsToExtract, modsToDecomp, modsToCopy);
return; connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onModsExtracted);
connect(&m_modExtractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [&]()
{
emitAborted();
});
m_modExtractFutureWatcher.setFuture(m_modExtractFuture);
} }
else {
install();
}
}
auto modPath = modsToExtract.firstKey(); void PackInstallTask::onModsExtracted() {
auto mod = modsToExtract.value(modPath); qDebug() << "PackInstallTask::onModsExtracted: " << QThread::currentThreadId();
if(m_modExtractFuture.result()) {
install();
}
else {
emitFailed(tr("Failed to extract mods..."));
}
}
bool PackInstallTask::extractMods(
const QMap<QString, VersionMod> &toExtract,
const QMap<QString, VersionMod> &toDecomp,
const QMap<QString, QString> &toCopy
) {
qDebug() << "PackInstallTask::extractMods: " << QThread::currentThreadId();
setStatus(tr("Extracting mods..."));
for (auto iter = toExtract.begin(); iter != toExtract.end(); iter++) {
auto &modPath = iter.key();
auto &mod = iter.value();
QString extractToDir; QString extractToDir;
if(mod.type == ModType::Extract) { if(mod.type == ModType::Extract) {
@ -534,65 +569,52 @@ void PackInstallTask::extractMods()
extractToDir = FS::PathCombine("resourcepacks", "extracted"); extractToDir = FS::PathCombine("resourcepacks", "extracted");
} }
qDebug() << "Extracting " + mod.file + " to " + extractToDir;
QDir extractDir(m_stagingPath); QDir extractDir(m_stagingPath);
auto extractToPath = FS::PathCombine(extractDir.absolutePath(), "minecraft", extractToDir); auto extractToPath = FS::PathCombine(extractDir.absolutePath(), "minecraft", extractToDir);
QString folderToExtract = ""; QString folderToExtract = "";
if(mod.type == ModType::Extract) { if(mod.type == ModType::Extract) {
folderToExtract = mod.extractFolder; folderToExtract = mod.extractFolder;
folderToExtract.remove(QRegExp("^/"));
} }
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, modPath, folderToExtract, extractToPath); qDebug() << "Extracting " + mod.file + " to " + extractToDir;
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, [&]() if(!MMCZip::extractDir(modPath, folderToExtract, extractToPath)) {
{ // assume error
extractMods(); return false;
}); }
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, [&]()
{
emitAborted();
});
m_extractFutureWatcher.setFuture(m_extractFuture);
modsToExtract.remove(modPath);
}
void PackInstallTask::decompMods()
{
setStatus(tr("Extracting 'decomp' mods..."));
if(modsToDecomp.isEmpty()) {
install();
return;
} }
auto modPath = modsToDecomp.firstKey(); for (auto iter = toDecomp.begin(); iter != toDecomp.end(); iter++) {
auto mod = modsToDecomp.value(modPath); auto &modPath = iter.key();
auto &mod = iter.value();
auto extractToDir = getDirForModType(mod.decompType, mod.decompType_raw); auto extractToDir = getDirForModType(mod.decompType, mod.decompType_raw);
QDir extractDir(m_stagingPath); QDir extractDir(m_stagingPath);
auto extractToPath = FS::PathCombine(extractDir.absolutePath(), "minecraft", extractToDir, mod.decompFile); auto extractToPath = FS::PathCombine(extractDir.absolutePath(), "minecraft", extractToDir, mod.decompFile);
qWarning() << "Extracting " + mod.decompFile + " to " + extractToDir; qDebug() << "Extracting " + mod.decompFile + " to " + extractToDir;
if(!MMCZip::extractFile(modPath, mod.decompFile, extractToPath)) {
qWarning() << "Failed to extract" << mod.decompFile;
return false;
}
}
m_decompFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractFile, modPath, mod.decompFile, extractToPath); for (auto iter = toCopy.begin(); iter != toCopy.end(); iter++) {
connect(&m_decompFutureWatcher, &QFutureWatcher<bool>::finished, this, [&]() auto &from = iter.key();
{ auto &to = iter.value();
install(); FS::copy fileCopyOperation(from, to);
}); if(!fileCopyOperation()) {
connect(&m_decompFutureWatcher, &QFutureWatcher<bool>::canceled, this, [&]() qWarning() << "Failed to copy" << from << "to" << to;
{ return false;
emitAborted(); }
}); }
m_decompFutureWatcher.setFuture(m_decompFuture); return true;
modsToDecomp.remove(modPath);
} }
void PackInstallTask::install() void PackInstallTask::install()
{ {
qDebug() << "PackInstallTask::install: " << QThread::currentThreadId();
setStatus(tr("Installing modpack")); setStatus(tr("Installing modpack"));
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg"); auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");

View File

@ -11,6 +11,8 @@
#include "minecraft/PackProfile.h" #include "minecraft/PackProfile.h"
#include "meta/Version.h" #include "meta/Version.h"
#include <nonstd/optional>
namespace ATLauncher { namespace ATLauncher {
class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask
@ -30,6 +32,9 @@ private slots:
void onDownloadSucceeded(); void onDownloadSucceeded();
void onDownloadFailed(QString reason); void onDownloadFailed(QString reason);
void onModsDownloaded();
void onModsExtracted();
private: private:
QString getDirForModType(ModType type, QString raw); QString getDirForModType(ModType type, QString raw);
QString getVersionForLoader(QString uid); QString getVersionForLoader(QString uid);
@ -40,9 +45,12 @@ private:
void installConfigs(); void installConfigs();
void extractConfigs(); void extractConfigs();
void installMods(); void downloadMods();
void extractMods(); bool extractMods(
void decompMods(); const QMap<QString, VersionMod> &toExtract,
const QMap<QString, VersionMod> &toDecomp,
const QMap<QString, QString> &toCopy
);
void install(); void install();
private: private:
@ -55,14 +63,18 @@ private:
QMap<QString, VersionMod> modsToExtract; QMap<QString, VersionMod> modsToExtract;
QMap<QString, VersionMod> modsToDecomp; QMap<QString, VersionMod> modsToDecomp;
QMap<QString, QString> modsToCopy;
QString archivePath; QString archivePath;
QStringList jarmods; QStringList jarmods;
Meta::VersionPtr minecraftVersion; Meta::VersionPtr minecraftVersion;
QMap<QString, Meta::VersionPtr> componentsToInstall; QMap<QString, Meta::VersionPtr> componentsToInstall;
QFuture<QStringList> m_extractFuture; QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<QStringList> m_extractFutureWatcher; QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
QFuture<bool> m_modExtractFuture;
QFutureWatcher<bool> m_modExtractFutureWatcher;
QFuture<bool> m_decompFuture; QFuture<bool> m_decompFuture;
QFutureWatcher<bool> m_decompFutureWatcher; QFutureWatcher<bool> m_decompFutureWatcher;

View File

@ -8,6 +8,8 @@
#include "meta/VersionList.h" #include "meta/VersionList.h"
#include "PackHelpers.h" #include "PackHelpers.h"
#include <nonstd/optional>
namespace LegacyFTB { namespace LegacyFTB {
class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask
@ -40,8 +42,8 @@ private slots:
private: /* data */ private: /* data */
bool abortable = false; bool abortable = false;
std::unique_ptr<QuaZip> m_packZip; std::unique_ptr<QuaZip> m_packZip;
QFuture<QStringList> m_extractFuture; QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<QStringList> m_extractFutureWatcher; QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
NetJobPtr netJobContainer; NetJobPtr netJobContainer;
QString archivePath; QString archivePath;

View File

@ -79,7 +79,7 @@ void Technic::SingleZipPackInstallTask::downloadProgressChanged(qint64 current,
void Technic::SingleZipPackInstallTask::extractFinished() void Technic::SingleZipPackInstallTask::extractFinished()
{ {
m_packZip.reset(); m_packZip.reset();
if (m_extractFuture.result().isEmpty()) if (!m_extractFuture.result())
{ {
emitFailed(tr("Failed to extract modpack")); emitFailed(tr("Failed to extract modpack"));
return; return;

View File

@ -25,6 +25,8 @@
#include <QStringList> #include <QStringList>
#include <QUrl> #include <QUrl>
#include <nonstd/optional>
namespace Technic { namespace Technic {
class MULTIMC_LOGIC_EXPORT SingleZipPackInstallTask : public InstanceTask class MULTIMC_LOGIC_EXPORT SingleZipPackInstallTask : public InstanceTask
@ -51,8 +53,8 @@ private:
QString m_archivePath; QString m_archivePath;
NetJobPtr m_filesNetJob; NetJobPtr m_filesNetJob;
std::unique_ptr<QuaZip> m_packZip; std::unique_ptr<QuaZip> m_packZip;
QFuture<QStringList> m_extractFuture; QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<QStringList> m_extractFutureWatcher; QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
}; };
} // namespace Technic } // namespace Technic

View File

@ -117,7 +117,7 @@ void Technic::SolderPackInstallTask::downloadSucceeded()
while (m_modCount > i) while (m_modCount > i)
{ {
auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i)); auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i));
if (MMCZip::extractDir(path, extractDir).isEmpty()) if (!MMCZip::extractDir(path, extractDir))
{ {
return false; return false;
} }