From 9f175a4a4dc3db7be376c0e7ac746d10223608a9 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 8 May 2026 21:26:10 +0300 Subject: [PATCH] refactor ModrinthCreationTask Signed-off-by: Trial97 --- launcher/BaseInstance.cpp | 16 -- launcher/BaseInstance.h | 1 - .../modrinth/ModrinthInstanceCreationTask.cpp | 264 ++++++++++-------- .../modrinth/ModrinthInstanceCreationTask.h | 30 +- 4 files changed, 163 insertions(+), 148 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 0080cc516..3062b7459 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -189,22 +189,6 @@ void BaseInstance::setManagedPack(const QString& type, m_settings->set("ManagedPackVersionName", version); } -void BaseInstance::copyManagedPack(BaseInstance& other) -{ - m_settings->set("ManagedPack", other.isManagedPack()); - m_settings->set("ManagedPackType", other.getManagedPackType()); - m_settings->set("ManagedPackID", other.getManagedPackID()); - m_settings->set("ManagedPackName", other.getManagedPackName()); - m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID()); - m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName()); - - if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_settings->get("AutomaticJava").toBool() && - m_settings->get("OverrideJavaLocation").toBool()) { - m_settings->set("OverrideJavaLocation", false); - m_settings->set("JavaPath", ""); - } -} - QStringList BaseInstance::getLinkedInstances() const { auto setting = m_settings->get("linkedInstances").toString(); diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 9280d2e1c..c57c8220c 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -166,7 +166,6 @@ class BaseInstance : public QObject { QString getManagedPackVersionID() const; QString getManagedPackVersionName() const; void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version); - void copyManagedPack(BaseInstance& other); virtual QStringList extraArguments(); diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 0cb2c547d..4ac044f69 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -16,7 +16,6 @@ #include "net/ChecksumValidator.h" #include "net/ApiDownload.h" -#include "net/ApiHeaderProxy.h" #include "net/NetJob.h" #include "modplatform/ModIndex.h" @@ -39,10 +38,10 @@ bool ModrinthCreationTask::abort() if (m_task) { m_task->abort(); } - return InstanceCreationTask::abort(); + return InstanceTask::abort(); } -bool ModrinthCreationTask::updateInstance() +void ModrinthCreationTask::executeTask() { auto* instanceList = APPLICATION->instances(); @@ -58,28 +57,30 @@ bool ModrinthCreationTask::updateInstance() inst = instanceList->getInstanceById(originalName()); if (!inst) { - return false; + createInstance(); + return; } } } QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); if (!parseManifest(indexPath, m_files, true, false)) { - return false; + return; } auto versionName = inst->getManagedPackVersionName(); - m_root_path = QFileInfo(inst->gameRoot()).fileName(); + m_rootPath = QFileInfo(inst->gameRoot()).fileName(); auto versionStr = !versionName.isEmpty() ? tr(" (version %1)").arg(versionName) : ""; if (shouldConfirmUpdate()) { auto shouldUpdate = askIfShouldUpdate(m_parent, versionStr); if (shouldUpdate == ShouldUpdate::SkipUpdating) { - return false; + createInstance(); + return; } if (shouldUpdate == ShouldUpdate::Cancel) { - m_abort = true; - return false; + emitAborted(); + return; } } @@ -147,30 +148,28 @@ bool ModrinthCreationTask::updateInstance() QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Cancel); if (dialog->exec() == QDialog::DialogCode::Rejected) { - m_abort = true; - return false; + emitAborted(); + return; } } setOverride(true, inst->id()); qDebug() << "Will override instance!"; - m_instance = inst; + m_oldInstance = inst; // We let it go through the createInstance() stage, just with a couple modifications for updating - return false; + createInstance(); } // https://docs.modrinth.com/docs/modpacks/format_definition/ -std::unique_ptr ModrinthCreationTask::createInstance() +void ModrinthCreationTask::createInstance() { - QEventLoop loop; - QString parentFolder(FS::PathCombine(m_stagingPath, "mrpack")); QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); if (m_files.empty() && !parseManifest(indexPath, m_files, true, true)) { - return nullptr; + return; } // Keep index file in case we need it some other time (like when changing versions) @@ -178,7 +177,7 @@ std::unique_ptr ModrinthCreationTask::createInstance() FS::ensureFilePathExists(newIndexPlace); FS::move(indexPath, newIndexPlace); - auto mcPath = FS::PathCombine(m_stagingPath, m_root_path); + auto mcPath = FS::PathCombine(m_stagingPath, m_rootPath); auto overridePath = FS::PathCombine(m_stagingPath, "overrides"); if (QFile::exists(overridePath)) { @@ -187,8 +186,8 @@ std::unique_ptr ModrinthCreationTask::createInstance() // Apply the overrides if (!FS::move(overridePath, mcPath)) { - setError(tr("Could not rename the overrides folder:\n") + "overrides"); - return nullptr; + emitFailed(tr("Could not rename the overrides folder:\n") + "overrides"); + return; } } @@ -200,85 +199,80 @@ std::unique_ptr ModrinthCreationTask::createInstance() // Apply the overrides if (!FS::overrideFolder(mcPath, clientOverridePath)) { - setError(tr("Could not rename the client overrides folder:\n") + "client overrides"); - return nullptr; + emitFailed(tr("Could not rename the client overrides folder:\n") + "client overrides"); + return; } } QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); auto instanceSettings = std::make_unique(configPath); - auto instance = std::make_unique(m_globalSettings, std::move(instanceSettings), m_stagingPath); + m_newInstance = std::make_unique(m_globalSettings, std::move(instanceSettings), m_stagingPath); - auto* components = instance->getPackProfile(); + auto* components = m_newInstance->getPackProfile(); components->buildingFromScratch(); - components->setComponentVersion("net.minecraft", m_minecraft_version, true); + components->setComponentVersion("net.minecraft", m_minecraftVersion, true); QString loader; - if (!m_fabric_version.isEmpty()) { - components->setComponentVersion("net.fabricmc.fabric-loader", m_fabric_version); + if (!m_fabricVersion.isEmpty()) { + components->setComponentVersion("net.fabricmc.fabric-loader", m_fabricVersion); loader = ModPlatform::getModLoaderAsString(ModPlatform::ModLoaderType::Fabric); } - if (!m_quilt_version.isEmpty()) { - components->setComponentVersion("org.quiltmc.quilt-loader", m_quilt_version); + if (!m_quiltVersion.isEmpty()) { + components->setComponentVersion("org.quiltmc.quilt-loader", m_quiltVersion); loader = ModPlatform::getModLoaderAsString(ModPlatform::ModLoaderType::Quilt); } - if (!m_forge_version.isEmpty()) { - components->setComponentVersion("net.minecraftforge", m_forge_version); + if (!m_forgeVersion.isEmpty()) { + components->setComponentVersion("net.minecraftforge", m_forgeVersion); loader = ModPlatform::getModLoaderAsString(ModPlatform::ModLoaderType::Forge); } - if (!m_neoForge_version.isEmpty()) { - components->setComponentVersion("net.neoforged", m_neoForge_version); + if (!m_neoForgeVersion.isEmpty()) { + components->setComponentVersion("net.neoforged", m_neoForgeVersion); loader = ModPlatform::getModLoaderAsString(ModPlatform::ModLoaderType::NeoForge); } if (m_instIcon != "default") { - instance->setIconKey(m_instIcon); - } else if (!m_managed_id.isEmpty()) { - instance->setIconKey("modrinth"); + m_newInstance->setIconKey(m_instIcon); + } else if (!m_managedId.isEmpty()) { + m_newInstance->setIconKey("modrinth"); } - // Don't add managed info to packs without an ID (most likely imported from ZIP) - if (!m_managed_id.isEmpty()) { - instance->setManagedPack("modrinth", m_managed_id, m_managed_name, m_managed_version_id, version()); - } else { - instance->setManagedPack("modrinth", "", name(), "", ""); - } + setManagedPack(m_newInstance.get()); - instance->setName(name()); - instance->saveNow(); + m_newInstance->setName(name()); + m_newInstance->saveNow(); auto downloadMods = makeShared(tr("Mod Download Modrinth"), APPLICATION->network()); - auto rootModpackPath = FS::PathCombine(m_stagingPath, m_root_path); + auto rootModpackPath = FS::PathCombine(m_stagingPath, m_rootPath); auto rootModpackUrl = QUrl::fromLocalFile(rootModpackPath); // TODO make this work with other sorts of resource - QHash resources; for (auto& file : m_files) { auto fileName = file.path; fileName = FS::RemoveInvalidPathChars(fileName); auto filePath = FS::PathCombine(rootModpackPath, fileName); if (!rootModpackUrl.isParentOf(QUrl::fromLocalFile(filePath))) { // This means we somehow got out of the root folder, so abort here to prevent exploits - setError(tr("One of the files has a path that leads to an arbitrary location (%1). This is a security risk and isn't allowed.") - .arg(fileName)); - return nullptr; + emitFailed( + tr("One of the files has a path that leads to an arbitrary location (%1). This is a security risk and isn't allowed.") + .arg(fileName)); + return; } if (fileName.startsWith("mods/")) { auto* mod = new Mod(filePath); ModDetails d; d.mod_id = filePath; mod->setDetails(d); - resources[file.hash.toHex()] = mod; + m_resources[file.hash.toHex()] = mod; } if (file.downloads.empty()) { - setError(tr("The file '%1' is missing a download link. This is invalid in the pack format.").arg(fileName)); - return nullptr; + emitFailed(tr("The file '%1' is missing a download link. This is invalid in the pack format.").arg(fileName)); + return; } qDebug() << "Will try to download" << file.downloads.front() << "to" << filePath; Net::ModrinthDownloadMeta meta{ - .reason = m_instance.has_value() ? "update" : "modpack", - .gameVersion = m_minecraft_version, + .reason = m_oldInstance.has_value() ? "update" : "modpack", + .gameVersion = m_minecraftVersion, .loader = loader, }; @@ -302,14 +296,9 @@ std::unique_ptr ModrinthCreationTask::createInstance() } } - bool endedWell = false; - - connect(downloadMods.get(), &NetJob::succeeded, this, [&endedWell]() { endedWell = true; }); - connect(downloadMods.get(), &NetJob::failed, [this, &endedWell](const QString& reason) { - endedWell = false; - setError(reason); - }); - connect(downloadMods.get(), &NetJob::finished, &loop, &QEventLoop::quit); + connect(downloadMods.get(), &NetJob::succeeded, this, &ModrinthCreationTask::ensureMetaLoop); + connect(downloadMods.get(), &NetJob::failed, this, &ModrinthCreationTask::emitFailed); + connect(downloadMods.get(), &NetJob::aborted, this, &ModrinthCreationTask::emitAborted); connect(downloadMods.get(), &NetJob::progress, [this](qint64 current, qint64 total) { setDetails(tr("%1 out of %2 complete").arg(current).arg(total)); setProgress(current, total); @@ -319,57 +308,6 @@ std::unique_ptr ModrinthCreationTask::createInstance() setStatus(tr("Downloading mods...")); downloadMods->start(); m_task = downloadMods; - - loop.exec(); - - if (!endedWell) { - for (auto* resource : resources) { - delete resource; - } - return nullptr; - } - - QEventLoop ensureMetaLoop; - QDir folder = FS::PathCombine(instance->modsRoot(), ".index"); - auto ensureMetadataTask = makeShared(resources, folder, ModPlatform::ResourceProvider::MODRINTH); - connect(ensureMetadataTask.get(), &Task::succeeded, this, [&endedWell]() { endedWell = true; }); - connect(ensureMetadataTask.get(), &Task::finished, &ensureMetaLoop, &QEventLoop::quit); - connect(ensureMetadataTask.get(), &Task::progress, [this](qint64 current, qint64 total) { - setDetails(tr("%1 out of %2 complete").arg(current).arg(total)); - setProgress(current, total); - }); - connect(ensureMetadataTask.get(), &Task::stepProgress, this, &ModrinthCreationTask::propagateStepProgress); - - ensureMetadataTask->start(); - m_task = ensureMetadataTask; - - ensureMetaLoop.exec(); - for (auto* resource : resources) { - delete resource; - } - resources.clear(); - - // Update information of the already installed instance, if any. - if (m_instance && endedWell) { - setAbortable(false); - auto* inst = m_instance.value(); - - // Only change the name if it didn't use a custom name, so that the previous custom name - // is preserved, but if we're using the original one, we update the version string. - // NOTE: This needs to come before the copyManagedPack call! - if (inst->name().contains(inst->getManagedPackVersionName()) && inst->name() != instance->name()) { - if (askForChangingInstanceName(m_parent, inst->name(), instance->name()) == InstanceNameChange::ShouldChange) { - inst->setName(instance->name()); - } - } - - inst->copyManagedPack(*instance); - } - - if (endedWell) { - return instance; - } - return nullptr; } bool ModrinthCreationTask::parseManifest(const QString& indexPath, std::vector& files, bool setInternalData, bool showOptionalDialog) @@ -385,10 +323,10 @@ bool ModrinthCreationTask::parseManifest(const QString& indexPath, std::vector(obj, "files", "modrinth.index.json"); @@ -470,15 +408,15 @@ bool ModrinthCreationTask::parseManifest(const QString& indexPath, std::vector(m_resources, folder, ModPlatform::ResourceProvider::MODRINTH); + connect(ensureMetadataTask.get(), &Task::succeeded, this, &ModrinthCreationTask::finishInstall); + connect(ensureMetadataTask.get(), &Task::failed, this, &ModrinthCreationTask::emitFailed); + connect(ensureMetadataTask.get(), &Task::aborted, this, &ModrinthCreationTask::emitAborted); + connect(ensureMetadataTask.get(), &Task::progress, [this](qint64 current, qint64 total) { + setDetails(tr("%1 out of %2 complete").arg(current).arg(total)); + setProgress(current, total); + }); + connect(ensureMetadataTask.get(), &Task::stepProgress, this, &ModrinthCreationTask::propagateStepProgress); + + ensureMetadataTask->start(); + m_task = ensureMetadataTask; +} + +ModrinthCreationTask::~ModrinthCreationTask() +{ + for (auto* resource : m_resources) { + delete resource; + } + m_resources.clear(); +} + +void ModrinthCreationTask::setManagedPack(BaseInstance* instance) +{ + // Don't add managed info to packs without an ID (most likely imported from ZIP) + if (!m_managedId.isEmpty()) { + instance->setManagedPack("modrinth", m_managedId, m_managedName, m_managedVersionId, version()); + } else { + instance->setManagedPack("modrinth", "", name(), "", ""); + } +} + +void ModrinthCreationTask::finishInstall() +{ + // Update information of the already installed instance, if any. + if (m_oldInstance) { + setAbortable(false); + auto* inst = m_oldInstance.value(); + + // Only change the name if it didn't use a custom name, so that the previous custom name + // is preserved, but if we're using the original one, we update the version string. + // NOTE: This needs to come before the setManagedPack call! + if (inst->name().contains(inst->getManagedPackVersionName()) && inst->name() != name()) { + if (askForChangingInstanceName(m_parent, inst->name(), name()) == InstanceNameChange::ShouldChange) { + inst->setName(name()); + } + } + + setManagedPack(m_oldInstance.value()); + } + + if (shouldOverride()) { + bool deleteFailed = false; + + setAbortable(false); + setStatus(tr("Removing old conflicting files...")); + qDebug() << "Removing old files"; + + for (const QString& path : m_filesToRemove) { + if (!QFile::exists(path)) { + continue; + } + + qDebug() << "Removing" << path; + + if (!QFile::remove(path)) { + qCritical() << "Could not remove" << path; + deleteFailed = true; + } + } + + if (deleteFailed) { + emitFailed(tr("Failed to remove old conflicting files.")); + return; + } + } + downloadFiles(m_newInstance.get()); +} diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h index 1b82fbb89..9abf6de5e 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h @@ -10,9 +10,11 @@ #include #include "BaseInstance.h" -#include "InstanceCreationTask.h" +#include "InstanceTask.h" -class ModrinthCreationTask final : public InstanceCreationTask { +class Resource; + +class ModrinthCreationTask final : public InstanceTask { Q_OBJECT struct File { QString path; @@ -30,32 +32,42 @@ class ModrinthCreationTask final : public InstanceCreationTask { QString id, QString versionId = {}, QString originalInstanceId = {}) - : m_parent(parent), m_managed_id(std::move(id)), m_managed_version_id(std::move(versionId)) + : m_parent(parent), m_managedId(std::move(id)), m_managedVersionId(std::move(versionId)) { setStagingPath(stagingPath); setParentSettings(globalSettings); m_originalInstanceId = std::move(originalInstanceId); } + ~ModrinthCreationTask() override; bool abort() override; - bool updateInstance() override; - std::unique_ptr createInstance() override; + void createInstance(); + void executeTask() override; + + private slots: + void finishInstall(); private: bool parseManifest(const QString&, std::vector&, bool setInternalData = true, bool showOptionalDialog = true); + void ensureMetaLoop(); + void setManagedPack(BaseInstance* instance); + private: QWidget* m_parent = nullptr; - QString m_minecraft_version, m_fabric_version, m_quilt_version, m_forge_version, m_neoForge_version; - QString m_managed_id, m_managed_version_id, m_managed_name; + QString m_minecraftVersion, m_fabricVersion, m_quiltVersion, m_forgeVersion, m_neoForgeVersion; + QString m_managedId, m_managedVersionId, m_managedName; std::vector m_files; Task::Ptr m_task; - std::optional m_instance; + std::optional m_oldInstance; + std::unique_ptr m_newInstance{}; - QString m_root_path = "minecraft"; + QString m_rootPath = "minecraft"; + + QHash m_resources; };