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/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 ++++ 7 files changed, 556 insertions(+) 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 (limited to 'api/logic/modplatform/ftb') 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; -- cgit v1.2.3