From 106155dd627d8e333260e2460d4c9c558b49b21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 16 Mar 2018 23:33:58 +0100 Subject: NOISSUE move modpack platform related files to 'modplatform' subfolders --- api/logic/CMakeLists.txt | 34 +++-- api/logic/FolderInstanceProvider.cpp | 2 +- api/logic/FolderInstanceProvider.h | 2 +- api/logic/InstanceImportTask.cpp | 4 +- api/logic/minecraft/flame/FileResolvingTask.cpp | 117 --------------- api/logic/minecraft/flame/FileResolvingTask.h | 32 ---- api/logic/minecraft/flame/PackManifest.cpp | 66 --------- api/logic/minecraft/flame/PackManifest.h | 59 -------- api/logic/modplatform/FtbPackDownloader.cpp | 109 -------------- api/logic/modplatform/FtbPackDownloader.h | 64 -------- api/logic/modplatform/FtbPackFetchTask.cpp | 96 ------------ api/logic/modplatform/FtbPackFetchTask.h | 33 ----- api/logic/modplatform/FtbPackInstallTask.cpp | 173 ---------------------- api/logic/modplatform/FtbPackInstallTask.h | 55 ------- api/logic/modplatform/PackHelpers.h | 26 ---- api/logic/modplatform/flame/FileResolvingTask.cpp | 117 +++++++++++++++ api/logic/modplatform/flame/FileResolvingTask.h | 32 ++++ api/logic/modplatform/flame/PackManifest.cpp | 66 +++++++++ api/logic/modplatform/flame/PackManifest.h | 59 ++++++++ api/logic/modplatform/ftb/FtbPackDownloader.cpp | 109 ++++++++++++++ api/logic/modplatform/ftb/FtbPackDownloader.h | 64 ++++++++ api/logic/modplatform/ftb/FtbPackFetchTask.cpp | 96 ++++++++++++ api/logic/modplatform/ftb/FtbPackFetchTask.h | 33 +++++ api/logic/modplatform/ftb/FtbPackInstallTask.cpp | 173 ++++++++++++++++++++++ api/logic/modplatform/ftb/FtbPackInstallTask.h | 55 +++++++ api/logic/modplatform/ftb/PackHelpers.h | 26 ++++ application/FtbListModel.h | 2 +- application/MainWindow.cpp | 3 +- application/MainWindow.h | 2 +- application/dialogs/ChooseFtbPackDialog.h | 3 +- application/dialogs/NewInstanceDialog.h | 4 +- 31 files changed, 859 insertions(+), 857 deletions(-) delete mode 100644 api/logic/minecraft/flame/FileResolvingTask.cpp delete mode 100644 api/logic/minecraft/flame/FileResolvingTask.h delete mode 100644 api/logic/minecraft/flame/PackManifest.cpp delete mode 100644 api/logic/minecraft/flame/PackManifest.h delete mode 100644 api/logic/modplatform/FtbPackDownloader.cpp delete mode 100644 api/logic/modplatform/FtbPackDownloader.h delete mode 100644 api/logic/modplatform/FtbPackFetchTask.cpp delete mode 100644 api/logic/modplatform/FtbPackFetchTask.h delete mode 100644 api/logic/modplatform/FtbPackInstallTask.cpp delete mode 100644 api/logic/modplatform/FtbPackInstallTask.h delete mode 100644 api/logic/modplatform/PackHelpers.h create mode 100644 api/logic/modplatform/flame/FileResolvingTask.cpp create mode 100644 api/logic/modplatform/flame/FileResolvingTask.h create mode 100644 api/logic/modplatform/flame/PackManifest.cpp create mode 100644 api/logic/modplatform/flame/PackManifest.h create mode 100644 api/logic/modplatform/ftb/FtbPackDownloader.cpp create mode 100644 api/logic/modplatform/ftb/FtbPackDownloader.h create mode 100644 api/logic/modplatform/ftb/FtbPackFetchTask.cpp create mode 100644 api/logic/modplatform/ftb/FtbPackFetchTask.h create mode 100644 api/logic/modplatform/ftb/FtbPackInstallTask.cpp create mode 100644 api/logic/modplatform/ftb/FtbPackInstallTask.h create mode 100644 api/logic/modplatform/ftb/PackHelpers.h diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 404044d8..e40f188e 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -277,12 +277,6 @@ set(MINECRAFT_SOURCES minecraft/WorldList.h minecraft/WorldList.cpp - # Flame - minecraft/flame/PackManifest.h - minecraft/flame/PackManifest.cpp - minecraft/flame/FileResolvingTask.h - minecraft/flame/FileResolvingTask.cpp - # Assets minecraft/AssetsUtils.h minecraft/AssetsUtils.cpp @@ -418,18 +412,25 @@ set(META_SOURCES meta/Index.h ) -set(MODPLATFORM_SOURCES - # Modplatform sources - modplatform/FtbPackDownloader.h - modplatform/FtbPackDownloader.cpp +set(FTB_SOURCES + # Modplatform sources + modplatform/ftb/FtbPackDownloader.h + modplatform/ftb/FtbPackDownloader.cpp - modplatform/FtbPackFetchTask.h - modplatform/FtbPackFetchTask.cpp - modplatform/FtbPackInstallTask.h - modplatform/FtbPackInstallTask.cpp + modplatform/ftb/FtbPackFetchTask.h + modplatform/ftb/FtbPackFetchTask.cpp + modplatform/ftb/FtbPackInstallTask.h + modplatform/ftb/FtbPackInstallTask.cpp - modplatform/PackHelpers.h + modplatform/ftb/PackHelpers.h +) +set(FLAME_SOURCES + # Flame + modplatform/flame/PackManifest.h + modplatform/flame/PackManifest.cpp + modplatform/flame/FileResolvingTask.h + modplatform/flame/FileResolvingTask.cpp ) add_unit_test(Index @@ -460,7 +461,8 @@ set(LOGIC_SOURCES ${TOOLS_SOURCES} ${META_SOURCES} ${ICONS_SOURCES} - ${MODPLATFORM_SOURCES} + ${FTB_SOURCES} + ${FLAME_SOURCES} ) add_library(MultiMC_logic SHARED ${LOGIC_SOURCES}) diff --git a/api/logic/FolderInstanceProvider.cpp b/api/logic/FolderInstanceProvider.cpp index a6d3bdc8..52e23254 100644 --- a/api/logic/FolderInstanceProvider.cpp +++ b/api/logic/FolderInstanceProvider.cpp @@ -428,7 +428,7 @@ Task * FolderInstanceProvider::creationTask(BaseVersionPtr version, const QStrin return new FolderInstanceStaging(this, task, stagingPath, instName, instGroup); } -#include +#include Task * FolderInstanceProvider::ftbCreationTask(FtbPackDownloader *downloader, const QString& instName, const QString& instGroup, const QString& instIcon) { auto stagingPath = getStagedInstancePath(); diff --git a/api/logic/FolderInstanceProvider.h b/api/logic/FolderInstanceProvider.h index 5117affc..2641a46b 100644 --- a/api/logic/FolderInstanceProvider.h +++ b/api/logic/FolderInstanceProvider.h @@ -2,7 +2,7 @@ #include "BaseInstanceProvider.h" #include -#include +#include class QFileSystemWatcher; diff --git a/api/logic/InstanceImportTask.cpp b/api/logic/InstanceImportTask.cpp index 2b481300..7fae97b8 100644 --- a/api/logic/InstanceImportTask.cpp +++ b/api/logic/InstanceImportTask.cpp @@ -12,8 +12,8 @@ // FIXME: this does not belong here, it's Minecraft/Flame specific #include "minecraft/MinecraftInstance.h" #include "minecraft/ComponentList.h" -#include "minecraft/flame/FileResolvingTask.h" -#include "minecraft/flame/PackManifest.h" +#include "modplatform/flame/FileResolvingTask.h" +#include "modplatform/flame/PackManifest.h" #include "Json.h" InstanceImportTask::InstanceImportTask(SettingsObjectPtr settings, const QUrl sourceUrl, const QString & stagingPath, diff --git a/api/logic/minecraft/flame/FileResolvingTask.cpp b/api/logic/minecraft/flame/FileResolvingTask.cpp deleted file mode 100644 index efc73621..00000000 --- a/api/logic/minecraft/flame/FileResolvingTask.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "FileResolvingTask.h" -#include "Json.h" - -const char * metabase = "https://cursemeta.dries007.net"; - -Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess) - : m_toProcess(toProcess) -{ -} - -void Flame::FileResolvingTask::executeTask() -{ - setStatus(tr("Resolving mod IDs...")); - setProgress(0, m_toProcess.files.size()); - m_dljob.reset(new NetJob("Mod id resolver")); - results.resize(m_toProcess.files.size()); - int index = 0; - for(auto & file: m_toProcess.files) - { - auto projectIdStr = QString::number(file.projectId); - auto fileIdStr = QString::number(file.fileId); - QString metaurl = QString("%1/%2/%3.json").arg(metabase, projectIdStr, fileIdStr); - auto dl = Net::Download::makeByteArray(QUrl(metaurl), &results[index]); - m_dljob->addNetAction(dl); - index ++; - } - connect(m_dljob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::netJobFinished); - m_dljob->start(); -} - -void Flame::FileResolvingTask::netJobFinished() -{ - bool failed = false; - int index = 0; - for(auto & bytes: results) - { - try - { - auto doc = Json::requireDocument(bytes); - auto obj = Json::requireObject(doc); - auto & out = m_toProcess.files[index]; - // result code signifies true failure. - if(obj.contains("code")) - { - qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a negative result:"; - qCritical() << bytes; - failed = true; - continue; - } - out.fileName = Json::requireString(obj, "FileNameOnDisk"); - QString rawUrl = Json::requireString(obj, "DownloadURL"); - out.url = QUrl(rawUrl, QUrl::TolerantMode); - if(!out.url.isValid()) - { - throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); - } - // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience - // It is also optional - QJsonObject projObj = Json::ensureObject(obj, "_Project", {}); - if(!projObj.isEmpty()) - { - QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower(); - if(strType == "singlefile") - { - out.type = File::Type::SingleFile; - } - else if(strType == "ctoc") - { - out.type = File::Type::Ctoc; - } - else if(strType == "cmod2") - { - out.type = File::Type::Cmod2; - } - else if(strType == "mod") - { - out.type = File::Type::Mod; - } - else if(strType == "folder") - { - out.type = File::Type::Folder; - } - else if(strType == "modpack") - { - out.type = File::Type::Modpack; - } - else - { - qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of unknown file type:" << strType; - out.type = File::Type::Unknown; - failed = true; - continue; - } - out.targetFolder = Json::ensureString(projObj, "Path", "mods"); - } - out.resolved = true; - } - catch(JSONValidationError & e) - { - auto & out = m_toProcess.files[index]; - qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:"; - qCritical() << e.cause(); - qCritical() << "JSON:"; - qCritical() << bytes; - failed = true; - } - index++; - } - if(!failed) - { - emitSucceeded(); - } - else - { - emitFailed(tr("Some mod ID resolving tasks failed.")); - } -} diff --git a/api/logic/minecraft/flame/FileResolvingTask.h b/api/logic/minecraft/flame/FileResolvingTask.h deleted file mode 100644 index 00658452..00000000 --- a/api/logic/minecraft/flame/FileResolvingTask.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "tasks/Task.h" -#include "net/NetJob.h" -#include "PackManifest.h" - -#include "multimc_logic_export.h" - -namespace Flame -{ -class MULTIMC_LOGIC_EXPORT FileResolvingTask : public Task -{ - Q_OBJECT -public: - explicit FileResolvingTask(Flame::Manifest &toProcess); - const Flame::Manifest &getResults() const - { - return m_toProcess; - } - -protected: - virtual void executeTask() override; - -protected slots: - void netJobFinished(); - -private: /* data */ - Flame::Manifest m_toProcess; - QVector results; - NetJobPtr m_dljob; -}; -} diff --git a/api/logic/minecraft/flame/PackManifest.cpp b/api/logic/minecraft/flame/PackManifest.cpp deleted file mode 100644 index 6a9324fe..00000000 --- a/api/logic/minecraft/flame/PackManifest.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "PackManifest.h" -#include "Json.h" - -static void loadFileV1(Flame::File & f, QJsonObject & file) -{ - f.projectId = Json::requireInteger(file, "projectID"); - f.fileId = Json::requireInteger(file, "fileID"); - f.required = Json::ensureBoolean(file, QString("required"), true); -} - -static void loadModloaderV1(Flame::Modloader & m, QJsonObject & modLoader) -{ - m.id = Json::requireString(modLoader, "id"); - m.primary = Json::ensureBoolean(modLoader, QString("primary"), false); -} - -static void loadMinecraftV1(Flame::Minecraft & m, QJsonObject & minecraft) -{ - m.version = Json::requireString(minecraft, "version"); - // extra libraries... apparently only used for a custom Minecraft launcher in the 1.2.5 FTB retro pack - // intended use is likely hardcoded in the 'Flame' client, the manifest says nothing - m.libraries = Json::ensureString(minecraft, QString("libraries"), QString()); - auto arr = Json::ensureArray(minecraft, "modLoaders", QJsonArray()); - for (const auto & item : arr) - { - auto obj = Json::requireObject(item); - Flame::Modloader loader; - loadModloaderV1(loader, obj); - m.modLoaders.append(loader); - } -} - -static void loadManifestV1(Flame::Manifest & m, QJsonObject & manifest) -{ - auto mc = Json::requireObject(manifest, "minecraft"); - loadMinecraftV1(m.minecraft, mc); - m.name = Json::ensureString(manifest, QString("name"), "Unnamed"); - m.version = Json::ensureString(manifest, QString("version"), QString()); - m.author = Json::ensureString(manifest, QString("author"), "Anonymous Coward"); - auto arr = Json::ensureArray(manifest, "files", QJsonArray()); - for (const auto & item : arr) - { - auto obj = Json::requireObject(item); - Flame::File file; - loadFileV1(file, obj); - m.files.append(file); - } - m.overrides = Json::ensureString(manifest, "overrides", "overrides"); -} - -void Flame::loadManifest(Flame::Manifest & m, const QString &filepath) -{ - auto doc = Json::requireDocument(filepath); - auto obj = Json::requireObject(doc); - m.manifestType = Json::requireString(obj, "manifestType"); - if(m.manifestType != "minecraftModpack") - { - throw JSONValidationError("Not a modpack manifest!"); - } - m.manifestVersion = Json::requireInteger(obj, "manifestVersion"); - if(m.manifestVersion != 1) - { - throw JSONValidationError(QString("Unknown manifest version (%1)").arg(m.manifestVersion)); - } - loadManifestV1(m, obj); -} diff --git a/api/logic/minecraft/flame/PackManifest.h b/api/logic/minecraft/flame/PackManifest.h deleted file mode 100644 index 1a5254a8..00000000 --- a/api/logic/minecraft/flame/PackManifest.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Flame -{ -struct File -{ - int projectId = 0; - int fileId = 0; - // NOTE: the opposite to 'optional'. This is at the time of writing unused. - bool required = true; - - // our - bool resolved = false; - QString fileName; - QUrl url; - QString targetFolder = QLatin1Literal("mods"); - enum class Type - { - Unknown, - Folder, - Ctoc, - SingleFile, - Cmod2, - Modpack, - Mod - } type = Type::Mod; -}; - -struct Modloader -{ - QString id; - bool primary = false; -}; - -struct Minecraft -{ - QString version; - QString libraries; - QVector modLoaders; -}; - -struct Manifest -{ - QString manifestType; - int manifestVersion = 0; - Flame::Minecraft minecraft; - QString name; - QString version; - QString author; - QVector files; - QString overrides; -}; - -void loadManifest(Flame::Manifest & m, const QString &filepath); -} diff --git a/api/logic/modplatform/FtbPackDownloader.cpp b/api/logic/modplatform/FtbPackDownloader.cpp deleted file mode 100644 index caadd4ae..00000000 --- a/api/logic/modplatform/FtbPackDownloader.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "FtbPackDownloader.h" -#include "PackHelpers.h" -#include "FtbPackFetchTask.h" -#include "Env.h" - -FtbPackDownloader::FtbPackDownloader() { - done = false; - fetching = false; -} - -FtbPackDownloader::~FtbPackDownloader(){ -} - -bool FtbPackDownloader::isValidPackSelected(){ - FtbModpack dummy; - dummy.name = "__INVALID__"; - - FtbModpack other = fetchedPacks.value(selected.name, dummy); - if(other.name == "__INVALID__") { - return false; - } - - return other.oldVersions.contains(selectedVersion) && !other.broken; -} - -QString FtbPackDownloader::getSuggestedInstanceName() { - return selected.name; -} - -FtbModpackList FtbPackDownloader::getModpacks() { - return static_cast(fetchedPacks.values()); -} - -void FtbPackDownloader::fetchModpacks(bool force = false){ - if(fetching || (!force && done)) { - qDebug() << "Skipping modpack refetch because done or already fetching [done =>" << done << "| fetching =>" << fetching << "]"; - return; - } - - fetching = true; - - fetchTask = new FtbPackFetchTask(); - connect(fetchTask, &FtbPackFetchTask::finished, this, &FtbPackDownloader::fetchSuccess); - connect(fetchTask, &FtbPackFetchTask::failed, this, &FtbPackDownloader::fetchFailed); - fetchTask->fetch(); -} - - -void FtbPackDownloader::fetchSuccess(FtbModpackList modpacks) { - for(int i = 0; i < modpacks.size(); i++) { - fetchedPacks.insert(modpacks.at(i).name, modpacks.at(i)); - } - - fetching = false; - done = true; - emit ready(); - fetchTask->deleteLater(); -} - -void FtbPackDownloader::fetchFailed(QString reason) { - qWarning() << "Failed to fetch FtbData" << reason; - fetching = false; - emit packFetchFailed(); - fetchTask->deleteLater(); -} - -void FtbPackDownloader::selectPack(FtbModpack modpack, QString version) { - selected = modpack; - selectedVersion = version; -} - -FtbModpack FtbPackDownloader::getSelectedPack() { - return selected; -} - -void FtbPackDownloader::downloadSelected(MetaEntryPtr cache) { - NetJob *job = new NetJob("Downlad FTB Pack"); - - cache->setStale(true); - QString url = QString("http://ftb.cursecdn.com/FTB2/modpacks/%1/%2/%3").arg(selected.dir, selectedVersion.replace(".", "_"), selected.file); - job->addNetAction(Net::Download::makeCached(url, cache)); - downloadPath = cache->getFullPath(); - - netJobContainer.reset(job); - - connect(job, &NetJob::succeeded, this, &FtbPackDownloader::_downloadSucceeded); - connect(job, &NetJob::failed, this, &FtbPackDownloader::_downloadFailed); - connect(job, &NetJob::progress, this, &FtbPackDownloader::_downloadProgress); - job->start(); -} - -void FtbPackDownloader::_downloadSucceeded() { - netJobContainer.reset(); - emit downloadSucceded(downloadPath); -} - -void FtbPackDownloader::_downloadProgress(qint64 current, qint64 total) { - emit downloadProgress(current, total); -} - -void FtbPackDownloader::_downloadFailed(QString reason) { - netJobContainer.reset(); - emit downloadFailed(reason); -} - -NetJobPtr FtbPackDownloader::getNetJob() -{ - return netJobContainer; -} diff --git a/api/logic/modplatform/FtbPackDownloader.h b/api/logic/modplatform/FtbPackDownloader.h deleted file mode 100644 index c5cc9bd2..00000000 --- a/api/logic/modplatform/FtbPackDownloader.h +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include -#include "FtbPackFetchTask.h" -#include "tasks/Task.h" -#include "net/NetJob.h" - -#include "PackHelpers.h" -#include "Env.h" - -#pragma once - -class FtbPackDownloader; -class MULTIMC_LOGIC_EXPORT FtbPackDownloader : public QObject { - - Q_OBJECT - -private: - QMap fetchedPacks; - bool fetching = false; - bool done = false; - - FtbModpack selected; - QString selectedVersion; - QString downloadPath; - - FtbPackFetchTask *fetchTask = 0; - NetJobPtr netJobContainer; - - void _downloadSucceeded(); - void _downloadFailed(QString reason); - void _downloadProgress(qint64 current, qint64 total); - -private slots: - void fetchSuccess(FtbModpackList modlist); - void fetchFailed(QString reason); - -public: - FtbPackDownloader(); - ~FtbPackDownloader(); - - bool isValidPackSelected(); - void selectPack(FtbModpack modpack, QString version); - - FtbModpack getSelectedPack(); - - void fetchModpacks(bool force); - void downloadSelected(MetaEntryPtr cache); - - QString getSuggestedInstanceName(); - - FtbModpackList getModpacks(); - NetJobPtr getNetJob(); - -signals: - void ready(); - void packFetchFailed(); - - void downloadSucceded(QString archivePath); - void downloadFailed(QString reason); - void downloadProgress(qint64 current, qint64 total); - -}; diff --git a/api/logic/modplatform/FtbPackFetchTask.cpp b/api/logic/modplatform/FtbPackFetchTask.cpp deleted file mode 100644 index 9e151186..00000000 --- a/api/logic/modplatform/FtbPackFetchTask.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "FtbPackFetchTask.h" -#include - -FtbPackFetchTask::FtbPackFetchTask() { - -} - -FtbPackFetchTask::~FtbPackFetchTask() { - -} - -void FtbPackFetchTask::fetch() { - NetJob *netJob = new NetJob("FtbModpackFetch"); - - QUrl url = QUrl("https://ftb.cursecdn.com/FTB2/static/modpacks.xml"); - qDebug() << "Downloading version info from " << url.toString(); - - netJob->addNetAction(downloadPtr = Net::Download::makeByteArray(url, &modpacksXmlFileData)); - - QObject::connect(netJob, &NetJob::succeeded, this, &FtbPackFetchTask::fileDownloadFinished); - QObject::connect(netJob, &NetJob::failed, this, &FtbPackFetchTask::fileDownloadFailed); - - jobPtr.reset(netJob); - netJob->start(); -} - -void FtbPackFetchTask::fileDownloadFinished(){ - - jobPtr.reset(); - - QDomDocument doc; - - QString errorMsg = "Unknown error."; - int errorLine = -1; - int errorCol = -1; - - if(!doc.setContent(modpacksXmlFileData, false, &errorMsg, &errorLine, &errorCol)){ - auto fullErrMsg = QString("Failed to fetch modpack data: %s %d:%d!").arg(errorMsg, errorLine, errorCol); - qWarning() << fullErrMsg; - emit failed(fullErrMsg); - modpacksXmlFileData.clear(); - return; - } - - modpacksXmlFileData.clear(); - - FtbModpackList modpackList; - - QDomNodeList nodes = doc.elementsByTagName("modpack"); - for(int i = 0; i < nodes.length(); i++) { - QDomElement element = nodes.at(i).toElement(); - - FtbModpack modpack; - modpack.name = element.attribute("name"); - modpack.currentVersion = element.attribute("version"); - modpack.mcVersion = element.attribute("mcVersion"); - modpack.description = element.attribute("description"); - modpack.mods = element.attribute("mods"); - modpack.image = element.attribute("image"); - modpack.oldVersions = element.attribute("oldVersions").split(";"); - - //remove empty if the xml is bugged - for(QString curr : modpack.oldVersions) { - if(curr.isNull() || curr.isEmpty()) { - modpack.oldVersions.removeAll(curr); - modpack.bugged = true; - qWarning() << "Removed some empty versions from" << modpack.name; - } - } - - if(modpack.oldVersions.size() < 1) { - if(!modpack.currentVersion.isNull() && !modpack.currentVersion.isEmpty()) { - modpack.oldVersions.append(modpack.currentVersion); - qWarning() << "Added current version to oldVersions because oldVersions was empty! (" + modpack.name + ")"; - } else { - modpack.broken = true; - qWarning() << "Broken pack:" << modpack.name << " => No valid version!"; - } - } - - modpack.author = element.attribute("author"); - - modpack.dir = element.attribute("dir"); - modpack.file = element.attribute("url"); - - modpackList.append(modpack); - } - - - emit finished(modpackList); -} - -void FtbPackFetchTask::fileDownloadFailed(QString reason){ - qWarning() << "Fetching FtbPacks failed: " << reason; - emit failed(reason); -} diff --git a/api/logic/modplatform/FtbPackFetchTask.h b/api/logic/modplatform/FtbPackFetchTask.h deleted file mode 100644 index 3cfac4ed..00000000 --- a/api/logic/modplatform/FtbPackFetchTask.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "net/NetJob.h" -#include -#include -#include -#include "PackHelpers.h" - -class MULTIMC_LOGIC_EXPORT FtbPackFetchTask : public QObject { - - Q_OBJECT - -public: - FtbPackFetchTask(); - ~FtbPackFetchTask(); - - void fetch(); - -private: - NetJobPtr jobPtr; - Net::Download::Ptr downloadPtr; - - QByteArray modpacksXmlFileData; - -protected slots: - void fileDownloadFinished(); - void fileDownloadFailed(QString reason); - -signals: - void finished(FtbModpackList list); - void failed(QString reason); - -}; diff --git a/api/logic/modplatform/FtbPackInstallTask.cpp b/api/logic/modplatform/FtbPackInstallTask.cpp deleted file mode 100644 index 530f72ca..00000000 --- a/api/logic/modplatform/FtbPackInstallTask.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "FtbPackInstallTask.h" -#include "Env.h" -#include "MMCZip.h" -#include "QtConcurrent" -#include "BaseInstance.h" -#include "FileSystem.h" -#include "settings/INISettingsObject.h" -#include "minecraft/MinecraftInstance.h" -#include "minecraft/ComponentList.h" -#include "minecraft/GradleSpecifier.h" - -FtbPackInstallTask::FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, - const QString &stagingPath, const QString &instName, const QString &instIcon, const QString &instGroup) : - m_globalSettings(settings), m_stagingPath(stagingPath), m_instName(instName), m_instIcon(instIcon), m_instGroup(instGroup) -{ - m_downloader = downloader; -} - -void FtbPackInstallTask::executeTask() { - downloadPack(); -} - -void FtbPackInstallTask::downloadPack(){ - FtbModpack toInstall = m_downloader->getSelectedPack(); - setStatus(tr("Downloading zip for %1").arg(toInstall.name)); - - auto entry = ENV.metacache()->resolveEntry("general", "FTBPacks/" + toInstall.name); - m_downloader->downloadSelected(entry); - - connect(m_downloader, &FtbPackDownloader::downloadSucceded, this, &FtbPackInstallTask::onDownloadSucceeded); - connect(m_downloader, &FtbPackDownloader::downloadProgress, this, &FtbPackInstallTask::onDownloadProgress); - connect(m_downloader, &FtbPackDownloader::downloadFailed, this,&FtbPackInstallTask::onDownloadFailed); - progress(1, 4); -} - -void FtbPackInstallTask::onDownloadSucceeded(QString archivePath){ - abortable = false; - unzip(archivePath); -} - -void FtbPackInstallTask::onDownloadFailed(QString reason) { - emitFailed(reason); -} - -void FtbPackInstallTask::onDownloadProgress(qint64 current, qint64 total){ - abortable = true; - progress(current, total * 4); - setStatus(tr("Downloading zip for %1 (%2\%)").arg(m_downloader->getSelectedPack().name).arg(current / 10)); -} - -void FtbPackInstallTask::unzip(QString archivePath) { - progress(2, 4); - setStatus(tr("Extracting modpack")); - QDir extractDir(m_stagingPath); - - m_packZip.reset(new QuaZip(archivePath)); - if(!m_packZip->open(QuaZip::mdUnzip)) { - emitFailed(tr("Failed to open modpack file %1!").arg(archivePath)); - return; - } - - m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip"); - connect(&m_extractFutureWatcher, &QFutureWatcher::finished, this, &FtbPackInstallTask::onUnzipFinished); - connect(&m_extractFutureWatcher, &QFutureWatcher::canceled, this, &FtbPackInstallTask::onUnzipCanceled); - m_extractFutureWatcher.setFuture(m_extractFuture); -} - -void FtbPackInstallTask::onUnzipFinished() { - install(); -} - -void FtbPackInstallTask::onUnzipCanceled() { - emitAborted(); -} - -void FtbPackInstallTask::install() { - progress(3, 4); - FtbModpack toInstall = m_downloader->getSelectedPack(); - setStatus(tr("Installing modpack")); - QDir unzipMcDir(m_stagingPath + "/unzip/minecraft"); - if(unzipMcDir.exists()) { - //ok, found minecraft dir, move contents to instance dir - if(!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft")) { - emitFailed(tr("Failed to move unzipped minecraft!")); - return; - } - } - - QString instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg"); - auto instanceSettings = std::make_shared(instanceConfigPath); - instanceSettings->registerSetting("InstanceType", "Legacy"); - instanceSettings->set("InstanceType", "OneSix"); - - MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); - auto components = instance.getComponentList(); - components->buildingFromScratch(); - components->setComponentVersion("net.minecraft", toInstall.mcVersion, true); - - bool fallback = true; - - //handle different versions - QFile packJson(m_stagingPath + "/.minecraft/pack.json"); - QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods"); - if(packJson.exists()) { - packJson.open(QIODevice::ReadOnly | QIODevice::Text); - QJsonDocument doc = QJsonDocument::fromJson(packJson.readAll()); - packJson.close(); - - //we only care about the libs - QJsonArray libs = doc.object().value("libraries").toArray(); - - foreach (const QJsonValue &value, libs) { - QString nameValue = value.toObject().value("name").toString(); - if(!nameValue.startsWith("net.minecraftforge")) { - continue; - } - - GradleSpecifier forgeVersion(nameValue); - - components->setComponentVersion("net.minecraftforge", forgeVersion.version().replace(toInstall.mcVersion, "").replace("-", "")); - packJson.remove(); - fallback = false; - break; - } - - } - - if(jarmodDir.exists()) { - qDebug() << "Found jarmods, installing..."; - - QStringList jarmods; - for (auto info: jarmodDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files)) - { - qDebug() << "Jarmod:" << info.fileName(); - jarmods.push_back(info.absoluteFilePath()); - } - - components->installJarMods(jarmods); - fallback = false; - } - - //just nuke unzip directory, it s not needed anymore - FS::deletePath(m_stagingPath + "/unzip"); - - if(fallback) { - //TODO: Some fallback mechanism... or just keep failing! - emitFailed(tr("No installation method found!")); - return; - } - - components->saveNow(); - - progress(4, 4); - - instance.init(); - instance.setName(m_instName); - if(m_instIcon == "default") { - m_instIcon = "ftb_logo"; - } - instance.setIconKey(m_instIcon); - instance.setGroupInitial(m_instGroup); - instanceSettings->resumeSave(); - - emitSucceeded(); -} - -bool FtbPackInstallTask::abort() -{ - if(abortable) { - return m_downloader->getNetJob()->abort(); - } - return false; -} diff --git a/api/logic/modplatform/FtbPackInstallTask.h b/api/logic/modplatform/FtbPackInstallTask.h deleted file mode 100644 index cf477ae2..00000000 --- a/api/logic/modplatform/FtbPackInstallTask.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "tasks/Task.h" -#include "modplatform/FtbPackDownloader.h" -#include "BaseInstanceProvider.h" -#include "net/NetJob.h" -#include "quazip.h" -#include "quazipdir.h" -#include "meta/Index.h" -#include "meta/Version.h" -#include "meta/VersionList.h" - -class MULTIMC_LOGIC_EXPORT FtbPackInstallTask : public Task { - - Q_OBJECT - -public: - explicit FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, const QString &stagingPath, const QString &instName, - const QString &instIcon, const QString &instGroup); - bool abort() override; - -protected: - //! Entry point for tasks. - virtual void executeTask() override; - -private: /* data */ - SettingsObjectPtr m_globalSettings; - QString m_stagingPath; - QString m_instName; - QString m_instIcon; - QString m_instGroup; - NetJobPtr m_netJobPtr; - - FtbPackDownloader *m_downloader; - - std::unique_ptr m_packZip; - QFuture m_extractFuture; - QFutureWatcher m_extractFutureWatcher; - - void downloadPack(); - void unzip(QString archivePath); - void install(); - - bool moveRecursively(QString source, QString dest); - - bool abortable = false; - -private slots: - void onDownloadSucceeded(QString archivePath); - void onDownloadFailed(QString reason); - void onDownloadProgress(qint64 current, qint64 total); - - void onUnzipFinished(); - void onUnzipCanceled(); - -}; diff --git a/api/logic/modplatform/PackHelpers.h b/api/logic/modplatform/PackHelpers.h deleted file mode 100644 index f761ed6b..00000000 --- a/api/logic/modplatform/PackHelpers.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include "qmetatype.h" - -//Header for structs etc... -struct FtbModpack { - QString name; - QString description; - QString author; - QStringList oldVersions; - QString currentVersion; - QString mcVersion; - QString mods; - QString image; - - //Technical data - QString dir; - QString file; //<- Url in the xml, but doesn't make much sense - - bool bugged = false; - bool broken = false; -}; -//We need it for the proxy model -Q_DECLARE_METATYPE(FtbModpack) - -typedef QList FtbModpackList; diff --git a/api/logic/modplatform/flame/FileResolvingTask.cpp b/api/logic/modplatform/flame/FileResolvingTask.cpp new file mode 100644 index 00000000..efc73621 --- /dev/null +++ b/api/logic/modplatform/flame/FileResolvingTask.cpp @@ -0,0 +1,117 @@ +#include "FileResolvingTask.h" +#include "Json.h" + +const char * metabase = "https://cursemeta.dries007.net"; + +Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess) + : m_toProcess(toProcess) +{ +} + +void Flame::FileResolvingTask::executeTask() +{ + setStatus(tr("Resolving mod IDs...")); + setProgress(0, m_toProcess.files.size()); + m_dljob.reset(new NetJob("Mod id resolver")); + results.resize(m_toProcess.files.size()); + int index = 0; + for(auto & file: m_toProcess.files) + { + auto projectIdStr = QString::number(file.projectId); + auto fileIdStr = QString::number(file.fileId); + QString metaurl = QString("%1/%2/%3.json").arg(metabase, projectIdStr, fileIdStr); + auto dl = Net::Download::makeByteArray(QUrl(metaurl), &results[index]); + m_dljob->addNetAction(dl); + index ++; + } + connect(m_dljob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::netJobFinished); + m_dljob->start(); +} + +void Flame::FileResolvingTask::netJobFinished() +{ + bool failed = false; + int index = 0; + for(auto & bytes: results) + { + try + { + auto doc = Json::requireDocument(bytes); + auto obj = Json::requireObject(doc); + auto & out = m_toProcess.files[index]; + // result code signifies true failure. + if(obj.contains("code")) + { + qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a negative result:"; + qCritical() << bytes; + failed = true; + continue; + } + out.fileName = Json::requireString(obj, "FileNameOnDisk"); + QString rawUrl = Json::requireString(obj, "DownloadURL"); + out.url = QUrl(rawUrl, QUrl::TolerantMode); + if(!out.url.isValid()) + { + throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); + } + // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience + // It is also optional + QJsonObject projObj = Json::ensureObject(obj, "_Project", {}); + if(!projObj.isEmpty()) + { + QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower(); + if(strType == "singlefile") + { + out.type = File::Type::SingleFile; + } + else if(strType == "ctoc") + { + out.type = File::Type::Ctoc; + } + else if(strType == "cmod2") + { + out.type = File::Type::Cmod2; + } + else if(strType == "mod") + { + out.type = File::Type::Mod; + } + else if(strType == "folder") + { + out.type = File::Type::Folder; + } + else if(strType == "modpack") + { + out.type = File::Type::Modpack; + } + else + { + qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of unknown file type:" << strType; + out.type = File::Type::Unknown; + failed = true; + continue; + } + out.targetFolder = Json::ensureString(projObj, "Path", "mods"); + } + out.resolved = true; + } + catch(JSONValidationError & e) + { + auto & out = m_toProcess.files[index]; + qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:"; + qCritical() << e.cause(); + qCritical() << "JSON:"; + qCritical() << bytes; + failed = true; + } + index++; + } + if(!failed) + { + emitSucceeded(); + } + else + { + emitFailed(tr("Some mod ID resolving tasks failed.")); + } +} diff --git a/api/logic/modplatform/flame/FileResolvingTask.h b/api/logic/modplatform/flame/FileResolvingTask.h new file mode 100644 index 00000000..00658452 --- /dev/null +++ b/api/logic/modplatform/flame/FileResolvingTask.h @@ -0,0 +1,32 @@ +#pragma once + +#include "tasks/Task.h" +#include "net/NetJob.h" +#include "PackManifest.h" + +#include "multimc_logic_export.h" + +namespace Flame +{ +class MULTIMC_LOGIC_EXPORT FileResolvingTask : public Task +{ + Q_OBJECT +public: + explicit FileResolvingTask(Flame::Manifest &toProcess); + const Flame::Manifest &getResults() const + { + return m_toProcess; + } + +protected: + virtual void executeTask() override; + +protected slots: + void netJobFinished(); + +private: /* data */ + Flame::Manifest m_toProcess; + QVector results; + NetJobPtr m_dljob; +}; +} diff --git a/api/logic/modplatform/flame/PackManifest.cpp b/api/logic/modplatform/flame/PackManifest.cpp new file mode 100644 index 00000000..6a9324fe --- /dev/null +++ b/api/logic/modplatform/flame/PackManifest.cpp @@ -0,0 +1,66 @@ +#include "PackManifest.h" +#include "Json.h" + +static void loadFileV1(Flame::File & f, QJsonObject & file) +{ + f.projectId = Json::requireInteger(file, "projectID"); + f.fileId = Json::requireInteger(file, "fileID"); + f.required = Json::ensureBoolean(file, QString("required"), true); +} + +static void loadModloaderV1(Flame::Modloader & m, QJsonObject & modLoader) +{ + m.id = Json::requireString(modLoader, "id"); + m.primary = Json::ensureBoolean(modLoader, QString("primary"), false); +} + +static void loadMinecraftV1(Flame::Minecraft & m, QJsonObject & minecraft) +{ + m.version = Json::requireString(minecraft, "version"); + // extra libraries... apparently only used for a custom Minecraft launcher in the 1.2.5 FTB retro pack + // intended use is likely hardcoded in the 'Flame' client, the manifest says nothing + m.libraries = Json::ensureString(minecraft, QString("libraries"), QString()); + auto arr = Json::ensureArray(minecraft, "modLoaders", QJsonArray()); + for (const auto & item : arr) + { + auto obj = Json::requireObject(item); + Flame::Modloader loader; + loadModloaderV1(loader, obj); + m.modLoaders.append(loader); + } +} + +static void loadManifestV1(Flame::Manifest & m, QJsonObject & manifest) +{ + auto mc = Json::requireObject(manifest, "minecraft"); + loadMinecraftV1(m.minecraft, mc); + m.name = Json::ensureString(manifest, QString("name"), "Unnamed"); + m.version = Json::ensureString(manifest, QString("version"), QString()); + m.author = Json::ensureString(manifest, QString("author"), "Anonymous Coward"); + auto arr = Json::ensureArray(manifest, "files", QJsonArray()); + for (const auto & item : arr) + { + auto obj = Json::requireObject(item); + Flame::File file; + loadFileV1(file, obj); + m.files.append(file); + } + m.overrides = Json::ensureString(manifest, "overrides", "overrides"); +} + +void Flame::loadManifest(Flame::Manifest & m, const QString &filepath) +{ + auto doc = Json::requireDocument(filepath); + auto obj = Json::requireObject(doc); + m.manifestType = Json::requireString(obj, "manifestType"); + if(m.manifestType != "minecraftModpack") + { + throw JSONValidationError("Not a modpack manifest!"); + } + m.manifestVersion = Json::requireInteger(obj, "manifestVersion"); + if(m.manifestVersion != 1) + { + throw JSONValidationError(QString("Unknown manifest version (%1)").arg(m.manifestVersion)); + } + loadManifestV1(m, obj); +} diff --git a/api/logic/modplatform/flame/PackManifest.h b/api/logic/modplatform/flame/PackManifest.h new file mode 100644 index 00000000..1a5254a8 --- /dev/null +++ b/api/logic/modplatform/flame/PackManifest.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include + +namespace Flame +{ +struct File +{ + int projectId = 0; + int fileId = 0; + // NOTE: the opposite to 'optional'. This is at the time of writing unused. + bool required = true; + + // our + bool resolved = false; + QString fileName; + QUrl url; + QString targetFolder = QLatin1Literal("mods"); + enum class Type + { + Unknown, + Folder, + Ctoc, + SingleFile, + Cmod2, + Modpack, + Mod + } type = Type::Mod; +}; + +struct Modloader +{ + QString id; + bool primary = false; +}; + +struct Minecraft +{ + QString version; + QString libraries; + QVector modLoaders; +}; + +struct Manifest +{ + QString manifestType; + int manifestVersion = 0; + Flame::Minecraft minecraft; + QString name; + QString version; + QString author; + QVector files; + QString overrides; +}; + +void loadManifest(Flame::Manifest & m, const QString &filepath); +} diff --git a/api/logic/modplatform/ftb/FtbPackDownloader.cpp b/api/logic/modplatform/ftb/FtbPackDownloader.cpp new file mode 100644 index 00000000..caadd4ae --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackDownloader.cpp @@ -0,0 +1,109 @@ +#include "FtbPackDownloader.h" +#include "PackHelpers.h" +#include "FtbPackFetchTask.h" +#include "Env.h" + +FtbPackDownloader::FtbPackDownloader() { + done = false; + fetching = false; +} + +FtbPackDownloader::~FtbPackDownloader(){ +} + +bool FtbPackDownloader::isValidPackSelected(){ + FtbModpack dummy; + dummy.name = "__INVALID__"; + + FtbModpack other = fetchedPacks.value(selected.name, dummy); + if(other.name == "__INVALID__") { + return false; + } + + return other.oldVersions.contains(selectedVersion) && !other.broken; +} + +QString FtbPackDownloader::getSuggestedInstanceName() { + return selected.name; +} + +FtbModpackList FtbPackDownloader::getModpacks() { + return static_cast(fetchedPacks.values()); +} + +void FtbPackDownloader::fetchModpacks(bool force = false){ + if(fetching || (!force && done)) { + qDebug() << "Skipping modpack refetch because done or already fetching [done =>" << done << "| fetching =>" << fetching << "]"; + return; + } + + fetching = true; + + fetchTask = new FtbPackFetchTask(); + connect(fetchTask, &FtbPackFetchTask::finished, this, &FtbPackDownloader::fetchSuccess); + connect(fetchTask, &FtbPackFetchTask::failed, this, &FtbPackDownloader::fetchFailed); + fetchTask->fetch(); +} + + +void FtbPackDownloader::fetchSuccess(FtbModpackList modpacks) { + for(int i = 0; i < modpacks.size(); i++) { + fetchedPacks.insert(modpacks.at(i).name, modpacks.at(i)); + } + + fetching = false; + done = true; + emit ready(); + fetchTask->deleteLater(); +} + +void FtbPackDownloader::fetchFailed(QString reason) { + qWarning() << "Failed to fetch FtbData" << reason; + fetching = false; + emit packFetchFailed(); + fetchTask->deleteLater(); +} + +void FtbPackDownloader::selectPack(FtbModpack modpack, QString version) { + selected = modpack; + selectedVersion = version; +} + +FtbModpack FtbPackDownloader::getSelectedPack() { + return selected; +} + +void FtbPackDownloader::downloadSelected(MetaEntryPtr cache) { + NetJob *job = new NetJob("Downlad FTB Pack"); + + cache->setStale(true); + QString url = QString("http://ftb.cursecdn.com/FTB2/modpacks/%1/%2/%3").arg(selected.dir, selectedVersion.replace(".", "_"), selected.file); + job->addNetAction(Net::Download::makeCached(url, cache)); + downloadPath = cache->getFullPath(); + + netJobContainer.reset(job); + + connect(job, &NetJob::succeeded, this, &FtbPackDownloader::_downloadSucceeded); + connect(job, &NetJob::failed, this, &FtbPackDownloader::_downloadFailed); + connect(job, &NetJob::progress, this, &FtbPackDownloader::_downloadProgress); + job->start(); +} + +void FtbPackDownloader::_downloadSucceeded() { + netJobContainer.reset(); + emit downloadSucceded(downloadPath); +} + +void FtbPackDownloader::_downloadProgress(qint64 current, qint64 total) { + emit downloadProgress(current, total); +} + +void FtbPackDownloader::_downloadFailed(QString reason) { + netJobContainer.reset(); + emit downloadFailed(reason); +} + +NetJobPtr FtbPackDownloader::getNetJob() +{ + return netJobContainer; +} diff --git a/api/logic/modplatform/ftb/FtbPackDownloader.h b/api/logic/modplatform/ftb/FtbPackDownloader.h new file mode 100644 index 00000000..c5cc9bd2 --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackDownloader.h @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include "FtbPackFetchTask.h" +#include "tasks/Task.h" +#include "net/NetJob.h" + +#include "PackHelpers.h" +#include "Env.h" + +#pragma once + +class FtbPackDownloader; +class MULTIMC_LOGIC_EXPORT FtbPackDownloader : public QObject { + + Q_OBJECT + +private: + QMap fetchedPacks; + bool fetching = false; + bool done = false; + + FtbModpack selected; + QString selectedVersion; + QString downloadPath; + + FtbPackFetchTask *fetchTask = 0; + NetJobPtr netJobContainer; + + void _downloadSucceeded(); + void _downloadFailed(QString reason); + void _downloadProgress(qint64 current, qint64 total); + +private slots: + void fetchSuccess(FtbModpackList modlist); + void fetchFailed(QString reason); + +public: + FtbPackDownloader(); + ~FtbPackDownloader(); + + bool isValidPackSelected(); + void selectPack(FtbModpack modpack, QString version); + + FtbModpack getSelectedPack(); + + void fetchModpacks(bool force); + void downloadSelected(MetaEntryPtr cache); + + QString getSuggestedInstanceName(); + + FtbModpackList getModpacks(); + NetJobPtr getNetJob(); + +signals: + void ready(); + void packFetchFailed(); + + void downloadSucceded(QString archivePath); + void downloadFailed(QString reason); + void downloadProgress(qint64 current, qint64 total); + +}; diff --git a/api/logic/modplatform/ftb/FtbPackFetchTask.cpp b/api/logic/modplatform/ftb/FtbPackFetchTask.cpp new file mode 100644 index 00000000..9e151186 --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackFetchTask.cpp @@ -0,0 +1,96 @@ +#include "FtbPackFetchTask.h" +#include + +FtbPackFetchTask::FtbPackFetchTask() { + +} + +FtbPackFetchTask::~FtbPackFetchTask() { + +} + +void FtbPackFetchTask::fetch() { + NetJob *netJob = new NetJob("FtbModpackFetch"); + + QUrl url = QUrl("https://ftb.cursecdn.com/FTB2/static/modpacks.xml"); + qDebug() << "Downloading version info from " << url.toString(); + + netJob->addNetAction(downloadPtr = Net::Download::makeByteArray(url, &modpacksXmlFileData)); + + QObject::connect(netJob, &NetJob::succeeded, this, &FtbPackFetchTask::fileDownloadFinished); + QObject::connect(netJob, &NetJob::failed, this, &FtbPackFetchTask::fileDownloadFailed); + + jobPtr.reset(netJob); + netJob->start(); +} + +void FtbPackFetchTask::fileDownloadFinished(){ + + jobPtr.reset(); + + QDomDocument doc; + + QString errorMsg = "Unknown error."; + int errorLine = -1; + int errorCol = -1; + + if(!doc.setContent(modpacksXmlFileData, false, &errorMsg, &errorLine, &errorCol)){ + auto fullErrMsg = QString("Failed to fetch modpack data: %s %d:%d!").arg(errorMsg, errorLine, errorCol); + qWarning() << fullErrMsg; + emit failed(fullErrMsg); + modpacksXmlFileData.clear(); + return; + } + + modpacksXmlFileData.clear(); + + FtbModpackList modpackList; + + QDomNodeList nodes = doc.elementsByTagName("modpack"); + for(int i = 0; i < nodes.length(); i++) { + QDomElement element = nodes.at(i).toElement(); + + FtbModpack modpack; + modpack.name = element.attribute("name"); + modpack.currentVersion = element.attribute("version"); + modpack.mcVersion = element.attribute("mcVersion"); + modpack.description = element.attribute("description"); + modpack.mods = element.attribute("mods"); + modpack.image = element.attribute("image"); + modpack.oldVersions = element.attribute("oldVersions").split(";"); + + //remove empty if the xml is bugged + for(QString curr : modpack.oldVersions) { + if(curr.isNull() || curr.isEmpty()) { + modpack.oldVersions.removeAll(curr); + modpack.bugged = true; + qWarning() << "Removed some empty versions from" << modpack.name; + } + } + + if(modpack.oldVersions.size() < 1) { + if(!modpack.currentVersion.isNull() && !modpack.currentVersion.isEmpty()) { + modpack.oldVersions.append(modpack.currentVersion); + qWarning() << "Added current version to oldVersions because oldVersions was empty! (" + modpack.name + ")"; + } else { + modpack.broken = true; + qWarning() << "Broken pack:" << modpack.name << " => No valid version!"; + } + } + + modpack.author = element.attribute("author"); + + modpack.dir = element.attribute("dir"); + modpack.file = element.attribute("url"); + + modpackList.append(modpack); + } + + + emit finished(modpackList); +} + +void FtbPackFetchTask::fileDownloadFailed(QString reason){ + qWarning() << "Fetching FtbPacks failed: " << reason; + emit failed(reason); +} diff --git a/api/logic/modplatform/ftb/FtbPackFetchTask.h b/api/logic/modplatform/ftb/FtbPackFetchTask.h new file mode 100644 index 00000000..3cfac4ed --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackFetchTask.h @@ -0,0 +1,33 @@ +#pragma once + +#include "net/NetJob.h" +#include +#include +#include +#include "PackHelpers.h" + +class MULTIMC_LOGIC_EXPORT FtbPackFetchTask : public QObject { + + Q_OBJECT + +public: + FtbPackFetchTask(); + ~FtbPackFetchTask(); + + void fetch(); + +private: + NetJobPtr jobPtr; + Net::Download::Ptr downloadPtr; + + QByteArray modpacksXmlFileData; + +protected slots: + void fileDownloadFinished(); + void fileDownloadFailed(QString reason); + +signals: + void finished(FtbModpackList list); + void failed(QString reason); + +}; diff --git a/api/logic/modplatform/ftb/FtbPackInstallTask.cpp b/api/logic/modplatform/ftb/FtbPackInstallTask.cpp new file mode 100644 index 00000000..530f72ca --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackInstallTask.cpp @@ -0,0 +1,173 @@ +#include "FtbPackInstallTask.h" +#include "Env.h" +#include "MMCZip.h" +#include "QtConcurrent" +#include "BaseInstance.h" +#include "FileSystem.h" +#include "settings/INISettingsObject.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/ComponentList.h" +#include "minecraft/GradleSpecifier.h" + +FtbPackInstallTask::FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, + const QString &stagingPath, const QString &instName, const QString &instIcon, const QString &instGroup) : + m_globalSettings(settings), m_stagingPath(stagingPath), m_instName(instName), m_instIcon(instIcon), m_instGroup(instGroup) +{ + m_downloader = downloader; +} + +void FtbPackInstallTask::executeTask() { + downloadPack(); +} + +void FtbPackInstallTask::downloadPack(){ + FtbModpack toInstall = m_downloader->getSelectedPack(); + setStatus(tr("Downloading zip for %1").arg(toInstall.name)); + + auto entry = ENV.metacache()->resolveEntry("general", "FTBPacks/" + toInstall.name); + m_downloader->downloadSelected(entry); + + connect(m_downloader, &FtbPackDownloader::downloadSucceded, this, &FtbPackInstallTask::onDownloadSucceeded); + connect(m_downloader, &FtbPackDownloader::downloadProgress, this, &FtbPackInstallTask::onDownloadProgress); + connect(m_downloader, &FtbPackDownloader::downloadFailed, this,&FtbPackInstallTask::onDownloadFailed); + progress(1, 4); +} + +void FtbPackInstallTask::onDownloadSucceeded(QString archivePath){ + abortable = false; + unzip(archivePath); +} + +void FtbPackInstallTask::onDownloadFailed(QString reason) { + emitFailed(reason); +} + +void FtbPackInstallTask::onDownloadProgress(qint64 current, qint64 total){ + abortable = true; + progress(current, total * 4); + setStatus(tr("Downloading zip for %1 (%2\%)").arg(m_downloader->getSelectedPack().name).arg(current / 10)); +} + +void FtbPackInstallTask::unzip(QString archivePath) { + progress(2, 4); + setStatus(tr("Extracting modpack")); + QDir extractDir(m_stagingPath); + + m_packZip.reset(new QuaZip(archivePath)); + if(!m_packZip->open(QuaZip::mdUnzip)) { + emitFailed(tr("Failed to open modpack file %1!").arg(archivePath)); + return; + } + + m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip"); + connect(&m_extractFutureWatcher, &QFutureWatcher::finished, this, &FtbPackInstallTask::onUnzipFinished); + connect(&m_extractFutureWatcher, &QFutureWatcher::canceled, this, &FtbPackInstallTask::onUnzipCanceled); + m_extractFutureWatcher.setFuture(m_extractFuture); +} + +void FtbPackInstallTask::onUnzipFinished() { + install(); +} + +void FtbPackInstallTask::onUnzipCanceled() { + emitAborted(); +} + +void FtbPackInstallTask::install() { + progress(3, 4); + FtbModpack toInstall = m_downloader->getSelectedPack(); + setStatus(tr("Installing modpack")); + QDir unzipMcDir(m_stagingPath + "/unzip/minecraft"); + if(unzipMcDir.exists()) { + //ok, found minecraft dir, move contents to instance dir + if(!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft")) { + emitFailed(tr("Failed to move unzipped minecraft!")); + return; + } + } + + QString instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg"); + auto instanceSettings = std::make_shared(instanceConfigPath); + instanceSettings->registerSetting("InstanceType", "Legacy"); + instanceSettings->set("InstanceType", "OneSix"); + + MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); + auto components = instance.getComponentList(); + components->buildingFromScratch(); + components->setComponentVersion("net.minecraft", toInstall.mcVersion, true); + + bool fallback = true; + + //handle different versions + QFile packJson(m_stagingPath + "/.minecraft/pack.json"); + QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods"); + if(packJson.exists()) { + packJson.open(QIODevice::ReadOnly | QIODevice::Text); + QJsonDocument doc = QJsonDocument::fromJson(packJson.readAll()); + packJson.close(); + + //we only care about the libs + QJsonArray libs = doc.object().value("libraries").toArray(); + + foreach (const QJsonValue &value, libs) { + QString nameValue = value.toObject().value("name").toString(); + if(!nameValue.startsWith("net.minecraftforge")) { + continue; + } + + GradleSpecifier forgeVersion(nameValue); + + components->setComponentVersion("net.minecraftforge", forgeVersion.version().replace(toInstall.mcVersion, "").replace("-", "")); + packJson.remove(); + fallback = false; + break; + } + + } + + if(jarmodDir.exists()) { + qDebug() << "Found jarmods, installing..."; + + QStringList jarmods; + for (auto info: jarmodDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files)) + { + qDebug() << "Jarmod:" << info.fileName(); + jarmods.push_back(info.absoluteFilePath()); + } + + components->installJarMods(jarmods); + fallback = false; + } + + //just nuke unzip directory, it s not needed anymore + FS::deletePath(m_stagingPath + "/unzip"); + + if(fallback) { + //TODO: Some fallback mechanism... or just keep failing! + emitFailed(tr("No installation method found!")); + return; + } + + components->saveNow(); + + progress(4, 4); + + instance.init(); + instance.setName(m_instName); + if(m_instIcon == "default") { + m_instIcon = "ftb_logo"; + } + instance.setIconKey(m_instIcon); + instance.setGroupInitial(m_instGroup); + instanceSettings->resumeSave(); + + emitSucceeded(); +} + +bool FtbPackInstallTask::abort() +{ + if(abortable) { + return m_downloader->getNetJob()->abort(); + } + return false; +} diff --git a/api/logic/modplatform/ftb/FtbPackInstallTask.h b/api/logic/modplatform/ftb/FtbPackInstallTask.h new file mode 100644 index 00000000..7d6e5276 --- /dev/null +++ b/api/logic/modplatform/ftb/FtbPackInstallTask.h @@ -0,0 +1,55 @@ +#pragma once +#include "tasks/Task.h" +#include "modplatform/ftb/FtbPackDownloader.h" +#include "BaseInstanceProvider.h" +#include "net/NetJob.h" +#include "quazip.h" +#include "quazipdir.h" +#include "meta/Index.h" +#include "meta/Version.h" +#include "meta/VersionList.h" + +class MULTIMC_LOGIC_EXPORT FtbPackInstallTask : public Task { + + Q_OBJECT + +public: + explicit FtbPackInstallTask(FtbPackDownloader *downloader, SettingsObjectPtr settings, const QString &stagingPath, const QString &instName, + const QString &instIcon, const QString &instGroup); + bool abort() override; + +protected: + //! Entry point for tasks. + virtual void executeTask() override; + +private: /* data */ + SettingsObjectPtr m_globalSettings; + QString m_stagingPath; + QString m_instName; + QString m_instIcon; + QString m_instGroup; + NetJobPtr m_netJobPtr; + + FtbPackDownloader *m_downloader; + + std::unique_ptr m_packZip; + QFuture m_extractFuture; + QFutureWatcher m_extractFutureWatcher; + + void downloadPack(); + void unzip(QString archivePath); + void install(); + + bool moveRecursively(QString source, QString dest); + + bool abortable = false; + +private slots: + void onDownloadSucceeded(QString archivePath); + void onDownloadFailed(QString reason); + void onDownloadProgress(qint64 current, qint64 total); + + void onUnzipFinished(); + void onUnzipCanceled(); + +}; diff --git a/api/logic/modplatform/ftb/PackHelpers.h b/api/logic/modplatform/ftb/PackHelpers.h new file mode 100644 index 00000000..f761ed6b --- /dev/null +++ b/api/logic/modplatform/ftb/PackHelpers.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include "qmetatype.h" + +//Header for structs etc... +struct FtbModpack { + QString name; + QString description; + QString author; + QStringList oldVersions; + QString currentVersion; + QString mcVersion; + QString mods; + QString image; + + //Technical data + QString dir; + QString file; //<- Url in the xml, but doesn't make much sense + + bool bugged = false; + bool broken = false; +}; +//We need it for the proxy model +Q_DECLARE_METATYPE(FtbModpack) + +typedef QList FtbModpackList; diff --git a/application/FtbListModel.h b/application/FtbListModel.h index e41e9b62..41fc3ccd 100644 --- a/application/FtbListModel.h +++ b/application/FtbListModel.h @@ -2,7 +2,7 @@ #include #include -#include +#include class FtbFilterModel : public QSortFilterProxyModel { diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index e690e1b7..542d1da6 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -1368,7 +1368,8 @@ void MainWindow::addInstance(QString url) const QUrl modpackUrl = newInstDlg.modpackUrl(); - if(newInstDlg.isFtbModpackRequested()) { + if(newInstDlg.isFtbModpackRequested()) + { instanceFromFtbPack(newInstDlg.getFtbPackDownloader(), newInstDlg.instName(), newInstDlg.instGroup(), newInstDlg.iconKey()); } else if (modpackUrl.isValid()) diff --git a/application/MainWindow.h b/application/MainWindow.h index 25dc36ed..e9897606 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -25,7 +25,7 @@ #include "minecraft/auth/MojangAccount.h" #include "net/NetJob.h" #include "updater/GoUpdate.h" -#include +#include class LaunchController; class NewsChecker; diff --git a/application/dialogs/ChooseFtbPackDialog.h b/application/dialogs/ChooseFtbPackDialog.h index 0b021138..f9f3dd08 100644 --- a/application/dialogs/ChooseFtbPackDialog.h +++ b/application/dialogs/ChooseFtbPackDialog.h @@ -2,9 +2,8 @@ #include #include -#include +#include #include "ui_ChooseFtbPackDialog.h" -#include #include "FtbListModel.h" namespace Ui { diff --git a/application/dialogs/NewInstanceDialog.h b/application/dialogs/NewInstanceDialog.h index 9b0f7f53..f1fe26f4 100644 --- a/application/dialogs/NewInstanceDialog.h +++ b/application/dialogs/NewInstanceDialog.h @@ -18,8 +18,8 @@ #include #include "BaseVersion.h" -#include "modplatform/FtbPackDownloader.h" -#include "modplatform/PackHelpers.h" +#include "modplatform/ftb/FtbPackDownloader.h" +#include "modplatform/ftb/PackHelpers.h" namespace Ui { -- cgit v1.2.3