aboutsummaryrefslogtreecommitdiff
path: root/launcher/modplatform/modpacksch
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-07-25 19:11:59 +0200
committerPetr Mrázek <peterix@gmail.com>2021-07-25 19:50:44 +0200
commit20b9f2b42a3b58b6081af271774fbcc34025dccb (patch)
tree064fa59facb3357139b47bd4e60bfc8edb35ca11 /launcher/modplatform/modpacksch
parentdd133680858351e3e07690e286882327a4f42ba5 (diff)
downloadPrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.tar.gz
PrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.tar.bz2
PrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.zip
NOISSUE Flatten gui and logic libraries into MultiMC
Diffstat (limited to 'launcher/modplatform/modpacksch')
-rw-r--r--launcher/modplatform/modpacksch/FTBPackInstallTask.cpp209
-rw-r--r--launcher/modplatform/modpacksch/FTBPackInstallTask.h46
-rw-r--r--launcher/modplatform/modpacksch/FTBPackManifest.cpp156
-rw-r--r--launcher/modplatform/modpacksch/FTBPackManifest.h125
4 files changed, 536 insertions, 0 deletions
diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
new file mode 100644
index 00000000..f22373bc
--- /dev/null
+++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
@@ -0,0 +1,209 @@
+#include "FTBPackInstallTask.h"
+
+#include "BuildConfig.h"
+#include "Env.h"
+#include "FileSystem.h"
+#include "Json.h"
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/PackProfile.h"
+#include "net/ChecksumValidator.h"
+#include "settings/INISettingsObject.h"
+
+namespace ModpacksCH {
+
+PackInstallTask::PackInstallTask(Modpack pack, QString version)
+{
+ m_pack = pack;
+ m_version_name = version;
+}
+
+bool PackInstallTask::abort()
+{
+ if(abortable)
+ {
+ return jobPtr->abort();
+ }
+ return false;
+}
+
+void PackInstallTask::executeTask()
+{
+ // Find pack version
+ bool found = false;
+ VersionInfo version;
+
+ for(auto vInfo : m_pack.versions) {
+ if (vInfo.name == m_version_name) {
+ found = true;
+ version = vInfo;
+ break;
+ }
+ }
+
+ if(!found) {
+ emitFailed(tr("Failed to find pack version %1").arg(m_version_name));
+ return;
+ }
+
+ auto *netJob = new NetJob("ModpacksCH::VersionFetch");
+ auto searchUrl = QString(BuildConfig.MODPACKSCH_API_BASE_URL + "public/modpack/%1/%2")
+ .arg(m_pack.id).arg(version.id);
+ netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
+ jobPtr = netJob;
+ jobPtr->start();
+
+ QObject::connect(netJob, &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
+ QObject::connect(netJob, &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
+}
+
+void PackInstallTask::onDownloadSucceeded()
+{
+ jobPtr.reset();
+
+ QJsonParseError parse_error;
+ QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
+ if(parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from FTB at " << parse_error.offset << " reason: " << parse_error.errorString();
+ qWarning() << response;
+ return;
+ }
+
+ auto obj = doc.object();
+
+ ModpacksCH::Version version;
+ try
+ {
+ ModpacksCH::loadVersion(version, obj);
+ }
+ catch (const JSONValidationError &e)
+ {
+ emitFailed(tr("Could not understand pack manifest:\n") + e.cause());
+ return;
+ }
+ m_version = version;
+
+ downloadPack();
+}
+
+void PackInstallTask::onDownloadFailed(QString reason)
+{
+ jobPtr.reset();
+ emitFailed(reason);
+}
+
+void PackInstallTask::downloadPack()
+{
+ setStatus(tr("Downloading mods..."));
+
+ jobPtr.reset(new NetJob(tr("Mod download")));
+ for(auto file : m_version.files) {
+ if(file.serverOnly) continue;
+
+ QFileInfo fileName(file.name);
+ auto cacheName = fileName.completeBaseName() + "-" + file.sha1 + "." + fileName.suffix();
+
+ auto entry = ENV.metacache()->resolveEntry("ModpacksCHPacks", cacheName);
+ entry->setStale(true);
+
+ auto relpath = FS::PathCombine("minecraft", file.path, file.name);
+ auto path = FS::PathCombine(m_stagingPath, relpath);
+
+ qDebug() << "Will download" << file.url << "to" << path;
+ filesToCopy[entry->getFullPath()] = path;
+
+ auto dl = Net::Download::makeCached(file.url, entry);
+ if (!file.sha1.isEmpty()) {
+ auto rawSha1 = QByteArray::fromHex(file.sha1.toLatin1());
+ dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
+ }
+ jobPtr->addNetAction(dl);
+ }
+
+ connect(jobPtr.get(), &NetJob::succeeded, this, [&]()
+ {
+ abortable = false;
+ jobPtr.reset();
+ install();
+ });
+ connect(jobPtr.get(), &NetJob::failed, [&](QString reason)
+ {
+ abortable = false;
+ jobPtr.reset();
+ emitFailed(reason);
+ });
+ connect(jobPtr.get(), &NetJob::progress, [&](qint64 current, qint64 total)
+ {
+ abortable = true;
+ setProgress(current, total);
+ });
+
+ jobPtr->start();
+}
+
+void PackInstallTask::install()
+{
+ setStatus(tr("Copying modpack files"));
+
+ for (auto iter = filesToCopy.begin(); iter != filesToCopy.end(); iter++) {
+ auto &from = iter.key();
+ auto &to = iter.value();
+ FS::copy fileCopyOperation(from, to);
+ if(!fileCopyOperation()) {
+ qWarning() << "Failed to copy" << from << "to" << to;
+ emitFailed(tr("Failed to copy files"));
+ return;
+ }
+ }
+
+ setStatus(tr("Installing modpack"));
+
+ auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
+ auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
+ instanceSettings->suspendSave();
+ instanceSettings->registerSetting("InstanceType", "Legacy");
+ instanceSettings->set("InstanceType", "OneSix");
+
+ MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
+ auto components = instance.getPackProfile();
+ components->buildingFromScratch();
+
+ for(auto target : m_version.targets) {
+ if(target.type == "game" && target.name == "minecraft") {
+ components->setComponentVersion("net.minecraft", target.version, true);
+ break;
+ }
+ }
+
+ for(auto target : m_version.targets) {
+ if(target.type != "modloader") continue;
+
+ if(target.name == "forge") {
+ components->setComponentVersion("net.minecraftforge", target.version, true);
+ }
+ else if(target.name == "fabric") {
+ components->setComponentVersion("net.fabricmc.fabric-loader", target.version, true);
+ }
+ }
+
+ // install any jar mods
+ QDir jarModsDir(FS::PathCombine(m_stagingPath, "minecraft", "jarmods"));
+ if (jarModsDir.exists()) {
+ QStringList jarMods;
+
+ for (const auto& info : jarModsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files)) {
+ jarMods.push_back(info.absoluteFilePath());
+ }
+
+ components->installJarMods(jarMods);
+ }
+
+ components->saveNow();
+
+ instance.setName(m_instName);
+ instance.setIconKey(m_instIcon);
+ instanceSettings->resumeSave();
+
+ emitSucceeded();
+}
+
+}
diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.h b/launcher/modplatform/modpacksch/FTBPackInstallTask.h
new file mode 100644
index 00000000..fdd84c4e
--- /dev/null
+++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "FTBPackManifest.h"
+
+#include "InstanceTask.h"
+#include "net/NetJob.h"
+
+namespace ModpacksCH {
+
+class PackInstallTask : public InstanceTask
+{
+ Q_OBJECT
+
+public:
+ explicit PackInstallTask(Modpack pack, QString version);
+ virtual ~PackInstallTask(){}
+
+ bool canAbort() const override { return true; }
+ bool abort() override;
+
+protected:
+ virtual void executeTask() override;
+
+private slots:
+ void onDownloadSucceeded();
+ void onDownloadFailed(QString reason);
+
+private:
+ void downloadPack();
+ void install();
+
+private:
+ bool abortable = false;
+
+ NetJobPtr jobPtr;
+ QByteArray response;
+
+ Modpack m_pack;
+ QString m_version_name;
+ Version m_version;
+
+ QMap<QString, QString> filesToCopy;
+
+};
+
+}
diff --git a/launcher/modplatform/modpacksch/FTBPackManifest.cpp b/launcher/modplatform/modpacksch/FTBPackManifest.cpp
new file mode 100644
index 00000000..fd99d332
--- /dev/null
+++ b/launcher/modplatform/modpacksch/FTBPackManifest.cpp
@@ -0,0 +1,156 @@
+#include "FTBPackManifest.h"
+
+#include "Json.h"
+
+static void loadSpecs(ModpacksCH::Specs & s, QJsonObject & obj)
+{
+ s.id = Json::requireInteger(obj, "id");
+ s.minimum = Json::requireInteger(obj, "minimum");
+ s.recommended = Json::requireInteger(obj, "recommended");
+}
+
+static void loadTag(ModpacksCH::Tag & t, QJsonObject & obj)
+{
+ t.id = Json::requireInteger(obj, "id");
+ t.name = Json::requireString(obj, "name");
+}
+
+static void loadArt(ModpacksCH::Art & a, QJsonObject & obj)
+{
+ a.id = Json::requireInteger(obj, "id");
+ a.url = Json::requireString(obj, "url");
+ a.type = Json::requireString(obj, "type");
+ a.width = Json::requireInteger(obj, "width");
+ a.height = Json::requireInteger(obj, "height");
+ a.compressed = Json::requireBoolean(obj, "compressed");
+ a.sha1 = Json::requireString(obj, "sha1");
+ a.size = Json::requireInteger(obj, "size");
+ a.updated = Json::requireInteger(obj, "updated");
+}
+
+static void loadAuthor(ModpacksCH::Author & a, QJsonObject & obj)
+{
+ a.id = Json::requireInteger(obj, "id");
+ a.name = Json::requireString(obj, "name");
+ a.type = Json::requireString(obj, "type");
+ a.website = Json::requireString(obj, "website");
+ a.updated = Json::requireInteger(obj, "updated");
+}
+
+static void loadVersionInfo(ModpacksCH::VersionInfo & v, QJsonObject & obj)
+{
+ v.id = Json::requireInteger(obj, "id");
+ v.name = Json::requireString(obj, "name");
+ v.type = Json::requireString(obj, "type");
+ v.updated = Json::requireInteger(obj, "updated");
+ auto specs = Json::requireObject(obj, "specs");
+ loadSpecs(v.specs, specs);
+}
+
+void ModpacksCH::loadModpack(ModpacksCH::Modpack & m, QJsonObject & obj)
+{
+ m.id = Json::requireInteger(obj, "id");
+ m.name = Json::requireString(obj, "name");
+ m.synopsis = Json::requireString(obj, "synopsis");
+ m.description = Json::requireString(obj, "description");
+ m.type = Json::requireString(obj, "type");
+ m.featured = Json::requireBoolean(obj, "featured");
+ m.installs = Json::requireInteger(obj, "installs");
+ m.plays = Json::requireInteger(obj, "plays");
+ m.updated = Json::requireInteger(obj, "updated");
+ m.refreshed = Json::requireInteger(obj, "refreshed");
+ auto artArr = Json::requireArray(obj, "art");
+ for (QJsonValueRef artRaw : artArr)
+ {
+ auto artObj = Json::requireObject(artRaw);
+ ModpacksCH::Art art;
+ loadArt(art, artObj);
+ m.art.append(art);
+ }
+ auto authorArr = Json::requireArray(obj, "authors");
+ for (QJsonValueRef authorRaw : authorArr)
+ {
+ auto authorObj = Json::requireObject(authorRaw);
+ ModpacksCH::Author author;
+ loadAuthor(author, authorObj);
+ m.authors.append(author);
+ }
+ auto versionArr = Json::requireArray(obj, "versions");
+ for (QJsonValueRef versionRaw : versionArr)
+ {
+ auto versionObj = Json::requireObject(versionRaw);
+ ModpacksCH::VersionInfo version;
+ loadVersionInfo(version, versionObj);
+ m.versions.append(version);
+ }
+ auto tagArr = Json::requireArray(obj, "tags");
+ for (QJsonValueRef tagRaw : tagArr)
+ {
+ auto tagObj = Json::requireObject(tagRaw);
+ ModpacksCH::Tag tag;
+ loadTag(tag, tagObj);
+ m.tags.append(tag);
+ }
+ m.updated = Json::requireInteger(obj, "updated");
+}
+
+static void loadVersionTarget(ModpacksCH::VersionTarget & a, QJsonObject & obj)
+{
+ a.id = Json::requireInteger(obj, "id");
+ a.name = Json::requireString(obj, "name");
+ a.type = Json::requireString(obj, "type");
+ a.version = Json::requireString(obj, "version");
+ a.updated = Json::requireInteger(obj, "updated");
+}
+
+static void loadVersionFile(ModpacksCH::VersionFile & a, QJsonObject & obj)
+{
+ a.id = Json::requireInteger(obj, "id");
+ a.type = Json::requireString(obj, "type");
+ a.path = Json::requireString(obj, "path");
+ a.name = Json::requireString(obj, "name");
+ a.version = Json::requireString(obj, "version");
+ a.url = Json::requireString(obj, "url");
+ a.sha1 = Json::requireString(obj, "sha1");
+ a.size = Json::requireInteger(obj, "size");
+ a.clientOnly = Json::requireBoolean(obj, "clientonly");
+ a.serverOnly = Json::requireBoolean(obj, "serveronly");
+ a.optional = Json::requireBoolean(obj, "optional");
+ a.updated = Json::requireInteger(obj, "updated");
+}
+
+void ModpacksCH::loadVersion(ModpacksCH::Version & m, QJsonObject & obj)
+{
+ m.id = Json::requireInteger(obj, "id");
+ m.parent = Json::requireInteger(obj, "parent");
+ m.name = Json::requireString(obj, "name");
+ m.type = Json::requireString(obj, "type");
+ m.installs = Json::requireInteger(obj, "installs");
+ m.plays = Json::requireInteger(obj, "plays");
+ m.updated = Json::requireInteger(obj, "updated");
+ m.refreshed = Json::requireInteger(obj, "refreshed");
+ auto specs = Json::requireObject(obj, "specs");
+ loadSpecs(m.specs, specs);
+ auto targetArr = Json::requireArray(obj, "targets");
+ for (QJsonValueRef targetRaw : targetArr)
+ {
+ auto versionObj = Json::requireObject(targetRaw);
+ ModpacksCH::VersionTarget target;
+ loadVersionTarget(target, versionObj);
+ m.targets.append(target);
+ }
+ auto fileArr = Json::requireArray(obj, "files");
+ for (QJsonValueRef fileRaw : fileArr)
+ {
+ auto fileObj = Json::requireObject(fileRaw);
+ ModpacksCH::VersionFile file;
+ loadVersionFile(file, fileObj);
+ m.files.append(file);
+ }
+}
+
+//static void loadVersionChangelog(ModpacksCH::VersionChangelog & m, QJsonObject & obj)
+//{
+// m.content = Json::requireString(obj, "content");
+// m.updated = Json::requireInteger(obj, "updated");
+//}
diff --git a/launcher/modplatform/modpacksch/FTBPackManifest.h b/launcher/modplatform/modpacksch/FTBPackManifest.h
new file mode 100644
index 00000000..7818b36d
--- /dev/null
+++ b/launcher/modplatform/modpacksch/FTBPackManifest.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <QString>
+#include <QVector>
+#include <QUrl>
+#include <QJsonObject>
+#include <QMetaType>
+
+namespace ModpacksCH
+{
+
+struct Specs
+{
+ int id;
+ int minimum;
+ int recommended;
+};
+
+struct Tag
+{
+ int id;
+ QString name;
+};
+
+struct Art
+{
+ int id;
+ QString url;
+ QString type;
+ int width;
+ int height;
+ bool compressed;
+ QString sha1;
+ int size;
+ int64_t updated;
+};
+
+struct Author
+{
+ int id;
+ QString name;
+ QString type;
+ QString website;
+ int64_t updated;
+};
+
+struct VersionInfo
+{
+ int id;
+ QString name;
+ QString type;
+ int64_t updated;
+ Specs specs;
+};
+
+struct Modpack
+{
+ int id;
+ QString name;
+ QString synopsis;
+ QString description;
+ QString type;
+ bool featured;
+ int installs;
+ int plays;
+ int64_t updated;
+ int64_t refreshed;
+ QVector<Art> art;
+ QVector<Author> authors;
+ QVector<VersionInfo> versions;
+ QVector<Tag> tags;
+};
+
+struct VersionTarget
+{
+ int id;
+ QString type;
+ QString name;
+ QString version;
+ int64_t updated;
+};
+
+struct VersionFile
+{
+ int id;
+ QString type;
+ QString path;
+ QString name;
+ QString version;
+ QString url;
+ QString sha1;
+ int size;
+ bool clientOnly;
+ bool serverOnly;
+ bool optional;
+ int64_t updated;
+};
+
+struct Version
+{
+ int id;
+ int parent;
+ QString name;
+ QString type;
+ int installs;
+ int plays;
+ int64_t updated;
+ int64_t refreshed;
+ Specs specs;
+ QVector<VersionTarget> targets;
+ QVector<VersionFile> files;
+};
+
+struct VersionChangelog
+{
+ QString content;
+ int64_t updated;
+};
+
+void loadModpack(Modpack & m, QJsonObject & obj);
+
+void loadVersion(Version & m, QJsonObject & obj);
+}
+
+Q_DECLARE_METATYPE(ModpacksCH::Modpack)