diff options
| author | flow <flowlnlnln@gmail.com> | 2022-09-26 08:25:12 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-26 08:25:12 -0300 |
| commit | 370c3aa5985698351e706e61c660a3a566a5f09b (patch) | |
| tree | 5bd62ceec118396d676cf3799edafdb806e4375d /launcher | |
| parent | 58a5331f7bafb149c18f560a0363daab65521262 (diff) | |
| parent | dd6f670dec7dfd1a9ad6f4595ad5447ac735c737 (diff) | |
| download | PrismLauncher-370c3aa5985698351e706e61c660a3a566a5f09b.tar.gz PrismLauncher-370c3aa5985698351e706e61c660a3a566a5f09b.tar.bz2 PrismLauncher-370c3aa5985698351e706e61c660a3a566a5f09b.zip | |
Merge pull request #894 from flowln/update_from_external_source
epic PR
Diffstat (limited to 'launcher')
46 files changed, 1631 insertions, 697 deletions
diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index e6d4d8e3..2995df6f 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -114,44 +114,54 @@ QString BaseInstance::getPostExitCommand() return settings()->get("PostExitCommand").toString(); } -bool BaseInstance::isManagedPack() +bool BaseInstance::isManagedPack() const { - return settings()->get("ManagedPack").toBool(); + return m_settings->get("ManagedPack").toBool(); } -QString BaseInstance::getManagedPackType() +QString BaseInstance::getManagedPackType() const { - return settings()->get("ManagedPackType").toString(); + return m_settings->get("ManagedPackType").toString(); } -QString BaseInstance::getManagedPackID() +QString BaseInstance::getManagedPackID() const { - return settings()->get("ManagedPackID").toString(); + return m_settings->get("ManagedPackID").toString(); } -QString BaseInstance::getManagedPackName() +QString BaseInstance::getManagedPackName() const { - return settings()->get("ManagedPackName").toString(); + return m_settings->get("ManagedPackName").toString(); } -QString BaseInstance::getManagedPackVersionID() +QString BaseInstance::getManagedPackVersionID() const { - return settings()->get("ManagedPackVersionID").toString(); + return m_settings->get("ManagedPackVersionID").toString(); } -QString BaseInstance::getManagedPackVersionName() +QString BaseInstance::getManagedPackVersionName() const { - return settings()->get("ManagedPackVersionName").toString(); + return m_settings->get("ManagedPackVersionName").toString(); } void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version) { - settings()->set("ManagedPack", true); - settings()->set("ManagedPackType", type); - settings()->set("ManagedPackID", id); - settings()->set("ManagedPackName", name); - settings()->set("ManagedPackVersionID", versionId); - settings()->set("ManagedPackVersionName", version); + m_settings->set("ManagedPack", true); + m_settings->set("ManagedPackType", type); + m_settings->set("ManagedPackID", id); + m_settings->set("ManagedPackName", name); + m_settings->set("ManagedPackVersionID", versionId); + 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()); } int BaseInstance::getConsoleMaxLines() const diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 3af104e9..21cc3413 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -140,13 +140,14 @@ public: QString getPostExitCommand(); QString getWrapperCommand(); - bool isManagedPack(); - QString getManagedPackType(); - QString getManagedPackID(); - QString getManagedPackName(); - QString getManagedPackVersionID(); - QString getManagedPackVersionName(); + bool isManagedPack() const; + QString getManagedPackType() const; + QString getManagedPackID() const; + QString getManagedPackName() const; + 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); /// guess log level from a line of game log virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 848d2e51..2ff700ad 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -297,6 +297,8 @@ set(MINECRAFT_SOURCES minecraft/Library.cpp minecraft/Library.h minecraft/MojangDownloadInfo.h + minecraft/VanillaInstanceCreationTask.cpp + minecraft/VanillaInstanceCreationTask.h minecraft/VersionFile.cpp minecraft/VersionFile.h minecraft/VersionFilterData.h @@ -459,6 +461,8 @@ set(API_SOURCES modplatform/helpers/NetworkModAPI.cpp modplatform/helpers/HashUtils.h modplatform/helpers/HashUtils.cpp + modplatform/helpers/OverrideUtils.h + modplatform/helpers/OverrideUtils.cpp ) set(FTB_SOURCES @@ -484,6 +488,8 @@ set(FLAME_SOURCES modplatform/flame/FileResolvingTask.cpp modplatform/flame/FlameCheckUpdate.cpp modplatform/flame/FlameCheckUpdate.h + modplatform/flame/FlameInstanceCreationTask.h + modplatform/flame/FlameInstanceCreationTask.cpp ) set(MODRINTH_SOURCES @@ -493,6 +499,8 @@ set(MODRINTH_SOURCES modplatform/modrinth/ModrinthPackManifest.h modplatform/modrinth/ModrinthCheckUpdate.cpp modplatform/modrinth/ModrinthCheckUpdate.h + modplatform/modrinth/ModrinthInstanceCreationTask.cpp + modplatform/modrinth/ModrinthInstanceCreationTask.h ) set(MODPACKSCH_SOURCES diff --git a/launcher/InstanceCopyTask.cpp b/launcher/InstanceCopyTask.cpp index c2bfe839..b1e33884 100644 --- a/launcher/InstanceCopyTask.cpp +++ b/launcher/InstanceCopyTask.cpp @@ -44,7 +44,7 @@ void InstanceCopyTask::copyFinished() auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg")); InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath)); - inst->setName(m_instName); + inst->setName(name()); inst->setIconKey(m_instIcon); if(!m_keepPlaytime) { inst->resetTimePlayed(); diff --git a/launcher/InstanceCreationTask.cpp b/launcher/InstanceCreationTask.cpp index e01bf306..3971effa 100644 --- a/launcher/InstanceCreationTask.cpp +++ b/launcher/InstanceCreationTask.cpp @@ -1,40 +1,56 @@ #include "InstanceCreationTask.h" -#include "settings/INISettingsObject.h" -#include "FileSystem.h" -//FIXME: remove this -#include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" +#include <QDebug> +#include <QFile> -InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version) -{ - m_version = version; - m_usingLoader = false; -} - -InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion) -{ - m_version = version; - m_usingLoader = true; - m_loader = loader; - m_loaderVersion = loaderVersion; -} +InstanceCreationTask::InstanceCreationTask() = default; void InstanceCreationTask::executeTask() { - setStatus(tr("Creating instance from version %1").arg(m_version->name())); - { - auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg")); - instanceSettings->suspendSave(); - MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath); - auto components = inst.getPackProfile(); - components->buildingFromScratch(); - components->setComponentVersion("net.minecraft", m_version->descriptor(), true); - if(m_usingLoader) - components->setComponentVersion(m_loader, m_loaderVersion->descriptor()); - inst.setName(m_instName); - inst.setIconKey(m_instIcon); - instanceSettings->resumeSave(); + setAbortable(true); + + if (updateInstance()) { + emitSucceeded(); + return; + } + + // When the user aborted in the update stage. + if (m_abort) { + emitAborted(); + return; } + + if (!createInstance()) { + if (m_abort) + return; + + qWarning() << "Instance creation failed!"; + if (!m_error_message.isEmpty()) + qWarning() << "Reason: " << m_error_message; + emitFailed(tr("Error while creating new instance.")); + return; + } + + // If this is set, it means we're updating an instance. So, we now need to remove the + // files scheduled to, and we'd better not let the user abort in the middle of it, since it'd + // put the instance in an invalid state. + if (shouldOverride()) { + setAbortable(false); + setStatus(tr("Removing old conflicting files...")); + qDebug() << "Removing old files"; + + for (auto path : m_files_to_remove) { + if (!QFile::exists(path)) + continue; + qDebug() << "Removing" << path; + if (!QFile::remove(path)) { + qCritical() << "Couldn't remove the old conflicting files."; + emitFailed(tr("Failed to remove old conflicting files.")); + return; + } + } + } + emitSucceeded(); + return; } diff --git a/launcher/InstanceCreationTask.h b/launcher/InstanceCreationTask.h index 23367c3f..03ee1a7a 100644 --- a/launcher/InstanceCreationTask.h +++ b/launcher/InstanceCreationTask.h @@ -1,26 +1,46 @@ #pragma once -#include "tasks/Task.h" -#include "net/NetJob.h" -#include <QUrl> -#include "settings/SettingsObject.h" #include "BaseVersion.h" #include "InstanceTask.h" -class InstanceCreationTask : public InstanceTask -{ +class InstanceCreationTask : public InstanceTask { Q_OBJECT -public: - explicit InstanceCreationTask(BaseVersionPtr version); - explicit InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion); - -protected: - //! Entry point for tasks. - virtual void executeTask() override; - -private: /* data */ - BaseVersionPtr m_version; - bool m_usingLoader; - QString m_loader; - BaseVersionPtr m_loaderVersion; + public: + InstanceCreationTask(); + virtual ~InstanceCreationTask() = default; + + protected: + void executeTask() final override; + + /** + * Tries to update an already existing instance. + * + * This can be implemented by subclasses to provide a way of updating an already existing + * instance, according to that implementation's concept of 'identity' (i.e. instances that + * are updates / downgrades of one another). + * + * If this returns true, createInstance() will not run, so you should do all update steps in here. + * Otherwise, createInstance() is run as normal. + */ + virtual bool updateInstance() { return false; }; + + /** + * Creates a new instance. + * + * Returns whether the instance creation was successful (true) or not (false). + */ + virtual bool createInstance() { return false; }; + + QString getError() const { return m_error_message; } + + protected: + void setError(QString message) { m_error_message = message; }; + + protected: + bool m_abort = false; + + QStringList m_files_to_remove; + + private: + QString m_error_message; }; diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index de0afc96..b490620d 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -35,35 +35,26 @@ */ #include "InstanceImportTask.h" -#include <QtConcurrentRun> + #include "Application.h" -#include "BaseInstance.h" #include "FileSystem.h" #include "MMCZip.h" #include "NullInstance.h" + #include "icons/IconList.h" #include "icons/IconUtils.h" -#include "settings/INISettingsObject.h" -// FIXME: this does not belong here, it's Minecraft/Flame specific -#include <quazip/quazipdir.h> -#include "Json.h" -#include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" -#include "modplatform/flame/FileResolvingTask.h" -#include "modplatform/flame/PackManifest.h" -#include "modplatform/modrinth/ModrinthPackManifest.h" #include "modplatform/technic/TechnicPackProcessor.h" +#include "modplatform/modrinth/ModrinthInstanceCreationTask.h" +#include "modplatform/flame/FlameInstanceCreationTask.h" -#include "Application.h" -#include "icons/IconList.h" -#include "net/ChecksumValidator.h" - -#include "ui/dialogs/CustomMessageBox.h" -#include "ui/dialogs/BlockedModsDialog.h" +#include "settings/INISettingsObject.h" +#include <QtConcurrentRun> #include <algorithm> +#include <quazip/quazipdir.h> + InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent) { m_sourceUrl = sourceUrl; @@ -72,35 +63,41 @@ InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent) bool InstanceImportTask::abort() { + if (!canAbort()) + return false; + if (m_filesNetJob) m_filesNetJob->abort(); m_extractFuture.cancel(); - return false; + return Task::abort(); } void InstanceImportTask::executeTask() { - if (m_sourceUrl.isLocalFile()) - { + setAbortable(true); + + if (m_sourceUrl.isLocalFile()) { m_archivePath = m_sourceUrl.toLocalFile(); processZipPack(); - } - else - { + } else { setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString())); m_downloadRequired = true; - const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path(); + const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path()); + auto entry = APPLICATION->metacache()->resolveEntry("general", path); entry->setStale(true); + m_archivePath = entry->getFullPath(); + m_filesNetJob = new NetJob(tr("Modpack download"), APPLICATION->network()); m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry)); - m_archivePath = entry->getFullPath(); - auto job = m_filesNetJob.get(); - connect(job, &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded); - connect(job, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged); - connect(job, &NetJob::failed, this, &InstanceImportTask::downloadFailed); + + connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded); + connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged); + connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed); + connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted); + m_filesNetJob->start(); } } @@ -119,7 +116,13 @@ void InstanceImportTask::downloadFailed(QString reason) void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total) { - setProgress(current / 2, total); + setProgress(current, total); +} + +void InstanceImportTask::downloadAborted() +{ + emitAborted(); + m_filesNetJob.reset(); } void InstanceImportTask::processZipPack() @@ -255,293 +258,31 @@ void InstanceImportTask::extractFinished() void InstanceImportTask::extractAborted() { - emitFailed(tr("Instance import has been aborted.")); - return; + emitAborted(); } void InstanceImportTask::processFlame() { - const static QMap<QString,QString> forgemap = { - {"1.2.5", "3.4.9.171"}, - {"1.4.2", "6.0.1.355"}, - {"1.4.7", "6.6.2.534"}, - {"1.5.2", "7.8.1.737"} - }; - Flame::Manifest pack; - try - { - QString configPath = FS::PathCombine(m_stagingPath, "manifest.json"); - Flame::loadManifest(pack, configPath); - QFile::remove(configPath); - } - catch (const JSONValidationError &e) - { - emitFailed(tr("Could not understand pack manifest:\n") + e.cause()); - return; - } - if(!pack.overrides.isEmpty()) - { - QString overridePath = FS::PathCombine(m_stagingPath, pack.overrides); - if (QFile::exists(overridePath)) - { - QString mcPath = FS::PathCombine(m_stagingPath, "minecraft"); - if (!QFile::rename(overridePath, mcPath)) - { - emitFailed(tr("Could not rename the overrides folder:\n") + pack.overrides); - return; - } - } - else - { - logWarning(tr("The specified overrides folder (%1) is missing. Maybe the modpack was already used before?").arg(pack.overrides)); - } - } - - QString forgeVersion; - QString fabricVersion; - // TODO: is Quilt relevant here? - for(auto &loader: pack.minecraft.modLoaders) - { - auto id = loader.id; - if(id.startsWith("forge-")) - { - id.remove("forge-"); - forgeVersion = id; - continue; - } - if(id.startsWith("fabric-")) - { - id.remove("fabric-"); - fabricVersion = id; - continue; - } - logWarning(tr("Unknown mod loader in manifest: %1").arg(id)); - } + auto* inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent); - QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); - auto instanceSettings = std::make_shared<INISettingsObject>(configPath); - MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); - auto mcVersion = pack.minecraft.version; - // Hack to correct some 'special sauce'... - if(mcVersion.endsWith('.')) - { - mcVersion.remove(QRegularExpression("[.]+$")); - logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack.")); - } - auto components = instance.getPackProfile(); - components->buildingFromScratch(); - components->setComponentVersion("net.minecraft", mcVersion, true); - if(!forgeVersion.isEmpty()) - { - // FIXME: dirty, nasty, hack. Proper solution requires dependency resolution and knowledge of the metadata. - if(forgeVersion == "recommended") - { - if(forgemap.contains(mcVersion)) - { - forgeVersion = forgemap[mcVersion]; - } - else - { - logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion)); - } - } - components->setComponentVersion("net.minecraftforge", forgeVersion); - } - if(!fabricVersion.isEmpty()) - { - components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion); - } - if (m_instIcon != "default") - { - instance.setIconKey(m_instIcon); - } - else - { - if(pack.name.contains("Direwolf20")) - { - instance.setIconKey("steve"); - } - else if(pack.name.contains("FTB") || pack.name.contains("Feed The Beast")) - { - instance.setIconKey("ftb_logo"); - } - else - { - // default to something other than the MultiMC default to distinguish these - instance.setIconKey("flame"); - } - } - QString jarmodsPath = FS::PathCombine(m_stagingPath, "minecraft", "jarmods"); - QFileInfo jarmodsInfo(jarmodsPath); - if(jarmodsInfo.isDir()) - { - // install all the jar mods - qDebug() << "Found jarmods:"; - QDir jarmodsDir(jarmodsPath); - QStringList jarMods; - for (auto info: jarmodsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files)) - { - qDebug() << info.fileName(); - jarMods.push_back(info.absoluteFilePath()); - } - auto profile = instance.getPackProfile(); - profile->installJarMods(jarMods); - // nuke the original files - FS::deletePath(jarmodsPath); - } - instance.setName(m_instName); - m_modIdResolver = new Flame::FileResolvingTask(APPLICATION->network(), pack); - connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]() - { - auto results = m_modIdResolver->getResults(); - //first check for blocked mods - QString text; - QList<QUrl> urls; - auto anyBlocked = false; - for(const auto& result: results.files.values()) { - if (!result.resolved || result.url.isEmpty()) { - text += QString("%1: <a href='%2'>%2</a><br/>").arg(result.fileName, result.websiteUrl); - urls.append(QUrl(result.websiteUrl)); - anyBlocked = true; - } - } - if(anyBlocked) { - qWarning() << "Blocked mods found, displaying mod list"; - - auto message_dialog = new BlockedModsDialog(m_parent, - tr("Blocked mods found"), - tr("The following mods were blocked on third party launchers.<br/>" - "You will need to manually download them and add them to the modpack"), - text, - urls); - message_dialog->setModal(true); - - if (message_dialog->exec()) { - m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network()); - for (const auto &result: m_modIdResolver->getResults().files) { - QString filename = result.fileName; - if (!result.required) { - filename += ".disabled"; - } - - auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename); - auto path = FS::PathCombine(m_stagingPath, relpath); - - switch (result.type) { - case Flame::File::Type::Folder: { - logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath)); - // fall-through intentional, we treat these as plain old mods and dump them wherever. - } - case Flame::File::Type::SingleFile: - case Flame::File::Type::Mod: { |
