aboutsummaryrefslogtreecommitdiff
path: root/launcher/modplatform
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/modplatform')
-rw-r--r--launcher/modplatform/EnsureMetadataTask.cpp25
-rw-r--r--launcher/modplatform/ModIndex.h61
-rw-r--r--launcher/modplatform/ResourceAPI.h22
-rw-r--r--launcher/modplatform/atlauncher/ATLPackInstallTask.cpp19
-rw-r--r--launcher/modplatform/atlauncher/ATLPackInstallTask.h49
-rw-r--r--launcher/modplatform/flame/FileResolvingTask.cpp25
-rw-r--r--launcher/modplatform/flame/FlameAPI.cpp20
-rw-r--r--launcher/modplatform/flame/FlameAPI.h54
-rw-r--r--launcher/modplatform/flame/FlameCheckUpdate.cpp26
-rw-r--r--launcher/modplatform/flame/FlameInstanceCreationTask.cpp5
-rw-r--r--launcher/modplatform/flame/FlameModIndex.cpp81
-rw-r--r--launcher/modplatform/flame/FlameModIndex.h6
-rw-r--r--launcher/modplatform/flame/FlamePackIndex.h10
-rw-r--r--launcher/modplatform/helpers/HashUtils.cpp16
-rw-r--r--launcher/modplatform/helpers/HashUtils.h5
-rw-r--r--launcher/modplatform/helpers/NetworkResourceAPI.cpp58
-rw-r--r--launcher/modplatform/helpers/NetworkResourceAPI.h5
-rw-r--r--launcher/modplatform/legacy_ftb/PackFetchTask.cpp68
-rw-r--r--launcher/modplatform/legacy_ftb/PackFetchTask.h26
-rw-r--r--launcher/modplatform/modrinth/ModrinthAPI.cpp22
-rw-r--r--launcher/modplatform/modrinth/ModrinthAPI.h41
-rw-r--r--launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp33
-rw-r--r--launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp2
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackExportTask.cpp319
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackExportTask.h77
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.cpp43
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.h3
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.cpp33
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.h73
29 files changed, 898 insertions, 329 deletions
diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp
index 34d969f0..93b5ce76 100644
--- a/launcher/modplatform/EnsureMetadataTask.cpp
+++ b/launcher/modplatform/EnsureMetadataTask.cpp
@@ -10,6 +10,7 @@
#include "modplatform/flame/FlameAPI.h"
#include "modplatform/flame/FlameModIndex.h"
+#include "modplatform/helpers/HashUtils.h"
#include "modplatform/modrinth/ModrinthAPI.h"
#include "modplatform/modrinth/ModrinthPackIndex.h"
@@ -24,8 +25,8 @@ EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::Resource
auto hash_task = createNewHash(mod);
if (!hash_task)
return;
- connect(hash_task.get(), &Task::succeeded, [this, hash_task, mod] { m_mods.insert(hash_task->getResult(), mod); });
- connect(hash_task.get(), &Task::failed, [this, hash_task, mod] { emitFail(mod, "", RemoveFromList::No); });
+ connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
+ connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
hash_task->start();
}
@@ -37,8 +38,8 @@ EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform:
auto hash_task = createNewHash(mod);
if (!hash_task)
continue;
- connect(hash_task.get(), &Task::succeeded, [this, hash_task, mod] { m_mods.insert(hash_task->getResult(), mod); });
- connect(hash_task.get(), &Task::failed, [this, hash_task, mod] { emitFail(mod, "", RemoveFromList::No); });
+ connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
+ connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
m_hashing_task->addTask(hash_task);
}
}
@@ -212,12 +213,12 @@ Task::Ptr EnsureMetadataTask::modrinthVersionsTask()
{
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
- auto* response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response);
// Prevents unfortunate timings when aborting the task
if (!ver_task)
- return Task::Ptr{nullptr};
+ return Task::Ptr{ nullptr };
connect(ver_task.get(), &Task::succeeded, this, [this, response] {
QJsonParseError parse_error{};
@@ -264,7 +265,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
for (auto const& data : m_temp_versions)
addonIds.insert(data.addonId.toString(), data.hash);
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
Task::Ptr proj_task;
if (addonIds.isEmpty()) {
@@ -277,7 +278,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
// Prevents unfortunate timings when aborting the task
if (!proj_task)
- return Task::Ptr{nullptr};
+ return Task::Ptr{ nullptr };
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
QJsonParseError parse_error{};
@@ -345,7 +346,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
// Flame
Task::Ptr EnsureMetadataTask::flameVersionsTask()
{
- auto* response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
QList<uint> fingerprints;
for (auto& murmur : m_mods.keys()) {
@@ -413,7 +414,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
QHash<QString, QString> addonIds;
for (auto const& hash : m_mods.keys()) {
if (m_temp_versions.contains(hash)) {
- auto const& data = m_temp_versions.find(hash).value();
+ auto data = m_temp_versions.find(hash).value();
auto id_str = data.addonId.toString();
if (!id_str.isEmpty())
@@ -421,7 +422,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
}
}
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
Task::Ptr proj_task;
if (addonIds.isEmpty()) {
@@ -434,7 +435,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
// Prevents unfortunate timings when aborting the task
if (!proj_task)
- return Task::Ptr{nullptr};
+ return Task::Ptr{ nullptr };
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
QJsonParseError parse_error{};
diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h
index a4d431e3..b7670051 100644
--- a/launcher/modplatform/ModIndex.h
+++ b/launcher/modplatform/ModIndex.h
@@ -1,20 +1,21 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
-* PolyMC - Minecraft Launcher
-* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, version 3.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
#pragma once
@@ -33,6 +34,8 @@ enum class ResourceProvider { MODRINTH, FLAME };
enum class ResourceType { MOD, RESOURCE_PACK, SHADER_PACK };
+enum class DependencyType { REQUIRED, OPTIONAL, INCOMPATIBLE, EMBEDDED, TOOL, INCLUDE, UNKNOWN };
+
class ProviderCapabilities {
public:
auto name(ResourceProvider) -> const char*;
@@ -52,6 +55,12 @@ struct DonationData {
QString url;
};
+struct Dependency {
+ QVariant addonId;
+ DependencyType type;
+ QString version;
+};
+
struct IndexedVersion {
QVariant addonId;
QVariant fileId;
@@ -66,10 +75,10 @@ struct IndexedVersion {
QString hash;
bool is_preferred = true;
QString changelog;
+ QList<Dependency> dependencies;
// For internal use, not provided by APIs
bool is_currently_selected = false;
- QString custom_target_folder;
};
struct ExtraPackData {
@@ -116,12 +125,28 @@ struct IndexedPack {
if (!versionsLoaded)
return false;
- return std::any_of(versions.constBegin(), versions.constEnd(),
- [](auto const& v) { return v.is_currently_selected; });
+ return std::any_of(versions.constBegin(), versions.constEnd(), [](auto const& v) { return v.is_currently_selected; });
}
};
+struct OverrideDep {
+ QString quilt;
+ QString fabric;
+ QString slug;
+ ModPlatform::ResourceProvider provider;
+};
+
+inline auto getOverrideDeps() -> QList<OverrideDep>
+{
+ return { { "634179", "306612", "API", ModPlatform::ResourceProvider::FLAME },
+ { "720410", "308769", "KotlinLibraries", ModPlatform::ResourceProvider::FLAME },
+
+ { "qvIfYCYJ", "P7dR8mSH", "API", ModPlatform::ResourceProvider::MODRINTH },
+ { "lwVhp9o5", "Ha28R6CL", "KotlinLibraries", ModPlatform::ResourceProvider::MODRINTH } };
+};
+
} // namespace ModPlatform
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
+Q_DECLARE_METATYPE(ModPlatform::IndexedPack::Ptr)
Q_DECLARE_METATYPE(ModPlatform::ResourceProvider)
diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h
index d4c9af8a..a8f300b4 100644
--- a/launcher/modplatform/ResourceAPI.h
+++ b/launcher/modplatform/ResourceAPI.h
@@ -111,6 +111,16 @@ class ResourceAPI {
std::function<void(QJsonDocument&, ModPlatform::IndexedPack)> on_succeed;
};
+ struct DependencySearchArgs {
+ ModPlatform::Dependency dependency;
+ Version mcVersion;
+ ModLoaderTypes loader;
+ };
+
+ struct DependencySearchCallbacks {
+ std::function<void(QJsonDocument&, const ModPlatform::Dependency&)> on_succeed;
+ };
+
public:
/** Gets a list of available sorting methods for this API. */
[[nodiscard]] virtual auto getSortingMethods() const -> QList<SortingMethod> = 0;
@@ -121,14 +131,12 @@ class ResourceAPI {
qWarning() << "TODO: ResourceAPI::searchProjects";
return nullptr;
}
- /** getProject(QString addonId, QByteArray* responce)*/
- [[nodiscard]] virtual Task::Ptr getProject(QString, QByteArray*) const
+ [[nodiscard]] virtual Task::Ptr getProject(QString addonId, std::shared_ptr<QByteArray> response) const
{
qWarning() << "TODO: ResourceAPI::getProject";
return nullptr;
}
- /** getProjects(QStringList addonIds, QByteArray* responce) */
- [[nodiscard]] virtual Task::Ptr getProjects(QStringList, QByteArray*) const
+ [[nodiscard]] virtual Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
{
qWarning() << "TODO: ResourceAPI::getProjects";
return nullptr;
@@ -145,6 +153,12 @@ class ResourceAPI {
return nullptr;
}
+ [[nodiscard]] virtual Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const
+ {
+ qWarning() << "TODO";
+ return nullptr;
+ }
+
static auto getModLoaderString(ModLoaderType type) -> const QString
{
switch (type) {
diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
index 96cea7b7..22ea02da 100644
--- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
+++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
@@ -82,9 +82,9 @@ void PackInstallTask::executeTask()
{
qDebug() << "PackInstallTask::executeTask: " << QThread::currentThreadId();
NetJob::Ptr netJob{ new NetJob("ATLauncher::VersionFetch", APPLICATION->network()) };
- auto searchUrl = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json")
- .arg(m_pack_safe_name).arg(m_version_name);
- netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
+ auto searchUrl =
+ QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json").arg(m_pack_safe_name).arg(m_version_name);
+ netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
QObject::connect(netJob.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
QObject::connect(netJob.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
@@ -99,11 +99,12 @@ void PackInstallTask::onDownloadSucceeded()
qDebug() << "PackInstallTask::onDownloadSucceeded: " << QThread::currentThreadId();
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 ATLauncher at " << parse_error.offset << " reason: " << parse_error.errorString();
- qWarning() << response;
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from ATLauncher at " << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qWarning() << *response.get();
return;
}
auto obj = doc.object();
@@ -352,7 +353,7 @@ QString PackInstallTask::getVersionForLoader(QString uid)
if(m_version.loader.recommended || m_version.loader.latest) {
for (int i = 0; i < vlist->versions().size(); i++) {
auto version = vlist->versions().at(i);
- auto reqs = version->requires();
+ auto reqs = version->requiredSet();
// filter by minecraft version, if the loader depends on a certain version.
// not all mod loaders depend on a given Minecraft version, so we won't do this
diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.h b/launcher/modplatform/atlauncher/ATLPackInstallTask.h
index 90e25ae2..b82f523f 100644
--- a/launcher/modplatform/atlauncher/ATLPackInstallTask.h
+++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.h
@@ -40,12 +40,13 @@
#include "ATLPackManifest.h"
#include "InstanceTask.h"
-#include "net/NetJob.h"
-#include "settings/INISettingsObject.h"
+#include "meta/Version.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
-#include "meta/Version.h"
+#include "net/NetJob.h"
+#include "settings/INISettingsObject.h"
+#include <memory>
#include <optional>
namespace ATLauncher {
@@ -57,8 +58,7 @@ enum class InstallMode {
};
class UserInteractionSupport {
-
-public:
+ public:
/**
* Requests a user interaction to select which optional mods should be installed.
*/
@@ -74,23 +74,27 @@ public:
* Requests a user interaction to display a message.
*/
virtual void displayMessage(QString message) = 0;
+
+ virtual ~UserInteractionSupport() = default;
};
-class PackInstallTask : public InstanceTask
-{
-Q_OBJECT
+class PackInstallTask : public InstanceTask {
+ Q_OBJECT
-public:
- explicit PackInstallTask(UserInteractionSupport *support, QString packName, QString version, InstallMode installMode = InstallMode::Install);
- virtual ~PackInstallTask(){}
+ public:
+ explicit PackInstallTask(UserInteractionSupport* support,
+ QString packName,
+ QString version,
+ InstallMode installMode = InstallMode::Install);
+ virtual ~PackInstallTask() { delete m_support; }
bool canAbort() const override { return true; }
bool abort() override;
-protected:
+ protected:
virtual void executeTask() override;
-private slots:
+ private slots:
void onDownloadSucceeded();
void onDownloadFailed(QString reason);
void onDownloadAborted();
@@ -98,7 +102,7 @@ private slots:
void onModsDownloaded();
void onModsExtracted();
-private:
+ private:
QString getDirForModType(ModType type, QString raw);
QString getVersionForLoader(QString uid);
QString detectLibrary(VersionLibrary library);
@@ -110,20 +114,18 @@ private:
void installConfigs();
void extractConfigs();
void downloadMods();
- bool extractMods(
- const QMap<QString, VersionMod> &toExtract,
- const QMap<QString, VersionMod> &toDecomp,
- const QMap<QString, QString> &toCopy
- );
+ bool extractMods(const QMap<QString, VersionMod>& toExtract,
+ const QMap<QString, VersionMod>& toDecomp,
+ const QMap<QString, QString>& toCopy);
void install();
-private:
- UserInteractionSupport *m_support;
+ private:
+ UserInteractionSupport* m_support;
bool abortable = false;
NetJob::Ptr jobPtr;
- QByteArray response;
+ std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
InstallMode m_install_mode;
QString m_pack_name;
@@ -145,7 +147,6 @@ private:
QFuture<bool> m_modExtractFuture;
QFutureWatcher<bool> m_modExtractFutureWatcher;
-
};
-}
+} // namespace ATLauncher
diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp
index 83db642e..ce7a6055 100644
--- a/launcher/modplatform/flame/FileResolvingTask.cpp
+++ b/launcher/modplatform/flame/FileResolvingTask.cpp
@@ -25,15 +25,16 @@ void Flame::FileResolvingTask::executeTask()
setProgress(0, 3);
m_dljob.reset(new NetJob("Mod id resolver", m_network));
result.reset(new QByteArray());
- //build json data to send
+ // build json data to send
QJsonObject object;
- object["fileIds"] = QJsonArray::fromVariantList(std::accumulate(m_toProcess.files.begin(), m_toProcess.files.end(), QVariantList(), [](QVariantList& l, const File& s) {
- l.push_back(s.fileId);
- return l;
- }));
+ object["fileIds"] = QJsonArray::fromVariantList(
+ std::accumulate(m_toProcess.files.begin(), m_toProcess.files.end(), QVariantList(), [](QVariantList& l, const File& s) {
+ l.push_back(s.fileId);
+ return l;
+ }));
QByteArray data = Json::toText(object);
- auto dl = Net::Upload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result.get(), data);
+ auto dl = Net::Upload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result, data);
m_dljob->addNetAction(dl);
auto step_progress = std::make_shared<TaskStepProgress>();
@@ -87,17 +88,15 @@ void Flame::FileResolvingTask::netJobFinished()
auto fileid = Json::requireInteger(Json::requireObject(file)["id"]);
auto& out = m_toProcess.files[fileid];
try {
- out.parseFromObject(Json::requireObject(file));
+ out.parseFromObject(Json::requireObject(file));
} catch (const JSONValidationError& e) {
qDebug() << "Blocked mod on curseforge" << out.fileName;
auto hash = out.hash;
- if(!hash.isEmpty()) {
+ if (!hash.isEmpty()) {
auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash);
auto output = std::make_shared<QByteArray>();
- auto dl = Net::Download::makeByteArray(QUrl(url), output.get());
- QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() {
- out.resolved = true;
- });
+ auto dl = Net::Download::makeByteArray(QUrl(url), output);
+ QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() { out.resolved = true; });
m_checkJob->addNetAction(dl);
blockedProjects.insert(&out, output);
@@ -169,7 +168,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished() {
auto projectId = mod->projectId;
auto output = std::make_shared<QByteArray>();
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId);
- auto dl = Net::Download::makeByteArray(url, output.get());
+ auto dl = Net::Download::makeByteArray(url, output);
qDebug() << "Fetching url slug for file:" << mod->fileName;
QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp
index 92590a08..5b0b1d8b 100644
--- a/launcher/modplatform/flame/FlameAPI.cpp
+++ b/launcher/modplatform/flame/FlameAPI.cpp
@@ -11,7 +11,7 @@
#include "net/NetJob.h"
#include "net/Upload.h"
-Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, QByteArray* response)
+Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Flame::MatchFingerprints"), APPLICATION->network());
@@ -28,8 +28,6 @@ Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, QByteArra
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
-
return netJob;
}
@@ -43,7 +41,7 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
netJob->addNetAction(Net::Download::makeByteArray(
QString("https://api.curseforge.com/v1/mods/%1/files/%2/changelog")
.arg(QString::fromStdString(std::to_string(modId)), QString::fromStdString(std::to_string(fileId))),
- response.get()));
+ response));
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &changelog] {
QJsonParseError parse_error{};
@@ -75,8 +73,8 @@ auto FlameAPI::getModDescription(int modId) -> QString
auto netJob = makeShared<NetJob>(QString("Flame::ModDescription"), APPLICATION->network());
auto response = std::make_shared<QByteArray>();
- netJob->addNetAction(Net::Download::makeByteArray(
- QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response.get()));
+ netJob->addNetAction(
+ Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response));
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &description] {
QJsonParseError parse_error{};
@@ -115,7 +113,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
auto response = std::make_shared<QByteArray>();
ModPlatform::IndexedVersion ver;
- netJob->addNetAction(Net::Download::makeByteArray(versions_url, response.get()));
+ netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
QObject::connect(netJob.get(), &NetJob::succeeded, [response, args, &ver] {
QJsonParseError parse_error{};
@@ -137,7 +135,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
for (auto file : arr) {
auto file_obj = Json::requireObject(file);
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
- if(file_tmp.date > ver_tmp.date) {
+ if (file_tmp.date > ver_tmp.date) {
ver_tmp = file_tmp;
latest_file_obj = file_obj;
}
@@ -160,7 +158,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
return ver;
}
-Task::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const
+Task::Ptr FlameAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
{
auto netJob = makeShared<NetJob>(QString("Flame::GetProjects"), APPLICATION->network());
@@ -177,13 +175,12 @@ Task::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) cons
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
return netJob;
}
-Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const
+Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, std::shared_ptr<QByteArray> response) const
{
auto netJob = makeShared<NetJob>(QString("Flame::GetFiles"), APPLICATION->network());
@@ -200,7 +197,6 @@ Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) c
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
return netJob;
diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h
index 5811d717..0a6dc78f 100644
--- a/launcher/modplatform/flame/FlameAPI.h
+++ b/launcher/modplatform/flame/FlameAPI.h
@@ -4,7 +4,10 @@
#pragma once
+#include <algorithm>
+#include <memory>
#include "modplatform/ModIndex.h"
+#include "modplatform/ResourceAPI.h"
#include "modplatform/helpers/NetworkResourceAPI.h"
class FlameAPI : public NetworkResourceAPI {
@@ -14,9 +17,9 @@ class FlameAPI : public NetworkResourceAPI {
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
- Task::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
- Task::Ptr matchFingerprints(const QList<uint>& fingerprints, QByteArray* response);
- Task::Ptr getFiles(const QStringList& fileIds, QByteArray* response) const;
+ Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
+ Task::Ptr matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response);
+ Task::Ptr getFiles(const QStringList& fileIds, std::shared_ptr<QByteArray> response) const;
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
@@ -41,14 +44,15 @@ class FlameAPI : public NetworkResourceAPI {
return 4;
// TODO: remove this once Quilt drops official Fabric support
if (loaders & Quilt) // NOTE: Most if not all Fabric mods should work *currently*
- return 4; // Quilt would probably be 5
+ return 4; // Quilt would probably be 5
return 0;
}
private:
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
{
- auto gameVersionStr = args.versions.has_value() ? QString("gameVersion=%1").arg(args.versions.value().front().toString()) : QString();
+ auto gameVersionStr =
+ args.versions.has_value() ? QString("gameVersion=%1").arg(args.versions.value().front().toString()) : QString();
QStringList get_arguments;
get_arguments.append(QString("classId=%1").arg(getClassId(args.type)));
@@ -73,14 +77,48 @@ class FlameAPI : public NetworkResourceAPI {
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
{
- QString url{QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(args.pack.addonId.toString())};
+ auto addonId = args.pack.addonId.toString();
+ QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) };
QStringList get_parameters;
if (args.mcVersions.has_value())
get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString()));
- if (args.loaders.has_value())
- get_parameters.append(QString("modLoaderType=%1").arg(getMappedModLoader(args.loaders.value())));
+
+ if (args.loaders.has_value()) {
+ int mappedModLoader = getMappedModLoader(args.loaders.value());
+
+ if (args.loaders.value() & Quilt) {
+ auto overide = ModPlatform::getOverrideDeps();
+ auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
+ return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
+ });
+ if (over != overide.cend()) {
+ mappedModLoader = 5;
+ }
+ }
+
+ get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader));
+ }
return url + get_parameters.join('&');
};
+
+ [[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
+ {
+ auto mappedModLoader = getMappedModLoader(args.loader);
+ auto addonId = args.dependency.addonId.toString();
+ if (args.loader & Quilt) {
+ auto overide = ModPlatform::getOverrideDeps();
+ auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
+ return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
+ });
+ if (over != overide.cend()) {
+ mappedModLoader = 5;
+ }
+ }
+ return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&gameVersion=%2&modLoaderType=%3")
+ .arg(addonId)
+ .arg(args.mcVersion.toString())
+ .arg(mappedModLoader);
+ };
};
diff --git a/launcher/modplatform/flame/FlameCheckUpdate.cpp b/launcher/modplatform/flame/FlameCheckUpdate.cpp
index 06a89502..a2628e34 100644
--- a/launcher/modplatform/flame/FlameCheckUpdate.cpp
+++ b/launcher/modplatform/flame/FlameCheckUpdate.cpp
@@ -3,6 +3,7 @@
#include "FlameModIndex.h"
#include <MurmurHash2.h>
+#include <memory>
#include "FileSystem.h"
#include "Json.h"
@@ -30,7 +31,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info)
auto get_project_job = new NetJob("Flame::GetProjectJob", APPLICATION->network());
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(ver_info.addonId.toString());
auto dl = Net::Download::makeByteArray(url, response);
get_project_job->addNetAction(dl);
@@ -74,7 +75,7 @@ ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId)
auto get_file_info_job = new NetJob("Flame::GetFileInfoJob", APPLICATION->network());
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto url = QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(QString::number(addonId), QString::number(fileId));
auto dl = Net::Download::makeByteArray(url, response);
get_file_info_job->addNetAction(dl);
@@ -129,8 +130,7 @@ void FlameCheckUpdate::executeTask()
setStatus(tr("Getting API response from CurseForge for '%1'...").arg(mod->name()));
setProgress(i++, m_mods.size());
- ModPlatform::IndexedPack pack{ mod->metadata()->project_id.toString() };
- auto latest_ver = api.getLatestVersion({ pack, m_game_versions, m_loaders });
+ auto latest_ver = api.getLatestVersion({ { mod->metadata()->project_id.toString() }, m_game_versions, m_loaders });
// Check if we were aborted while getting the latest version
if (m_was_aborted) {
@@ -156,15 +156,15 @@ void FlameCheckUpdate::executeTask()
if (!latest_ver.hash.isEmpty() && (mod->metadata()->hash != latest_ver.hash || mod->status() == ModStatus::NotInstalled)) {
// Fake pack with the necessary info to pass to the download task :)
- ModPlatform::IndexedPack pack;
- pack.name = mod->name();
- pack.slug = mod->metadata()->slug;
- pack.addonId = mod->metadata()->project_id;
- pack.websiteUrl = mod->homeurl();
+ auto pack = std::make_shared<ModPlatform::IndexedPack>();
+ pack->name = mod->name();
+ pack->slug = mod->metadata()->slug;
+ pack->addonId = mod->metadata()->project_id;
+ pack->websiteUrl = mod->homeurl();
for (auto& author : mod->authors())
- pack.authors.append({ author });
- pack.description = mod->description();
- pack.provider = ModPlatform::ResourceProvider::FLAME;
+ pack->authors.append({ author });
+ pack->description = mod->description();
+ pack->provider = ModPlatform::ResourceProvider::FLAME;
auto old_version = mod->version();
if (old_version.isEmpty() && mod->status() != ModStatus::NotInstalled) {
@@ -173,7 +173,7 @@ void FlameCheckUpdate::executeTask()
}
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver, m_mods_folder);
- m_updatable.emplace_back(pack.name, mod->metadata()->hash, old_version, latest_ver.version,
+ m_updatable.emplace_back(pack->name, mod->metadata()->hash, old_version, latest_ver.version,
api.getModFileChangelog(latest_ver.addonId.toInt(), latest_ver.fileId.toInt()),
ModPlatform::ResourceProvider::FLAME, download_task);
}
diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp
index dae93d1c..f003ada9 100644
--- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp
+++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp
@@ -153,6 +153,9 @@ bool FlameCreationTask::updateInstance()
old_files.remove(file.key());
files_iterator = files.erase(files_iterator);
+
+ if (files_iterator != files.begin())
+ files_iterator--;
}
}
@@ -179,7 +182,7 @@ bool FlameCreationTask::updateInstance()
fileIds.append(QString::number(file.fileId));
}
- auto* raw_response = new QByteArray;
+ auto raw_response = std::make_shared<QByteArray>();
auto job = api.getFiles(fileIds, raw_response);
QEventLoop loop;
diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp
index 7498e830..227ce489 100644
--- a/launcher/modplatform/flame/FlameModIndex.cpp
+++ b/launcher/modplatform/flame/FlameModIndex.cpp
@@ -39,15 +39,15 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
auto links_obj = Json::ensureObject(obj, "links");
pack.extraData.issuesUrl = Json::ensureString(links_obj, "issuesUrl");
- if(pack.extraData.issuesUrl.endsWith('/'))
+ if (pack.extraData.issuesUrl.endsWith('/'))
pack.extraData.issuesUrl.chop(1);
pack.extraData.sourceUrl = Json::ensureString(links_obj, "sourceUrl");
- if(pack.extraData.sourceUrl.endsWith('/'))
+ if (pack.extraData.sourceUrl.endsWith('/'))
pack.extraData.sourceUrl.chop(1);
pack.extraData.wikiUrl = Json::ensureString(links_obj, "wikiUrl");
- if(pack.extraData.wikiUrl.endsWith('/'))
+ if (pack.extraData.wikiUrl.endsWith('/'))
pack.extraData.wikiUrl.chop(1);
if (!pack.extraData.body.isEmpty())
@@ -56,7 +56,7 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
- pack.extraData.body = api.getModDescription(pack.addonId.toInt());
+ pack.extraData.body = api.getModDescription(pack.addonId.toInt());
if (!pack.extraData.issuesUrl.isEmpty() || !pack.extraData.sourceUrl.isEmpty() || !pack.extraData.wikiUrl.isEmpty())
pack.extraDataLoaded = true;
@@ -64,12 +64,12 @@ void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
static QString enumToString(int hash_algorithm)
{
- switch(hash_algorithm){
- default:
- case 1:
- return "sha1";
- case 2:
- return "md5";
+ switch (hash_algorithm) {
+ default:
+ case 1:
+ return "sha1";
+ case 2:
+ return "md5";
}
}
@@ -84,12 +84,12 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
-
+
auto file = loadIndexedPackVersion(obj);
- if(!file.addonId.isValid())
+ if (!file.addonId.isValid())
file.addonId = pack.addonId;
- if(file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
unsortedVersions.append(file);
}
@@ -136,8 +136,61 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
}
}
- if(load_changelog)
+ auto dependencies = Json::ensureArray(obj, "dependencies");
+ for (auto d : dependencies) {
+ auto dep = Json::ensureObject(d);
+ ModPlatform::Dependency dependency;
+ dependency.addonId = Json::requireInteger(dep, "modId");
+ switch (Json::requireInteger(dep, "relationType")) {
+ case 1: // EmbeddedLibrary
+ dependency.type = ModPlatform::DependencyType::EMBEDDED;
+ break;
+ case 2: // OptionalDependency
+ dependency.type = ModPlatform::DependencyType::OPTIONAL;
+ break;
+ case 3: // RequiredDependency
+ dependency.type = ModPlatform::DependencyType::REQUIRED;
+ break;
+ case 4: // Tool
+ dependency.type = ModPlatform::DependencyType::TOOL;
+ break;
+ case 5: // Incompatible
+ dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
+ break;
+ case 6: // Include
+ dependency.type = ModPlatform::DependencyType::INCLUDE;
+ break;
+ default:
+ dependency.type = ModPlatform::DependencyType::UNKNOWN;
+ break;
+ }
+ file.dependencies.append(dependency);
+ }
+
+ if (load_changelog)
file.changelog = api.getModFileChangelog(file.addonId.toInt(), file.fileId.toInt());
return file;
}
+
+ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr)
+{
+ QVector<ModPlatform::IndexedVersion> versions;
+ for (auto versionIter : arr) {
+ auto obj = versionIter.toObject();
+
+ auto file = loadIndexedPackVersion(obj);
+ if (!file.addonId.isValid())
+ file.addonId = m.addonId;
+
+ if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ versions.append(file);
+ }
+
+ auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
+ // dates are in RFC 3339 format
+ return a.date > b.date;
+ };
+ std::sort(versions.begin(), versions.end(), orderSortPredicate);
+ return versions.front();
+};
diff --git a/launcher/modplatform/flame/FlameModIndex.h b/launcher/modplatform/flame/FlameModIndex.h
index 33c4a529..aa0d6f81 100644
--- a/launcher/modplatform/flame/FlameModIndex.h
+++ b/launcher/modplatform/flame/FlameModIndex.h
@@ -6,8 +6,8 @@
#include "modplatform/ModIndex.h"
-#include "BaseInstance.h"
#include <QNetworkAccessManager>
+#include "BaseInstance.h"
namespace FlameMod {
@@ -19,5 +19,5 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
const shared_qobject_ptr<QNetworkAccessManager>& network,
const BaseInstance* inst);
auto loadIndexedPackVersion(QJsonObject& obj, bool load_changelog = false) -> ModPlatform::IndexedVersion;
-
-} // namespace FlameMod
+auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
+} // namespace FlameMod \ No newline at end of file
diff --git a/launcher/modplatform/flame/FlamePackIndex.h b/launcher/modplatform/flame/FlamePackIndex.h
index 1ca0fc0e..b089b722 100644
--- a/launcher/modplatform/flame/FlamePackIndex.h
+++ b/launcher/modplatform/flame/FlamePackIndex.h
@@ -4,6 +4,7 @@
#include <QMetaType>
#include <QString>
#include <QVector>
+#include "modplatform/ModIndex.h"
namespace Flame {
@@ -27,8 +28,7 @@ struct ModpackExtra {
QString sourceUrl;
};
-struct IndexedPack
-{
+struct IndexedPack {
int addonId;
QString name;
QString description;
@@ -43,9 +43,9 @@ struct IndexedPack
ModpackExtra extra;
};
-void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
+void loadIndexedPack(IndexedPack& m, QJsonObject& obj);
void loadIndexedInfo(IndexedPack&, QJsonObject&);
-void loadIndexedPackVersions(IndexedPack & m, QJsonArray & arr);
-}
+void loadIndexedPackVersions(IndexedPack& m, QJsonArray& arr);
+} // namespace Flame
Q_DECLARE_METATYPE(Flame::IndexedPack)
diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp
index 81c94e1b..6ff1d171 100644
--- a/launcher/modplatform/helpers/HashUtils.cpp
+++ b/launcher/modplatform/helpers/HashUtils.cpp
@@ -71,6 +71,7 @@ void ModrinthHasher::executeTask()
emitFailed("Empty hash!");
} else {
emitSucceeded();
+ emit resultsReady(m_hash);
}
}
@@ -88,13 +89,13 @@ void FlameHasher::executeTask()
emitFailed("Empty hash!");
} else {
emitSucceeded();
+ emit resultsReady(m_hash);
}
}
-
-BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider)
- : Hasher(file_path), provider(provider) {
- setObjectName(QString("BlockedModHasher: %1").arg(file_path));
+BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider) : Hasher(file_path), provider(provider)
+{
+ setObjectName(QString("BlockedModHasher: %1").arg(file_path));
hash_type = ProviderCaps.hashType(provider).first();
}
@@ -120,14 +121,17 @@ void BlockedModHasher::executeTask()
emitFailed("Empty hash!");
} else {
emitSucceeded();
+ emit resultsReady(m_hash);
}
}
-QStringList BlockedModHasher::getHashTypes() {
+QStringList BlockedModHasher::getHashTypes()
+{
return ProviderCaps.hashType(provider);
}
-bool BlockedModHasher::useHashType(QString type) {
+bool BlockedModHasher::useHashType(QString type)
+{
auto types = ProviderCaps.hashType(provider);
if (types.contains(type)) {
hash_type = type;
diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h
index 91146a52..73a2435a 100644
--- a/launcher/modplatform/helpers/HashUtils.h
+++ b/launcher/modplatform/helpers/HashUtils.h
@@ -8,6 +8,7 @@
namespace Hashing {
class Hasher : public Task {
+ Q_OBJECT
public:
using Ptr = shared_qobject_ptr<Hasher>;
@@ -21,6 +22,9 @@ class Hasher : public Task {
QString getResult() const { return m_hash; };
QString getPath() const { return m_path; };
+ signals:
+ void resultsReady(QString hash);
+
protected:
QString m_hash;
QString m_path;
@@ -48,6 +52,7 @@ class BlockedModHasher : public Hasher {
QStringList getHashTypes();
bool useHashType(QString type);
+
private:
ModPlatform::ResourceProvider provider;
QString hash_type;
diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp
index a3c592fd..c278f800 100644
--- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp
+++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "NetworkResourceAPI.h"
+#include <memory>
#include "Application.h"
#include "net/NetJob.h"
@@ -19,12 +20,12 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
auto search_url = search_url_optional.value();
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto netJob = makeShared<NetJob>(QString("%1::Search").arg(debugName()), APPLICATION->network());
netJob->addNetAction(Net::Download::makeByteArray(QUrl(search_url), response));
- QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks]{
+ QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
@@ -40,27 +41,21 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
callbacks.on_succeed(doc);
});
- QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason){
+ QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) {
int network_error_code = -1;
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- callbacks.on_fail(reason, network_error_code);
- });
- QObject::connect(netJob.get(), &NetJob::aborted, [callbacks]{
- callbacks.on_abort();
- });
- QObject::connect(netJob.get(), &NetJob::finished, [response] {
- delete response;
+ callbacks.on_fail(reason, network_error_code);
});
-
+ QObject::connect(netJob.get(), &NetJob::aborted, [callbacks] { callbacks.on_abort(); });
return netJob;
}
Task::Ptr NetworkResourceAPI::getProjectInfo(ProjectInfoArgs&& args, ProjectInfoCallbacks&& callbacks) const
{
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto job = getProject(args.pack.addonId.toString(), response);
QObject::connect(job.get(), &NetJob::succeeded, [response, callbacks, args] {
@@ -88,7 +83,7 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
auto versions_url = versions_url_optional.value();
auto netJob = makeShared<NetJob>(QString("%1::Versions").arg(args.pack.name), APPLICATION->network());
- auto response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
@@ -105,14 +100,10 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
callbacks.on_succeed(doc, args.pack);
});
- QObject::connect(netJob.get(), &NetJob::finished, [response] {
- delete response;
- });
-
return netJob;
}
-Task::Ptr NetworkResourceAPI::getProject(QString addonId, QByteArray* response) const
+Task::Ptr NetworkResourceAPI::getProject(QString addonId, std::shared_ptr<QByteArray> response) const
{
auto project_url_optional = getInfoURL(addonId);
if (!project_url_optional.has_value())
@@ -124,9 +115,34 @@ Task::Ptr NetworkResourceAPI::getProject(QString addonId, QByteArray* response)
netJob->addNetAction(Net::Download::makeByteArray(QUrl(project_url), response));
- QObject::connect(netJob.get(), &NetJob::finished, [response] {
- delete response;
+ return netJob;
+}
+
+Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, DependencySearchCallbacks&& callbacks) const
+{
+ auto versions_url_optional = getDependencyURL(args);
+ if (!versions_url_optional.has_value())
+ return nullptr;
+
+ auto versions_url = versions_url_optional.value();
+
+ auto netJob = makeShared<NetJob>(QString("%1::Dependency").arg(args.dependency.addonId.toString()), APPLICATION->network());
+ auto response = std::make_shared<QByteArray>();
+
+ netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
+
+ QObject::connect(netJob.get(), &NetJob::succeeded, [=] {
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response for getting versions at " << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qWarning() << *response;
+ return;
+ }
+
+ callbacks.on_succeed(doc, args.dependency);
});
return netJob;
-}
+};
diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.h b/launcher/modplatform/helpers/NetworkResourceAPI.h
index 94813bec..b72e8253 100644
--- a/launcher/modplatform/helpers/NetworkResourceAPI.h
+++ b/launcher/modplatform/helpers/NetworkResourceAPI.h
@@ -4,19 +4,22 @@
#pragma once
+#include <memory>
#include "modplatform/ResourceAPI.h"
class NetworkResourceAPI : public ResourceAPI {
public:
Task::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const override;
- Task::Ptr getProject(QString addonId, QByteArray* response) const override;
+ Task::Ptr getProject(QString addonId, std::shared_ptr<QByteArray> response) const override;
Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const override;
+ Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const override;
protected:
[[nodiscard]] virtual auto getSearchURL(SearchArgs const& args) const -> std::optional<QString> = 0;
[[nodiscard]] virtual auto getInfoURL(QString const& id) const -> std::optional<QString> = 0;
[[nodiscard]] virtual auto getVersionsURL(VersionSearchArgs const& args) const -> std::optional<QString> = 0;
+ [[nodiscard]] virtual auto getDependencyURL(DependencySearchArgs const& args) const -> std::optional<QString> = 0;
};
diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
index e8768c5c..a8a0fc2c 100644
--- a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
+++ b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
@@ -51,11 +51,11 @@ void PackFetchTask::fetch()
QUrl publicPacksUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/modpacks.xml");
qDebug() << "Downloading public version info from" << publicPacksUrl.toString();
- jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, &publicModpacksXmlFileData));
+ jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, publicModpacksXmlFileData));
QUrl thirdPartyUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/thirdparty.xml");
qDebug() << "Downloading thirdparty version info from" << thirdPartyUrl.toString();
- jobPtr->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, &thirdPartyModpacksXmlFileData));
+ jobPtr->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, thirdPartyModpacksXmlFileData));
QObject::connect(jobPtr.get(), &NetJob::succeeded, this, &PackFetchTask::fileDownloadFinished);
QObject::connect(jobPtr.get(), &NetJob::failed, this, &PackFetchTask::fileDownloadFailed);
@@ -64,22 +64,19 @@ void PackFetchTask::fetch()
jobPtr->start();
}
-void PackFetchTask::fetchPrivate(const QStringList & toFetch)
+void PackFetchTask::fetchPrivate(const QStringList& toFetch)
{
QString privatePackBaseUrl = BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1.xml";
- for (auto &packCode: toFetch)
- {
- QByteArray *data = new QByteArray();
- NetJob *job = new NetJob("Fetching private pack", m_network);
+ for (auto& packCode : toFetch) {
+ auto data = std::make_shared<QByteArray>();
+ NetJob* job = new NetJob("Fetching private pack", m_network);
job->addNetAction(Net::Download::makeByteArray(privatePackBaseUrl.arg(packCode), data));
- QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode]
- {
+ QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode] {
ModpackList packs;
parseAndAddPacks(*data, PackType::Private, packs);
- foreach(Modpack currentPack, packs)
- {
+ foreach (Modpack currentPack, packs) {
currentPack.packCode = packCode;
emit privateFileDownloadFinished(currentPack);
}
@@ -87,24 +84,20 @@ void PackFetchTask::fetchPrivate(const QStringList & toFetch)
job->deleteLater();
data->clear();
- delete data;
});
- QObject::connect(job, &NetJob::failed, this, [this, job, packCode, data](QString reason)
- {
+ QObject::connect(job, &NetJob::failed, this, [this, job, packCode, data](QString reason) {
emit privateFileDownloadFailed(reason, packCode);
job->deleteLater();
data->clear();
- delete data;
});
- QObject::connect(job, &NetJob::aborted, this, [this, job, data]{
+ QObject::connect(job, &NetJob::aborted, this, [this, job, data] {
emit aborted();
job->deleteLater();
data->clear();
- delete data;
});
job->start();
@@ -117,27 +110,22 @@ void PackFetchTask::fileDownloadFinished()
QStringList failedLists;
- if(!parseAndAddPacks(publicModpacksXmlFileData, PackType::Public, publicPacks))
- {
+ if (!parseAndAddPacks(*publicModpacksXmlFileData, PackType::Public, publicPacks)) {
failedLists.append(tr("Public Packs"));
}
- if(!parseAndAddPacks(thirdPartyModpacksXmlFileData, PackType::ThirdParty, thirdPartyPacks))
- {
+ if (!parseAndAddPacks(*thirdPartyModpacksXmlFileData, PackType::ThirdParty, thirdPartyPacks)) {
failedLists.append(tr("Third Party Packs"));
}
- if(failedLists.size() > 0)
- {
+ if (failedLists.size() > 0) {
emit failed(tr("Failed to download some pack lists: %1").arg(failedLists.join("\n- ")));
- }
- else
- {
+ } else {
emit finished(publicPacks, thirdPartyPacks);
}
}
-bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, ModpackList &list)
+bool PackFetchTask::parseAndAddPacks(QByteArray& data, PackType packType, ModpackList& list)
{
QDomDocument doc;
@@ -145,8 +133,7 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
int errorLine = -1;
int errorCol = -1;
- if(!doc.setContent(data, false, &errorMsg, &errorLine, &errorCol))
- {
+ if (!doc.setContent(data, false, &errorMsg, &errorLine, &errorCol)) {
auto fullErrMsg = QString("Failed to fetch modpack data: %1 %2:%3!").arg(errorMsg).arg(errorLine).arg(errorCol);
qWarning() << fullErrMsg;
data.clear();
@@ -154,8 +141,7 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
}
QDomNodeList nodes = doc.elementsByTagName("modpack");
- for(int i = 0; i < nodes.length(); i++)
- {
+ for (int i = 0; i < nodes.length(); i++) {
QDomElement element = nodes.at(i).toElement();
Modpack modpack;
@@ -169,26 +155,20 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
modpack.broken = false;
modpack.bugged = false;
- //remove empty if the xml is bugged
- for(QString curr : modpack.oldVersions)
- {
- if(curr.isNull() || curr.isEmpty())
- {
+ // 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())
- {
+ 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
- {
+ } else {
modpack.broken = true;
qWarning() << "Broken pack:" << modpack.name << " => No valid version!";
}
@@ -218,4 +198,4 @@ void PackFetchTask::fileDownloadAborted()
emit aborted();
}
-}
+} // namespace LegacyFTB
diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.h b/launcher/modplatform/legacy_ftb/PackFetchTask.h
index 8f3c4f3b..f2116ce9 100644
--- a/launcher/modplatform/legacy_ftb/PackFetchTask.h
+++ b/launcher/modplatform/legacy_ftb/PackFetchTask.h
@@ -1,41 +1,41 @@
#pragma once
-#include "net/NetJob.h"
-#include <QTemporaryDir>
#include <QByteArray>
#include <QObject>
+#include <QTemporaryDir>
+#include <memory>
#include "PackHelpers.h"
+#include "net/NetJob.h"
namespace LegacyFTB {
class PackFetchTask : public QObject {
-
Q_OBJECT
-public:
- PackFetchTask(shared_qobject_ptr<QNetworkAccessManager> network) : QObject(nullptr), m_network(network) {};
+ public:
+ PackFetchTask(shared_qobject_ptr<QNetworkAccessManager> network) : QObject(nullptr), m_network(network){};
virtual ~PackFetchTask() = default;
void fetch();
- void fetchPrivate(const QStringList &toFetch);
+ void fetchPrivate(const QStringList& toFetch);
-private:
+ private:
shared_qobject_ptr<QNetworkAccessManager> m_network;
NetJob::Ptr jobPtr;
- QByteArray publicModpacksXmlFileData;
- QByteArray thirdPartyModpacksXmlFileData;
+ std::shared_ptr<QByteArray> publicModpacksXmlFileData = std::make_shared<QByteArray>();
+ std::shared_ptr<QByteArray> thirdPartyModpacksXmlFileData = std::make_shared<QByteArray>();
- bool parseAndAddPacks(QByteArray &data, PackType packType, ModpackList &list);
+ bool parseAndAddPacks(QByteArray& data, PackType packType, ModpackList& list);
ModpackList publicPacks;
ModpackList thirdPartyPacks;
-protected slots:
+ protected slots:
void fileDownloadFinished();
void fileDownloadFailed(QString reason);
void fileDownloadAborted();
-signals:
+ signals:
void finished(ModpackList publicPacks, ModpackList thirdPartyPacks);
void failed(QString reason);
void aborted();
@@ -44,4 +44,4 @@ signals:
void privateFileDownloadFailed(QString reason, QString packCode);
};
-}
+} // namespace LegacyFTB
diff --git a/launcher/modplatform/modrinth/ModrinthAPI.cpp b/launcher/modplatform/modrinth/ModrinthAPI.cpp
index 29e3d129..364cf3f3 100644
--- a/launcher/modplatform/modrinth/ModrinthAPI.cpp
+++ b/launcher/modplatform/modrinth/ModrinthAPI.cpp
@@ -9,19 +9,17 @@
#include "net/NetJob.h"
#include "net/Upload.h"
-Task::Ptr ModrinthAPI::currentVersion(QString hash, QString hash_format, QByteArray* response)
+Task::Ptr ModrinthAPI::currentVersion(QString hash, QString hash_format, std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersion"), APPLICATION->network());
netJob->addNetAction(Net::Download::makeByteArray(
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1?algorithm=%2").arg(hash, hash_format), response));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
-
return netJob;
}
-Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_format, QByteArray* response)
+Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_format, std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersions"), APPLICATION->network());
@@ -35,8 +33,6 @@ Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_f
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
-
return netJob;
}
@@ -44,7 +40,7 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
std::optional<ModLoaderTypes> loaders,
- QByteArray* response)
+ std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersion"), APPLICATION->network());
@@ -67,8 +63,6 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash,
netJob->addNetAction(Net::Upload::makeByteArray(
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1/update?algorithm=%2").arg(hash, hash_format), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
-
return netJob;
}
@@ -76,7 +70,7 @@ Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
std::optional<ModLoaderTypes> loaders,
- QByteArray* response)
+ std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersions"), APPLICATION->network());
@@ -101,22 +95,16 @@ Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes,
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files/update"), response, body_raw));
- QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
-
return netJob;
}
-Task::Ptr ModrinthAPI::getProjects(QStringList addonIds, QByteArray* response) const
+Task::Ptr ModrinthAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetProjects"), APPLICATION->network());
auto searchUrl = getMultipleModInfoURL(addonIds);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
- QObject::connect(netJob.get(), &NetJob::finished, [response, netJob] {
- delete response;
- });
-
return netJob;
}
diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h
index b91ac5c1..e83ed2bf 100644
--- a/launcher/modplatform/modrinth/ModrinthAPI.h
+++ b/launcher/modplatform/modrinth/ModrinthAPI.h
@@ -12,27 +12,23 @@
class ModrinthAPI : public NetworkResourceAPI {
public:
- auto currentVersion(QString hash,
- QString hash_format,
- QByteArray* response) -> Task::Ptr;
+ auto currentVersion(QString hash, QString hash_format, std::shared_ptr<QByteArray> response) -> Task::Ptr;
- auto currentVersions(const QStringList& hashes,
- QString hash_format,
- QByteArray* response) -> Task::Ptr;
+ auto currentVersions(const QStringList& hashes, QString hash_format, std::shared_ptr<QByteArray> response) -> Task::Ptr;
auto latestVersion(QString hash,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
std::optional<ModLoaderTypes> loaders,
- QByteArray* response) -> Task::Ptr;
+ std::shared_ptr<QByteArray> response) -> Task::Ptr;
auto latestVersions(const QStringList& hashes,
QString hash_format,
- std::optional<std::list<Version>> mcVersions,
- std::optional<ModLoaderTypes> loaders,
- QByteArray* response) -> Task::Ptr;
+ std::optional<std::list<Version>> mcVersions,
+ std::optional<ModLoaderTypes> loaders,
+ std::shared_ptr<QByteArray> response) -> Task::Ptr;
- Task::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
+ Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
public:
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
@@ -42,7 +38,7 @@ class ModrinthAPI : public NetworkResourceAPI {
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
{
QStringList l;
- for (auto loader : {Forge, Fabric, Quilt}) {
+ for (auto loader : { Forge, Fabric, Quilt }) {
if (types & loader) {
l << getModLoaderString(loader);
}
@@ -55,8 +51,7 @@ class ModrinthAPI : public NetworkResourceAPI {
static auto getModLoaderFilters(ModLoaderTypes types) -> const QString
{
QStringList l;
- for (auto loader : getModLoaderStrings(types))
- {
+ for (auto loader : getModLoaderStrings(types)) {
l << QString("\"categories:%1\"").arg(loader);
}
return l.join(',');
@@ -139,16 +134,22 @@ class ModrinthAPI : public NetworkResourceAPI {
auto getGameVersionsArray(std::list<Version> mcVersions) const -> QString
{
QString s;
- for(auto& ver : mcVersions){
+ for (auto& ver : mcVersions) {
s += QString("\"versions:%1\",").arg(ver.toString());
}
- s.remove(s.length() - 1, 1); //remove last comma
+ s.remove(s.length() - 1, 1); // remove last comma
return s.isEmpty() ? QString() : s;
}
- inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool
- {
- return loaders & (Forge | Fabric | Quilt);
- }
+ inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool { return loaders & (Forge | Fabric | Quilt); }
+ [[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
+ {
+ return args.dependency.version.length() != 0 ? QString("%1/version/%2").arg(BuildConfig.MODRINTH_PROD_URL, args.dependency.version)
+ : QString("%1/project/%2/version?game_versions=[\"%3\"]&loaders=[\"%4\"]")
+ .arg(BuildConfig.MODRINTH_PROD_URL)
+ .arg(args.dependency.addonId.toString())
+ .arg(args.mcVersion.toString())
+ .arg(getModLoaderStrings(args.loader).join("\",\""));
+ };
};
diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
index d1be7209..a7c22832 100644
--- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
+++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
@@ -53,12 +53,11 @@ void ModrinthCheckUpdate::executeTask()
// (though it will rarely happen, if at all)
if (mod->metadata()->hash_format != best_hash_type) {
auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath());
- connect(hash_task.get(), &Task::succeeded, [&] {
- QString hash (hash_task->getResult());
+ connect(hash_task.get(), &Hashing::Hasher::resultsReady, [&hashes, &mappings, mod](QString hash) {
hashes.append(hash);
mappings.insert(hash, mod);
});
- connect(hash_task.get(), &Task::failed, [this, hash_task] { failed("Failed to generate hash"); });
+ connect(hash_task.get(), &Task::failed, [this] { failed("Failed to generate hash"); });
hashing_task.addTask(hash_task);
} else {
hashes.append(hash);
@@ -67,11 +66,11 @@ void ModrinthCheckUpdate::executeTask()
}
QEventLoop loop;
- connect(&hashing_task, &Task::finished, [&loop]{ loop.quit(); });
+ connect(&hashing_task, &Task::finished, [&loop] { loop.quit(); });
hashing_task.start();
loop.exec();
- auto* response = new QByteArray();
+ auto response = std::make_shared<QByteArray>();
auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response);
QEventLoop lock;
@@ -112,7 +111,8 @@ void ModrinthCheckUpdate::executeTask()
// so we may want to filter it
QString loader_filter;
if (m_loaders.has_value()) {
- static auto flags = { ResourceAPI::ModLoaderType::Forge, ResourceAPI::ModLoaderType::Fabric, ResourceAPI::ModLoaderType::Quilt };
+ static auto flags = { ResourceAPI::ModLoaderType::Forge, ResourceAPI::ModLoaderType::Fabric,
+ ResourceAPI::ModLoaderType::Quilt };
for (auto flag : flags) {
if (m_loaders.value().testFlag(flag)) {
loader_filter = api.getModLoaderString(flag);
@@ -122,7 +122,8 @@ void ModrinthCheckUpdate::executeTask()
}
// Currently, we rely on a couple heuristics to determine whether an update is actually available or not:
- // - The file needs to be preferred: It is either the primary file, or the one found via (explicit) usage of the loader_filter
+ // - The file needs to be preferred: It is either the primary file, or the one found via (explicit) usage of the
+ // loader_filter
// - The version reported by the JAR is different from the version reported by the indexed version (it's usually the case)
// Such is the pain of having arbitrary files for a given version .-.
@@ -149,19 +150,19 @@ void ModrinthCheckUpdate::executeTask()
continue;
// Fake pack with the necessary info to pass to the download task :)
- ModPlatform::IndexedPack pack;
- pack.name = mod->name();
- pack.slug = mod->metadata()->slug;
- pack.addonId = mod->metadata()->project_id;
- pack.websiteUrl = mod->homeurl();
+ auto pack = std::make_shared<ModPlatform::IndexedPack>();
+ pack->name = mod->name();
+ pack->slug = mod->metadata()->slug;
+ pack->addonId = mod->metadata()->project_id;
+ pack->websiteUrl = mod->homeurl();
for (auto& author : mod->authors())
- pack.authors.append({ author });
- pack.description = mod->description();
- pack.provider = ModPlatform::ResourceProvider::MODRINTH;
+ pack->authors.append({ author });
+ pack->description = mod->description();
+ pack->provider = ModPlatform::ResourceProvider::MODRINTH;
auto download_task = makeShared<ResourceDownloadTask>(pack, project_ver, m_mods_folder);
- m_updatable.emplace_back(pack.name, hash, mod->version(), project_ver.version_number, project_ver.changelog,
+ m_updatable.emplace_back(pack->name, hash, mod->version(), project_ver.version_number, project_ver.changelog,
ModPlatform::ResourceProvider::MODRINTH, download_task);
}
}
diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp
index bb8227aa..76f07277 100644
--- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp
+++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp
@@ -214,7 +214,7 @@ bool ModrinthCreationTask::createInstance()
if (m_instIcon != "default") {
instance.setIconKey(m_instIcon);
- } else {
+ } else if (!m_managed_id.isEmpty()) {
instance.setIconKey("modrinth");
}
diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp
new file mode 100644
index 00000000..4cd88aa6
--- /dev/null
+++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "ModrinthPackExportTask.h"
+
+#include <QCryptographicHash>
+#include <QFileInfo>
+#include <QMessageBox>
+#include <QtConcurrentRun>
+#include "Json.h"
+#include "MMCZip.h"
+#include "minecraft/PackProfile.h"
+#include "minecraft/mod/ModFolderModel.h"
+
+const QStringList ModrinthPackExportTask::PREFIXES({ "mods/", "coremods/", "resourcepacks/", "texturepacks/", "shaderpacks/" });
+const QStringList ModrinthPackExportTask::FILE_EXTENSIONS({ "jar", "litemod", "zip" });
+
+ModrinthPackExportTask::ModrinthPackExportTask(const QString& name,
+ const QString& version,
+ const QString& summary,
+ InstancePtr instance,
+ const QString& output,
+ MMCZip::FilterFunction filter)
+ : name(name)
+ , version(version)
+ , summary(summary)
+ , instance(instance)
+ , mcInstance(dynamic_cast<MinecraftInstance*>(instance.get()))
+ , gameRoot(instance->gameRoot())
+ , output(output)
+ , filter(filter)
+{}
+
+void ModrinthPackExportTask::executeTask()
+{
+ setStatus(tr("Searching for files..."));
+ setProgress(0, 0);
+ collectFiles();
+}
+
+bool ModrinthPackExportTask::abort()
+{
+ if (task != nullptr) {
+ task->abort();
+ task = nullptr;
+ emitAborted();
+ return true;
+ }
+
+ if (buildZipFuture.isRunning()) {
+ buildZipFuture.cancel();
+ // NOTE: Here we don't do `emitAborted()` because it will be done when `buildZipFuture` actually cancels, which may not occur immediately.
+ return true;
+ }
+
+ return false;
+}
+
+void ModrinthPackExportTask::collectFiles()
+{
+ setAbortable(false);
+ QCoreApplication::processEvents();
+
+ files.clear();
+ if (!MMCZip::collectFileListRecursively(instance->gameRoot(), nullptr, &files, filter)) {
+ emitFailed(tr("Could not search for files"));
+ return;
+ }
+
+ pendingHashes.clear();
+ resolvedFiles.clear();
+
+ if (mcInstance) {
+ mcInstance->loaderModList()->update();
+ connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, &ModrinthPackExportTask::collectHashes);
+ } else
+ collectHashes();
+}
+
+void ModrinthPackExportTask::collectHashes()
+{
+ for (const QFileInfo& file : files) {
+ QCoreApplication::processEvents();
+
+ const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
+ // require sensible file types
+ if (!std::any_of(PREFIXES.begin(), PREFIXES.end(), [&relative](const QString& prefix) { return relative.startsWith(prefix); }))
+ continue;
+ if (!std::any_of(FILE_EXTENSIONS.begin(), FILE_EXTENSIONS.end(), [&relative](const QString& extension) {
+ return relative.endsWith('.' + extension) || relative.endsWith('.' + extension + ".disabled");
+ }))
+ continue;
+
+ QCryptographicHash sha512(QCryptographicHash::Algorithm::Sha512);
+
+ QFile openFile(file.absoluteFilePath());
+ if (!openFile.open(QFile::ReadOnly)) {
+ qWarning() << "Could not open" << file << "for hashing";
+ continue;
+ }
+
+ const QByteArray data = openFile.readAll();
+ if (openFile.error() != QFileDevice::NoError) {
+ qWarning() << "Could not read" << file;
+ continue;
+ }
+ sha512.addData(data);
+
+ auto allMods = mcInstance->loaderModList()->allMods();
+ if (auto modIter = std::find_if(allMods.begin(), allMods.end(), [&file](Mod* mod) { return mod->fileinfo() == file; });
+ modIter != allMods.end()) {
+ const Mod* mod = *modIter;
+ if (mod->metadata() != nullptr) {
+ QUrl& url = mod->metadata()->url;
+ // ensure the url is permitted on modrinth.com
+ if (!url.isEmpty() && BuildConfig.MODRINTH_MRPACK_HOSTS.contains(url.host())) {
+ qDebug() << "Resolving" << relative << "from index";
+
+ QCryptographicHash sha1(QCryptographicHash::Algorithm::Sha1);
+ sha1.addData(data);
+
+ ResolvedFile resolvedFile{ sha1.result().toHex(), sha512.result().toHex(), url.toEncoded(), openFile.size() };
+ resolvedFiles[relative] = resolvedFile;
+
+ // nice! we've managed to resolve based on local metadata!
+ // no need to enqueue it
+ continue;
+ }
+ }
+ }
+
+ qDebug() << "Enqueueing" << relative << "for Modrinth query";
+ pendingHashes[relative] = sha512.result().toHex();
+ }
+
+ setAbortable(true);
+ makeApiRequest();
+}
+
+void ModrinthPackExportTask::makeApiRequest()
+{
+ if (pendingHashes.isEmpty())
+ buildZip();
+ else {
+ auto response = std::make_shared<QByteArray>();
+ task = api.currentVersions(pendingHashes.values(), "sha512", response);
+ connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
+ connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
+ task->start();
+ }
+}
+
+void ModrinthPackExportTask::parseApiResponse(const std::shared_ptr<QByteArray> response)
+{
+ task = nullptr;
+
+ try {
+ const QJsonDocument doc = Json::requireDocument(*response);
+
+ QMapIterator<QString, QString> iterator(pendingHashes);
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ const QJsonObject obj = doc[iterator.value()].toObject();
+ if (obj.isEmpty())
+ continue;
+
+ const QJsonArray files = obj["files"].toArray();
+ if (auto fileIter = std::find_if(files.begin(), files.end(),
+ [&iterator](const QJsonValue& file) { return file["hashes"]["sha512"] == iterator.value(); });
+ fileIter != files.end()) {
+ // map the file to the url
+ resolvedFiles[iterator.key()] =
+ ResolvedFile{ fileIter->toObject()["hashes"].toObject()["sha1"].toString(), iterator.value(),
+ fileIter->toObject()["url"].toString(), fileIter->toObject()["size"].toInt() };
+ }
+ }
+ } catch (const Json::JsonException& e) {
+ emitFailed(tr("Failed to parse versions response: %1").arg(e.what()));
+ return;
+ }
+ pendingHashes.clear();
+ buildZip();
+}
+
+void ModrinthPackExportTask::buildZip()
+{
+ setStatus(tr("Adding files..."));
+
+ buildZipFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]() {
+ QuaZip zip(output);
+ if (!zip.open(QuaZip::mdCreate)) {
+ QFile::remove(output);
+ return BuildZipResult(tr("Could not create file"));
+ }
+
+ if (buildZipFuture.isCanceled())
+ return BuildZipResult();
+
+ QuaZipFile indexFile(&zip);
+ if (!indexFile.open(QIODevice::WriteOnly, QuaZipNewInfo("modrinth.index.json"))) {
+ QFile::remove(output);
+ return BuildZipResult(tr("Could not create index"));
+ }
+ indexFile.write(generateIndex());
+
+ size_t progress = 0;
+ for (const QFileInfo& file : files) {
+ if (buildZipFuture.isCanceled()) {
+ QFile::remove(output);
+ return BuildZipResult();
+ }
+
+ setProgress(progress, files.length());
+ const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
+ if (!resolvedFiles.contains(relative) && !JlCompress::compressFile(&zip, file.absoluteFilePath(), "overrides/" + relative)) {
+ QFile::remove(output);
+ return BuildZipResult(tr("Could not read and compress %1").arg(relative));
+ }
+ progress++;
+ }
+
+ zip.close();
+
+ if (zip.getZipError() != 0) {
+ QFile::remove(output);
+ return BuildZipResult(tr("A zip error occurred"));
+ }
+
+ return BuildZipResult();
+ });
+ connect(&buildZipWatcher, &QFutureWatcher<BuildZipResult>::finished, this, &ModrinthPackExportTask::finish);
+ buildZipWatcher.setFuture(buildZipFuture);
+}
+
+void ModrinthPackExportTask::finish()
+{
+ if (buildZipFuture.isCanceled())
+ emitAborted();
+ else {
+ const BuildZipResult result = buildZipFuture.result();
+ if (result.has_value())
+ emitFailed(result.value());
+ else
+ emitSucceeded();
+ }
+}
+
+QByteArray ModrinthPackExportTask::generateIndex()
+{
+ QJsonObject obj;
+ obj["formatVersion"] = 1;
+ obj["game"] = "minecraft";
+ obj["name"] = name;
+ obj["versionId"] = version;
+ if (!summary.isEmpty())
+ obj["summary"] = summary;
+
+ if (mcInstance) {
+ auto profile = mcInstance->getPackProfile();
+ // collect all supported components
+ const ComponentPtr minecraft = profile->getComponent("net.minecraft");
+ const ComponentPtr quilt = profile->getComponent("org.quiltmc.quilt-loader");
+ const ComponentPtr fabric = profile->getComponent("net.fabricmc.fabric-loader");
+ const ComponentPtr forge = profile->getComponent("net.minecraftforge");
+
+ // convert all available components to mrpack dependencies
+ QJsonObject dependencies;
+ if (minecraft != nullptr)
+ dependencies["minecraft"] = minecraft->m_version;
+ if (quilt != nullptr)
+ dependencies["quilt-loader"] = quilt->m_version;
+ if (fabric != nullptr)
+ dependencies["fabric-loader"] = fabric->m_version;
+ if (forge != nullptr)
+ dependencies["forge"] = forge->m_version;
+
+ obj["dependencies"] = dependencies;
+ }
+
+ QJsonArray files;
+ QMapIterator<QString, ResolvedFile> iterator(resolvedFiles);
+ while (iterator.hasNext()) {
+ iterator.next();
+
+ const ResolvedFile& value = iterator.value();
+
+ QJsonObject file;
+ file["path"] = iterator.key();
+ file["downloads"] = QJsonArray({ iterator.value().url });
+
+ QJsonObject hashes;
+ hashes["sha1"] = value.sha1;
+ hashes["sha512"] = value.sha512;
+
+ file["hashes"] = hashes;
+ file["fileSize"] = value.size;
+
+ files << file;
+ }
+ obj["files"] = files;
+
+ return QJsonDocument(obj).toJson(QJsonDocument::Compact);
+}
diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.h b/launcher/modplatform/modrinth/ModrinthPackExportTask.h
new file mode 100644
index 00000000..96f292c1
--- /dev/null
+++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <QFuture>
+#include <QFutureWatcher>
+#include "BaseInstance.h"
+#include "MMCZip.h"
+#include "minecraft/MinecraftInstance.h"
+#include "modplatform/modrinth/ModrinthAPI.h"
+#include "tasks/Task.h"
+
+class ModrinthPackExportTask : public Task {
+ public:
+ ModrinthPackExportTask(const QString& name,
+ const QString& version,
+ const QString& summary,
+ InstancePtr instance,
+ const QString& output,
+ MMCZip::FilterFunction filter);
+
+ protected:
+ void executeTask() override;
+ bool abort() override;
+
+ private:
+ struct ResolvedFile {
+ QString sha1, sha512, url;
+ qint64 size;
+ };
+
+ static const QStringList PREFIXES;
+ static const QStringList FILE_EXTENSIONS;
+
+ // inputs
+ const QString name, version, summary;
+ const InstancePtr instance;
+ MinecraftInstance* mcInstance;
+ const QDir gameRoot;
+ const QString output;
+ const MMCZip::FilterFunction filter;
+
+ typedef std::optional<QString> BuildZipResult;
+
+ ModrinthAPI api;
+ QFileInfoList files;
+ QMap<QString, QString> pendingHashes;
+ QMap<QString, ResolvedFile> resolvedFiles;
+ Task::Ptr task;
+ QFuture<BuildZipResult> buildZipFuture;
+ QFutureWatcher<BuildZipResult> buildZipWatcher;
+
+ void collectFiles();
+ void collectHashes();
+ void makeApiRequest();
+ void parseApiResponse(const std::shared_ptr<QByteArray> response);
+ void buildZip();
+ void finish();
+
+ QByteArray generateIndex();
+};
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
index 7ade131e..b4037349 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
@@ -22,7 +22,7 @@
#include "Json.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
-#include "net/NetJob.h"
+#include "modplatform/ModIndex.h"
static ModrinthAPI api;
static ModPlatform::ProviderCapabilities ProviderCaps;
@@ -140,6 +140,28 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
file.version_number = Json::requireString(obj, "version_number");
file.changelog = Json::requireString(obj, "changelog");
+ auto dependencies = Json::ensureArray(obj, "dependencies");
+ for (auto d : dependencies) {
+ auto dep = Json::ensureObject(d);
+ ModPlatform::Dependency dependency;
+ dependency.addonId = Json::ensureString(dep, "project_id");
+ dependency.version = Json::ensureString(dep, "version_id");
+ auto depType = Json::requireString(dep, "dependency_type");
+
+ if (depType == "required")
+ dependency.type = ModPlatform::DependencyType::REQUIRED;
+ else if (depType == "optional")
+ dependency.type = ModPlatform::DependencyType::OPTIONAL;
+ else if (depType == "incompatible")
+ dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
+ else if (depType == "embedded")
+ dependency.type = ModPlatform::DependencyType::EMBEDDED;
+ else
+ dependency.type = ModPlatform::DependencyType::UNKNOWN;
+
+ file.dependencies.append(dependency);
+ }
+
auto files = Json::requireArray(obj, "files");
int i = 0;
@@ -195,3 +217,22 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
return {};
}
+
+auto Modrinth::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
+{
+ QVector<ModPlatform::IndexedVersion> versions;
+
+ for (auto versionIter : arr) {
+ auto obj = versionIter.toObject();
+ auto file = loadIndexedPackVersion(obj);
+
+ if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ versions.append(file);
+ }
+ auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
+ // dates are in RFC 3339 format
+ return a.date > b.date;
+ };
+ std::sort(versions.begin(), versions.end(), orderSortPredicate);
+ return versions.length() != 0 ? versions.front() : ModPlatform::IndexedVersion();
+} \ No newline at end of file
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h
index e73e4b18..a8d986c5 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.h
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h
@@ -19,8 +19,8 @@
#include "modplatform/ModIndex.h"
-#include "BaseInstance.h"
#include <QNetworkAccessManager>
+#include "BaseInstance.h"
namespace Modrinth {
@@ -31,5 +31,6 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
const shared_qobject_ptr<QNetworkAccessManager>& network,
const BaseInstance* inst);
auto loadIndexedPackVersion(QJsonObject& obj, QString hash_type = "sha512", QString filename_prefer = "") -> ModPlatform::IndexedVersion;
+auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
} // namespace Modrinth
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp
index c26d6a5a..6a05d17a 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.cpp
+++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp
@@ -37,20 +37,19 @@
#include <FileSystem.h>
#include <Json.h>
-#include <QtConcurrentRun>
#include <MMCZip.h>
+#include <QtConcurrentRun>
-#include "TechnicPackProcessor.h"
#include "SolderPackManifest.h"
+#include "TechnicPackProcessor.h"
#include "net/ChecksumValidator.h"
-Technic::SolderPackInstallTask::SolderPackInstallTask(
- shared_qobject_ptr<QNetworkAccessManager> network,
- const QUrl &solderUrl,
- const QString &pack,
- const QString &version,
- const QString &minecraftVersion
-) {
+Technic::SolderPackInstallTask::SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network,
+ const QUrl& solderUrl,
+ const QString& pack,
+ const QString& version,
+ const QString& minecraftVersion)
+{
m_solderUrl = solderUrl;
m_pack = pack;
m_version = version;
@@ -58,9 +57,9 @@ Technic::SolderPackInstallTask::SolderPackInstallTask(
m_minecraftVersion = minecraftVersion;
}
-bool Technic::SolderPackInstallTask::abort() {
- if(m_abortable)
- {
+bool Technic::SolderPackInstallTask::abort()
+{
+ if (m_abortable) {
return m_filesNetJob->abort();
}
return false;
@@ -72,7 +71,7 @@ void Technic::SolderPackInstallTask::executeTask()
m_filesNetJob.reset(new NetJob(tr("Resolving modpack files"), m_network));
auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version);
- m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, &m_response));
+ m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, m_response));
auto job = m_filesNetJob.get();
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded);
@@ -85,11 +84,11 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
{
setStatus(tr("Downloading modpack"));
- QJsonParseError parse_error {};
- QJsonDocument doc = QJsonDocument::fromJson(m_response, &parse_error);
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*m_response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
- qWarning() << m_response;
+ qWarning() << *m_response;
return;
}
auto obj = doc.object();
@@ -110,7 +109,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
m_filesNetJob.reset(new NetJob(tr("Downloading modpack"), m_network));
int i = 0;
- for (const auto &mod : build.mods) {
+ for (const auto& mod : build.mods) {
auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i));
auto dl = Net::Download::makeFile(mod.url, path);
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.h b/launcher/modplatform/technic/SolderPackInstallTask.h
index aa14ce88..f2c6a83a 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.h
+++ b/launcher/modplatform/technic/SolderPackInstallTask.h
@@ -40,45 +40,48 @@
#include <tasks/Task.h>
#include <QUrl>
+#include <memory>
-namespace Technic
-{
- class SolderPackInstallTask : public InstanceTask
- {
- Q_OBJECT
- public:
- explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, const QUrl &solderUrl, const QString& pack, const QString& version, const QString &minecraftVersion);
+namespace Technic {
+class SolderPackInstallTask : public InstanceTask {
+ Q_OBJECT
+ public:
+ explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network,
+ const QUrl& solderUrl,
+ const QString& pack,
+ const QString& version,
+ const QString& minecraftVersion);
- bool canAbort() const override { return true; }
- bool abort() override;
+ bool canAbort() const override { return true; }
+ bool abort() override;
- protected:
- //! Entry point for tasks.
- virtual void executeTask() override;
+ protected:
+ //! Entry point for tasks.
+ virtual void executeTask() override;
- private slots:
- void fileListSucceeded();
- void downloadSucceeded();
- void downloadFailed(QString reason);
- void downloadProgressChanged(qint64 current, qint64 total);
- void downloadAborted();
- void extractFinished();
- void extractAborted();
+ private slots:
+ void fileListSucceeded();
+ void downloadSucceeded();
+ void downloadFailed(QString reason);
+ void downloadProgressChanged(qint64 current, qint64 total);
+ void downloadAborted();
+ void extractFinished();
+ void extractAborted();
- private:
- bool m_abortable = false;
+ private:
+ bool m_abortable = false;
- shared_qobject_ptr<QNetworkAccessManager> m_network;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
- NetJob::Ptr m_filesNetJob;
- QUrl m_solderUrl;
- QString m_pack;
- QString m_version;
- QString m_minecraftVersion;
- QByteArray m_response;
- QTemporaryDir m_outputDir;
- int m_modCount;
- QFuture<bool> m_extractFuture;
- QFutureWatcher<bool> m_extractFutureWatcher;
- };
-}
+ NetJob::Ptr m_filesNetJob;
+ QUrl m_solderUrl;
+ QString m_pack;
+ QString m_version;
+ QString m_minecraftVersion;
+ std::shared_ptr<QByteArray> m_response = std::make_shared<QByteArray>();
+ QTemporaryDir m_outputDir;
+ int m_modCount;
+ QFuture<bool> m_extractFuture;
+ QFutureWatcher<bool> m_extractFutureWatcher;
+};
+} // namespace Technic