refactor: generalize mod models and APIs to resources
Firstly, this abstract away behavior in the mod download models that can also be applied to other types of resources into a superclass, allowing other resource types to be implemented without so much code duplication. For that, this also generalizes the APIs used (currently, ModrinthAPI and FlameAPI) to be able to make requests to other types of resources. It also does a general cleanup of both of those. In particular, this makes use of std::optional instead of invalid values for errors and, well, optional values :p This is a squash of some commits that were becoming too interlaced together to be cleanly separated. Signed-off-by: flow <flowlnlnln@gmail.com>
This commit is contained in:
@ -1,18 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "modplatform/ModAPI.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "tasks/Task.h"
|
||||
|
||||
class ModDownloadTask;
|
||||
class ResourceDownloadTask;
|
||||
class ModFolderModel;
|
||||
|
||||
class CheckUpdateTask : public Task {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheckUpdateTask(QList<Mod*>& mods, std::list<Version>& mcVersions, ModAPI::ModLoaderTypes loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
CheckUpdateTask(QList<Mod*>& mods, std::list<Version>& mcVersions, std::optional<ResourceAPI::ModLoaderTypes> loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
: Task(nullptr), m_mods(mods), m_game_versions(mcVersions), m_loaders(loaders), m_mods_folder(mods_folder) {};
|
||||
|
||||
struct UpdatableMod {
|
||||
@ -21,11 +21,11 @@ class CheckUpdateTask : public Task {
|
||||
QString old_version;
|
||||
QString new_version;
|
||||
QString changelog;
|
||||
ModPlatform::Provider provider;
|
||||
ModDownloadTask* download;
|
||||
ModPlatform::ResourceProvider provider;
|
||||
ResourceDownloadTask* download;
|
||||
|
||||
public:
|
||||
UpdatableMod(QString name, QString old_h, QString old_v, QString new_v, QString changelog, ModPlatform::Provider p, ModDownloadTask* t)
|
||||
UpdatableMod(QString name, QString old_h, QString old_v, QString new_v, QString changelog, ModPlatform::ResourceProvider p, ResourceDownloadTask* t)
|
||||
: name(name), old_hash(old_h), old_version(old_v), new_version(new_v), changelog(changelog), provider(p), download(t)
|
||||
{}
|
||||
};
|
||||
@ -44,7 +44,7 @@ class CheckUpdateTask : public Task {
|
||||
protected:
|
||||
QList<Mod*>& m_mods;
|
||||
std::list<Version>& m_game_versions;
|
||||
ModAPI::ModLoaderTypes m_loaders;
|
||||
std::optional<ResourceAPI::ModLoaderTypes> m_loaders;
|
||||
std::shared_ptr<ModFolderModel> m_mods_folder;
|
||||
|
||||
std::vector<UpdatableMod> m_updatable;
|
||||
|
@ -20,7 +20,7 @@ static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
static ModrinthAPI modrinth_api;
|
||||
static FlameAPI flame_api;
|
||||
|
||||
EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::Provider prov)
|
||||
EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::ResourceProvider prov)
|
||||
: Task(nullptr), m_index_dir(dir), m_provider(prov), m_hashing_task(nullptr), m_current_task(nullptr)
|
||||
{
|
||||
auto hash_task = createNewHash(mod);
|
||||
@ -31,7 +31,7 @@ EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::Provider
|
||||
hash_task->start();
|
||||
}
|
||||
|
||||
EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform::Provider prov)
|
||||
EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform::ResourceProvider prov)
|
||||
: Task(nullptr), m_index_dir(dir), m_provider(prov), m_current_task(nullptr)
|
||||
{
|
||||
m_hashing_task = new ConcurrentTask(this, "MakeHashesTask", 10);
|
||||
@ -110,10 +110,10 @@ void EnsureMetadataTask::executeTask()
|
||||
NetJob::Ptr version_task;
|
||||
|
||||
switch (m_provider) {
|
||||
case (ModPlatform::Provider::MODRINTH):
|
||||
case (ModPlatform::ResourceProvider::MODRINTH):
|
||||
version_task = modrinthVersionsTask();
|
||||
break;
|
||||
case (ModPlatform::Provider::FLAME):
|
||||
case (ModPlatform::ResourceProvider::FLAME):
|
||||
version_task = flameVersionsTask();
|
||||
break;
|
||||
}
|
||||
@ -130,10 +130,10 @@ void EnsureMetadataTask::executeTask()
|
||||
NetJob::Ptr project_task;
|
||||
|
||||
switch (m_provider) {
|
||||
case (ModPlatform::Provider::MODRINTH):
|
||||
case (ModPlatform::ResourceProvider::MODRINTH):
|
||||
project_task = modrinthProjectsTask();
|
||||
break;
|
||||
case (ModPlatform::Provider::FLAME):
|
||||
case (ModPlatform::ResourceProvider::FLAME):
|
||||
project_task = flameProjectsTask();
|
||||
break;
|
||||
}
|
||||
@ -212,7 +212,7 @@ void EnsureMetadataTask::emitFail(Mod* m, QString key, RemoveFromList remove)
|
||||
|
||||
NetJob::Ptr EnsureMetadataTask::modrinthVersionsTask()
|
||||
{
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH).first();
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
|
||||
auto* response = new QByteArray();
|
||||
auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response);
|
||||
|
@ -14,8 +14,8 @@ class EnsureMetadataTask : public Task {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EnsureMetadataTask(Mod*, QDir, ModPlatform::Provider = ModPlatform::Provider::MODRINTH);
|
||||
EnsureMetadataTask(QList<Mod*>&, QDir, ModPlatform::Provider = ModPlatform::Provider::MODRINTH);
|
||||
EnsureMetadataTask(Mod*, QDir, ModPlatform::ResourceProvider = ModPlatform::ResourceProvider::MODRINTH);
|
||||
EnsureMetadataTask(QList<Mod*>&, QDir, ModPlatform::ResourceProvider = ModPlatform::ResourceProvider::MODRINTH);
|
||||
|
||||
~EnsureMetadataTask() = default;
|
||||
|
||||
@ -57,7 +57,7 @@ class EnsureMetadataTask : public Task {
|
||||
private:
|
||||
QHash<QString, Mod*> m_mods;
|
||||
QDir m_index_dir;
|
||||
ModPlatform::Provider m_provider;
|
||||
ModPlatform::ResourceProvider m_provider;
|
||||
|
||||
QHash<QString, ModPlatform::IndexedVersion> m_temp_versions;
|
||||
ConcurrentTask* m_hashing_task;
|
||||
|
@ -1,118 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <list>
|
||||
|
||||
#include "../Version.h"
|
||||
#include "net/NetJob.h"
|
||||
|
||||
namespace ModPlatform {
|
||||
class ListModel;
|
||||
struct IndexedPack;
|
||||
}
|
||||
|
||||
class ModAPI {
|
||||
protected:
|
||||
using CallerType = ModPlatform::ListModel;
|
||||
|
||||
public:
|
||||
virtual ~ModAPI() = default;
|
||||
|
||||
enum ModLoaderType {
|
||||
Unspecified = 0,
|
||||
Forge = 1 << 0,
|
||||
Cauldron = 1 << 1,
|
||||
LiteLoader = 1 << 2,
|
||||
Fabric = 1 << 3,
|
||||
Quilt = 1 << 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
|
||||
|
||||
struct SearchArgs {
|
||||
int offset;
|
||||
QString search;
|
||||
QString sorting;
|
||||
ModLoaderTypes loaders;
|
||||
std::list<Version> versions;
|
||||
};
|
||||
|
||||
virtual void searchMods(CallerType* caller, SearchArgs&& args) const = 0;
|
||||
virtual void getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback) = 0;
|
||||
|
||||
virtual auto getProject(QString addonId, QByteArray* response) const -> NetJob* = 0;
|
||||
virtual auto getProjects(QStringList addonIds, QByteArray* response) const -> NetJob* = 0;
|
||||
|
||||
|
||||
struct VersionSearchArgs {
|
||||
QString addonId;
|
||||
std::list<Version> mcVersions;
|
||||
ModLoaderTypes loaders;
|
||||
};
|
||||
|
||||
virtual void getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const = 0;
|
||||
|
||||
static auto getModLoaderString(ModLoaderType type) -> const QString {
|
||||
switch (type) {
|
||||
case Unspecified:
|
||||
break;
|
||||
case Forge:
|
||||
return "forge";
|
||||
case Cauldron:
|
||||
return "cauldron";
|
||||
case LiteLoader:
|
||||
return "liteloader";
|
||||
case Fabric:
|
||||
return "fabric";
|
||||
case Quilt:
|
||||
return "quilt";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
inline auto getGameVersionsString(std::list<Version> mcVersions) const -> QString
|
||||
{
|
||||
QString s;
|
||||
for(auto& ver : mcVersions){
|
||||
s += QString("\"%1\",").arg(ver.toString());
|
||||
}
|
||||
s.remove(s.length() - 1, 1); //remove last comma
|
||||
return s;
|
||||
}
|
||||
};
|
@ -24,47 +24,47 @@
|
||||
|
||||
namespace ModPlatform {
|
||||
|
||||
auto ProviderCapabilities::name(Provider p) -> const char*
|
||||
auto ProviderCapabilities::name(ResourceProvider p) -> const char*
|
||||
{
|
||||
switch (p) {
|
||||
case Provider::MODRINTH:
|
||||
case ResourceProvider::MODRINTH:
|
||||
return "modrinth";
|
||||
case Provider::FLAME:
|
||||
case ResourceProvider::FLAME:
|
||||
return "curseforge";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
auto ProviderCapabilities::readableName(Provider p) -> QString
|
||||
auto ProviderCapabilities::readableName(ResourceProvider p) -> QString
|
||||
{
|
||||
switch (p) {
|
||||
case Provider::MODRINTH:
|
||||
case ResourceProvider::MODRINTH:
|
||||
return "Modrinth";
|
||||
case Provider::FLAME:
|
||||
case ResourceProvider::FLAME:
|
||||
return "CurseForge";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
auto ProviderCapabilities::hashType(Provider p) -> QStringList
|
||||
auto ProviderCapabilities::hashType(ResourceProvider p) -> QStringList
|
||||
{
|
||||
switch (p) {
|
||||
case Provider::MODRINTH:
|
||||
case ResourceProvider::MODRINTH:
|
||||
return { "sha512", "sha1" };
|
||||
case Provider::FLAME:
|
||||
case ResourceProvider::FLAME:
|
||||
// Try newer formats first, fall back to old format
|
||||
return { "sha1", "md5", "murmur2" };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ProviderCapabilities::hash(Provider p, QIODevice* device, QString type) -> QString
|
||||
auto ProviderCapabilities::hash(ResourceProvider p, QIODevice* device, QString type) -> QString
|
||||
{
|
||||
QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1;
|
||||
switch (p) {
|
||||
case Provider::MODRINTH: {
|
||||
case ResourceProvider::MODRINTH: {
|
||||
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Sha512;
|
||||
break;
|
||||
}
|
||||
case Provider::FLAME:
|
||||
case ResourceProvider::FLAME:
|
||||
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Md5;
|
||||
break;
|
||||
}
|
||||
|
@ -28,17 +28,16 @@ class QIODevice;
|
||||
|
||||
namespace ModPlatform {
|
||||
|
||||
enum class Provider {
|
||||
MODRINTH,
|
||||
FLAME
|
||||
};
|
||||
enum class ResourceProvider { MODRINTH, FLAME };
|
||||
|
||||
enum class ResourceType { MOD, RESOURCE_PACK };
|
||||
|
||||
class ProviderCapabilities {
|
||||
public:
|
||||
auto name(Provider) -> const char*;
|
||||
auto readableName(Provider) -> QString;
|
||||
auto hashType(Provider) -> QStringList;
|
||||
auto hash(Provider, QIODevice*, QString type = "") -> QString;
|
||||
auto name(ResourceProvider) -> const char*;
|
||||
auto readableName(ResourceProvider) -> QString;
|
||||
auto hashType(ResourceProvider) -> QStringList;
|
||||
auto hash(ResourceProvider, QIODevice*, QString type = "") -> QString;
|
||||
};
|
||||
|
||||
struct ModpackAuthor {
|
||||
@ -81,7 +80,7 @@ struct ExtraPackData {
|
||||
|
||||
struct IndexedPack {
|
||||
QVariant addonId;
|
||||
Provider provider;
|
||||
ResourceProvider provider;
|
||||
QString name;
|
||||
QString slug;
|
||||
QString description;
|
||||
@ -101,4 +100,4 @@ struct IndexedPack {
|
||||
} // namespace ModPlatform
|
||||
|
||||
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
|
||||
Q_DECLARE_METATYPE(ModPlatform::Provider)
|
||||
Q_DECLARE_METATYPE(ModPlatform::ResourceProvider)
|
||||
|
149
launcher/modplatform/ResourceAPI.h
Normal file
149
launcher/modplatform/ResourceAPI.h
Normal file
@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "../Version.h"
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "net/NetJob.h"
|
||||
|
||||
/* Simple class with a common interface for interacting with APIs */
|
||||
class ResourceAPI {
|
||||
public:
|
||||
virtual ~ResourceAPI() = default;
|
||||
|
||||
enum ModLoaderType { Forge = 1 << 0, Cauldron = 1 << 1, LiteLoader = 1 << 2, Fabric = 1 << 3, Quilt = 1 << 4 };
|
||||
Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
|
||||
|
||||
struct SearchArgs {
|
||||
ModPlatform::ResourceType type{};
|
||||
int offset = 0;
|
||||
|
||||
std::optional<QString> search;
|
||||
std::optional<QString> sorting;
|
||||
std::optional<ModLoaderTypes> loaders;
|
||||
std::optional<std::list<Version> > versions;
|
||||
};
|
||||
struct SearchCallbacks {
|
||||
std::function<void(QJsonDocument&)> on_succeed;
|
||||
std::function<void(QString const& reason, int network_error_code)> on_fail;
|
||||
std::function<void()> on_abort;
|
||||
};
|
||||
|
||||
struct VersionSearchArgs {
|
||||
QString addonId;
|
||||
|
||||
std::optional<std::list<Version> > mcVersions;
|
||||
std::optional<ModLoaderTypes> loaders;
|
||||
};
|
||||
struct VersionSearchCallbacks {
|
||||
std::function<void(QJsonDocument&, QString)> on_succeed;
|
||||
};
|
||||
|
||||
struct ProjectInfoArgs {
|
||||
ModPlatform::IndexedPack& pack;
|
||||
|
||||
void operator=(ProjectInfoArgs other) { pack = other.pack; }
|
||||
};
|
||||
struct ProjectInfoCallbacks {
|
||||
std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> on_succeed;
|
||||
};
|
||||
|
||||
public slots:
|
||||
[[nodiscard]] virtual NetJob::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
[[nodiscard]] virtual NetJob::Ptr getProject(QString addonId, QByteArray* response) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
[[nodiscard]] virtual NetJob::Ptr getProjects(QStringList addonIds, QByteArray* response) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual NetJob::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
[[nodiscard]] virtual NetJob::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static auto getModLoaderString(ModLoaderType type) -> const QString
|
||||
{
|
||||
switch (type) {
|
||||
case Forge:
|
||||
return "forge";
|
||||
case Cauldron:
|
||||
return "cauldron";
|
||||
case LiteLoader:
|
||||
return "liteloader";
|
||||
case Fabric:
|
||||
return "fabric";
|
||||
case Quilt:
|
||||
return "quilt";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] inline QString debugName() const { return "External resource API"; }
|
||||
|
||||
[[nodiscard]] inline auto getGameVersionsString(std::list<Version> mcVersions) const -> QString
|
||||
{
|
||||
QString s;
|
||||
for (auto& ver : mcVersions) {
|
||||
s += QString("\"%1\",").arg(ver.toString());
|
||||
}
|
||||
s.remove(s.length() - 1, 1); // remove last comma
|
||||
return s;
|
||||
}
|
||||
};
|
@ -106,13 +106,19 @@ auto FlameAPI::getModDescription(int modId) -> QString
|
||||
|
||||
auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
auto versions_url_optional = getVersionsURL(args);
|
||||
if (!versions_url_optional.has_value())
|
||||
return {};
|
||||
|
||||
auto versions_url = versions_url_optional.value();
|
||||
|
||||
QEventLoop loop;
|
||||
|
||||
auto netJob = new NetJob(QString("Flame::GetLatestVersion(%1)").arg(args.addonId), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
ModPlatform::IndexedVersion ver;
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(args), response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, [response, args, &ver] {
|
||||
QJsonParseError parse_error{};
|
||||
@ -161,7 +167,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
||||
return ver;
|
||||
}
|
||||
|
||||
auto FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const -> NetJob*
|
||||
NetJob::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const
|
||||
{
|
||||
auto* netJob = new NetJob(QString("Flame::GetProjects"), APPLICATION->network());
|
||||
|
||||
@ -178,13 +184,13 @@ auto FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const ->
|
||||
|
||||
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw));
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response, netJob] { delete response; netJob->deleteLater(); });
|
||||
QObject::connect(netJob, &NetJob::finished, [response] { delete response; });
|
||||
QObject::connect(netJob, &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
||||
|
||||
return netJob;
|
||||
}
|
||||
|
||||
auto FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const -> NetJob*
|
||||
NetJob::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const
|
||||
{
|
||||
auto* netJob = new NetJob(QString("Flame::GetFiles"), APPLICATION->network());
|
||||
|
||||
@ -201,7 +207,7 @@ auto FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const
|
||||
|
||||
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw));
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response, netJob] { delete response; netJob->deleteLater(); });
|
||||
QObject::connect(netJob, &NetJob::finished, [response] { delete response; });
|
||||
QObject::connect(netJob, &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
||||
|
||||
return netJob;
|
||||
|
@ -1,21 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/helpers/NetworkModAPI.h"
|
||||
#include "modplatform/helpers/NetworkResourceAPI.h"
|
||||
|
||||
class FlameAPI : public NetworkModAPI {
|
||||
class FlameAPI : public NetworkResourceAPI {
|
||||
public:
|
||||
auto matchFingerprints(const QList<uint>& fingerprints, QByteArray* response) -> NetJob::Ptr;
|
||||
auto getModFileChangelog(int modId, int fileId) -> QString;
|
||||
auto getModDescription(int modId) -> QString;
|
||||
|
||||
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
|
||||
|
||||
auto getProjects(QStringList addonIds, QByteArray* response) const -> NetJob* override;
|
||||
auto getFiles(const QStringList& fileIds, QByteArray* response) const -> NetJob*;
|
||||
NetJob::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
|
||||
NetJob::Ptr matchFingerprints(const QList<uint>& fingerprints, QByteArray* response);
|
||||
NetJob::Ptr getFiles(const QStringList& fileIds, QByteArray* response) const;
|
||||
|
||||
private:
|
||||
inline auto getSortFieldInt(QString sortString) const -> int
|
||||
static int getSortFieldInt(QString const& sortString)
|
||||
{
|
||||
return sortString == "Featured" ? 1
|
||||
: sortString == "Popularity" ? 2
|
||||
@ -28,48 +28,16 @@ class FlameAPI : public NetworkModAPI {
|
||||
: 1;
|
||||
}
|
||||
|
||||
private:
|
||||
inline auto getModSearchURL(SearchArgs& args) const -> QString override
|
||||
static int getClassId(ModPlatform::ResourceType type)
|
||||
{
|
||||
auto gameVersionStr = args.versions.size() != 0 ? QString("gameVersion=%1").arg(args.versions.front().toString()) : QString();
|
||||
switch (type) {
|
||||
default:
|
||||
case ModPlatform::ResourceType::MOD:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
return QString(
|
||||
"https://api.curseforge.com/v1/mods/search?"
|
||||
"gameId=432&"
|
||||
"classId=6&"
|
||||
|
||||
"index=%1&"
|
||||
"pageSize=25&"
|
||||
"searchFilter=%2&"
|
||||
"sortField=%3&"
|
||||
"sortOrder=desc&"
|
||||
"modLoaderType=%4&"
|
||||
"%5")
|
||||
.arg(args.offset)
|
||||
.arg(args.search)
|
||||
.arg(getSortFieldInt(args.sorting))
|
||||
.arg(getMappedModLoader(args.loaders))
|
||||
.arg(gameVersionStr);
|
||||
};
|
||||
|
||||
inline auto getModInfoURL(QString& id) const -> QString override
|
||||
{
|
||||
return QString("https://api.curseforge.com/v1/mods/%1").arg(id);
|
||||
};
|
||||
|
||||
inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override
|
||||
{
|
||||
QString gameVersionQuery = args.mcVersions.size() == 1 ? QString("gameVersion=%1&").arg(args.mcVersions.front().toString()) : "";
|
||||
QString modLoaderQuery = QString("modLoaderType=%1&").arg(getMappedModLoader(args.loaders));
|
||||
|
||||
return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&%2%3")
|
||||
.arg(args.addonId)
|
||||
.arg(gameVersionQuery)
|
||||
.arg(modLoaderQuery);
|
||||
};
|
||||
|
||||
public:
|
||||
static auto getMappedModLoader(const ModLoaderTypes loaders) -> int
|
||||
static int getMappedModLoader(ModLoaderTypes loaders)
|
||||
{
|
||||
// https://docs.curseforge.com/?http#tocS_ModLoaderType
|
||||
if (loaders & Forge)
|
||||
@ -81,4 +49,43 @@ class FlameAPI : public NetworkModAPI {
|
||||
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();
|
||||
|
||||
QStringList get_arguments;
|
||||
get_arguments.append(QString("classId=%1").arg(getClassId(args.type)));
|
||||
get_arguments.append(QString("index=%1").arg(args.offset));
|
||||
get_arguments.append("pageSize=25");
|
||||
if (args.search.has_value())
|
||||
get_arguments.append(QString("searchFilter=%1").arg(args.search.value()));
|
||||
if (args.sorting.has_value())
|
||||
get_arguments.append(QString("sortField=%1").arg(getSortFieldInt(args.sorting.value())));
|
||||
get_arguments.append("sortOrder=desc");
|
||||
if (args.loaders.has_value())
|
||||
get_arguments.append(QString("modLoaderType=%1").arg(getMappedModLoader(args.loaders.value())));
|
||||
get_arguments.append(gameVersionStr);
|
||||
|
||||
return "https://api.curseforge.com/v1/mods/search?gameId=432&" + get_arguments.join('&');
|
||||
};
|
||||
|
||||
[[nodiscard]] std::optional<QString> getInfoURL(QString const& id) const override
|
||||
{
|
||||
return QString("https://api.curseforge.com/v1/mods/%1").arg(id);
|
||||
};
|
||||
|
||||
[[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.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())));
|
||||
|
||||
return url + get_parameters.join('&');
|
||||
};
|
||||
};
|
||||
|
@ -7,7 +7,10 @@
|
||||
#include "FileSystem.h"
|
||||
#include "Json.h"
|
||||
|
||||
#include "ModDownloadTask.h"
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "minecraft/mod/ResourceFolderModel.h"
|
||||
|
||||
static FlameAPI api;
|
||||
|
||||
@ -160,7 +163,7 @@ void FlameCheckUpdate::executeTask()
|
||||
for (auto& author : mod->authors())
|
||||
pack.authors.append({ author });
|
||||
pack.description = mod->description();
|
||||
pack.provider = ModPlatform::Provider::FLAME;
|
||||
pack.provider = ModPlatform::ResourceProvider::FLAME;
|
||||
|
||||
auto old_version = mod->version();
|
||||
if (old_version.isEmpty() && mod->status() != ModStatus::NotInstalled) {
|
||||
@ -168,10 +171,10 @@ void FlameCheckUpdate::executeTask()
|
||||
old_version = current_ver.version;
|
||||
}
|
||||
|
||||
auto download_task = new ModDownloadTask(pack, latest_ver, m_mods_folder);
|
||||
auto download_task = new ResourceDownloadTask(pack, latest_ver, m_mods_folder);
|
||||
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::Provider::FLAME, download_task);
|
||||
ModPlatform::ResourceProvider::FLAME, download_task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ class FlameCheckUpdate : public CheckUpdateTask {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlameCheckUpdate(QList<Mod*>& mods, std::list<Version>& mcVersions, ModAPI::ModLoaderTypes loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
FlameCheckUpdate(QList<Mod*>& mods, std::list<Version>& mcVersions, std::optional<ResourceAPI::ModLoaderTypes> loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
|
||||
{}
|
||||
|
||||
|
@ -183,7 +183,7 @@ bool FlameCreationTask::updateInstance()
|
||||
|
||||
QEventLoop loop;
|
||||
|
||||
connect(job, &NetJob::succeeded, this, [this, raw_response, fileIds, old_inst_dir, &old_files, old_minecraft_dir] {
|
||||
connect(job.get(), &NetJob::succeeded, this, [this, raw_response, fileIds, old_inst_dir, &old_files, old_minecraft_dir] {
|
||||
// Parse the API response
|
||||
QJsonParseError parse_error{};
|
||||
auto doc = QJsonDocument::fromJson(*raw_response, &parse_error);
|
||||
@ -225,7 +225,7 @@ bool FlameCreationTask::updateInstance()
|
||||
m_files_to_remove.append(old_minecraft_dir.absoluteFilePath(relative_path));
|
||||
}
|
||||
});
|
||||
connect(job, &NetJob::finished, &loop, &QEventLoop::quit);
|
||||
connect(job.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
m_process_update_file_info_job = job;
|
||||
job->start();
|
||||
|
@ -86,7 +86,7 @@ class FlameCreationTask final : public InstanceCreationTask {
|
||||
Flame::Manifest m_pack;
|
||||
|
||||
// Handle to allow aborting
|
||||
NetJob* m_process_update_file_info_job = nullptr;
|
||||
NetJob::Ptr m_process_update_file_info_job = nullptr;
|
||||
NetJob::Ptr m_files_job = nullptr;
|
||||
|
||||
QString m_managed_id, m_managed_version_id;
|
||||
|
@ -11,7 +11,7 @@ static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
{
|
||||
pack.addonId = Json::requireInteger(obj, "id");
|
||||
pack.provider = ModPlatform::Provider::FLAME;
|
||||
pack.provider = ModPlatform::ResourceProvider::FLAME;
|
||||
pack.name = Json::requireString(obj, "name");
|
||||
pack.slug = Json::requireString(obj, "slug");
|
||||
pack.websiteUrl = Json::ensureString(Json::ensureObject(obj, "links"), "websiteUrl", "");
|
||||
@ -127,7 +127,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
||||
auto hash_list = Json::ensureArray(obj, "hashes");
|
||||
for (auto h : hash_list) {
|
||||
auto hash_entry = Json::ensureObject(h);
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::Provider::FLAME);
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::FLAME);
|
||||
auto hash_algo = enumToString(Json::ensureInteger(hash_entry, "algo", 1, "algorithm"));
|
||||
if (hash_types.contains(hash_algo)) {
|
||||
file.hash = Json::requireString(hash_entry, "value");
|
||||
|
@ -12,12 +12,12 @@ namespace Hashing {
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider)
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider)
|
||||
{
|
||||
switch (provider) {
|
||||
case ModPlatform::Provider::MODRINTH:
|
||||
case ModPlatform::ResourceProvider::MODRINTH:
|
||||
return createModrinthHasher(file_path);
|
||||
case ModPlatform::Provider::FLAME:
|
||||
case ModPlatform::ResourceProvider::FLAME:
|
||||
return createFlameHasher(file_path);
|
||||
default:
|
||||
qCritical() << "[Hashing]"
|
||||
@ -36,12 +36,12 @@ Hasher::Ptr createFlameHasher(QString file_path)
|
||||
return new FlameHasher(file_path);
|
||||
}
|
||||
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider)
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider)
|
||||
{
|
||||
return new BlockedModHasher(file_path, provider);
|
||||
}
|
||||
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type)
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type)
|
||||
{
|
||||
auto hasher = new BlockedModHasher(file_path, provider);
|
||||
hasher->useHashType(type);
|
||||
@ -62,8 +62,8 @@ void ModrinthHasher::executeTask()
|
||||
return;
|
||||
}
|
||||
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH).first();
|
||||
m_hash = ProviderCaps.hash(ModPlatform::Provider::MODRINTH, &file, hash_type);
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
m_hash = ProviderCaps.hash(ModPlatform::ResourceProvider::MODRINTH, &file, hash_type);
|
||||
|
||||
file.close();
|
||||
|
||||
@ -92,7 +92,7 @@ void FlameHasher::executeTask()
|
||||
}
|
||||
|
||||
|
||||
BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::Provider provider)
|
||||
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();
|
||||
|
@ -42,21 +42,21 @@ class ModrinthHasher : public Hasher {
|
||||
|
||||
class BlockedModHasher : public Hasher {
|
||||
public:
|
||||
BlockedModHasher(QString file_path, ModPlatform::Provider provider);
|
||||
BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
|
||||
void executeTask() override;
|
||||
|
||||
QStringList getHashTypes();
|
||||
bool useHashType(QString type);
|
||||
private:
|
||||
ModPlatform::Provider provider;
|
||||
ModPlatform::ResourceProvider provider;
|
||||
QString hash_type;
|
||||
};
|
||||
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider);
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
Hasher::Ptr createFlameHasher(QString file_path);
|
||||
Hasher::Ptr createModrinthHasher(QString file_path);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type);
|
||||
|
||||
} // namespace Hashing
|
||||
|
@ -1,97 +0,0 @@
|
||||
#include "NetworkModAPI.h"
|
||||
|
||||
#include "ui/pages/modplatform/ModModel.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "net/NetJob.h"
|
||||
|
||||
void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const
|
||||
{
|
||||
auto netJob = new NetJob(QString("%1::Search").arg(caller->debugName()), APPLICATION->network());
|
||||
auto searchUrl = getModSearchURL(args);
|
||||
|
||||
auto response = new QByteArray();
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); });
|
||||
QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed);
|
||||
QObject::connect(netJob, &NetJob::aborted, caller, &CallerType::searchRequestAborted);
|
||||
QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
caller->searchRequestFinished(doc);
|
||||
});
|
||||
|
||||
netJob->start();
|
||||
}
|
||||
|
||||
void NetworkModAPI::getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback)
|
||||
{
|
||||
auto response = new QByteArray();
|
||||
auto job = getProject(pack.addonId.toString(), response);
|
||||
|
||||
QObject::connect(job, &NetJob::succeeded, [callback, &pack, response] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
callback(doc, pack);
|
||||
});
|
||||
|
||||
job->start();
|
||||
}
|
||||
|
||||
void NetworkModAPI::getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const
|
||||
{
|
||||
auto netJob = new NetJob(QString("ModVersions(%2)").arg(args.addonId), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(args), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, [response, callback, args] {
|
||||
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;
|
||||
}
|
||||
|
||||
callback(doc, args.addonId);
|
||||
});
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response, netJob] {
|
||||
netJob->deleteLater();
|
||||
delete response;
|
||||
});
|
||||
|
||||
netJob->start();
|
||||
}
|
||||
|
||||
auto NetworkModAPI::getProject(QString addonId, QByteArray* response) const -> NetJob*
|
||||
{
|
||||
auto netJob = new NetJob(QString("%1::GetProject").arg(addonId), APPLICATION->network());
|
||||
auto searchUrl = getModInfoURL(addonId);
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response, netJob] {
|
||||
netJob->deleteLater();
|
||||
delete response;
|
||||
});
|
||||
|
||||
return netJob;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "modplatform/ModAPI.h"
|
||||
|
||||
class NetworkModAPI : public ModAPI {
|
||||
public:
|
||||
void searchMods(CallerType* caller, SearchArgs&& args) const override;
|
||||
void getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback) override;
|
||||
void getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const override;
|
||||
|
||||
auto getProject(QString addonId, QByteArray* response) const -> NetJob* override;
|
||||
|
||||
protected:
|
||||
virtual auto getModSearchURL(SearchArgs& args) const -> QString = 0;
|
||||
virtual auto getModInfoURL(QString& id) const -> QString = 0;
|
||||
virtual auto getVersionsURL(VersionSearchArgs& args) const -> QString = 0;
|
||||
};
|
124
launcher/modplatform/helpers/NetworkResourceAPI.cpp
Normal file
124
launcher/modplatform/helpers/NetworkResourceAPI.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "NetworkResourceAPI.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "net/NetJob.h"
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
NetJob::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&& callbacks) const
|
||||
{
|
||||
auto search_url_optional = getSearchURL(args);
|
||||
if (!search_url_optional.has_value()) {
|
||||
callbacks.on_fail("Failed to create search URL", -1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto search_url = search_url_optional.value();
|
||||
|
||||
auto response = new QByteArray();
|
||||
auto netJob = new NetJob(QString("%1::Search").arg(debugName()), APPLICATION->network());
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(search_url), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, [=]{
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
|
||||
callbacks.on_fail(parse_error.errorString(), -1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.on_succeed(doc);
|
||||
});
|
||||
|
||||
QObject::connect(netJob, &NetJob::failed, [=](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, &NetJob::aborted, [=]{
|
||||
callbacks.on_abort();
|
||||
});
|
||||
|
||||
return netJob;
|
||||
}
|
||||
|
||||
NetJob::Ptr NetworkResourceAPI::getProjectInfo(ProjectInfoArgs&& args, ProjectInfoCallbacks&& callbacks) const
|
||||
{
|
||||
auto response = new QByteArray();
|
||||
auto job = getProject(args.pack.addonId.toString(), response);
|
||||
|
||||
QObject::connect(job.get(), &NetJob::succeeded, [response, callbacks, args] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.on_succeed(doc, args.pack);
|
||||
});
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
NetJob::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, VersionSearchCallbacks&& callbacks) const
|
||||
{
|
||||
auto versions_url_optional = getVersionsURL(args);
|
||||
if (!versions_url_optional.has_value())
|
||||
return nullptr;
|
||||
|
||||
auto versions_url = versions_url_optional.value();
|
||||
|
||||
auto netJob = new NetJob(QString("%1::Versions").arg(args.addonId), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||
|
||||
QObject::connect(netJob, &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.addonId);
|
||||
});
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response] {
|
||||
delete response;
|
||||
});
|
||||
|
||||
return netJob;
|
||||
}
|
||||
|
||||
NetJob::Ptr NetworkResourceAPI::getProject(QString addonId, QByteArray* response) const
|
||||
{
|
||||
auto project_url_optional = getInfoURL(addonId);
|
||||
if (!project_url_optional.has_value())
|
||||
return nullptr;
|
||||
|
||||
auto project_url = project_url_optional.value();
|
||||
|
||||
auto netJob = new NetJob(QString("%1::GetProject").arg(addonId), APPLICATION->network());
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(project_url), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::finished, [response] {
|
||||
delete response;
|
||||
});
|
||||
|
||||
return netJob;
|
||||
}
|
18
launcher/modplatform/helpers/NetworkResourceAPI.h
Normal file
18
launcher/modplatform/helpers/NetworkResourceAPI.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
class NetworkResourceAPI : public ResourceAPI {
|
||||
public:
|
||||
NetJob::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const override;
|
||||
|
||||
NetJob::Ptr getProject(QString addonId, QByteArray* response) const override;
|
||||
|
||||
NetJob::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
|
||||
NetJob::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) 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;
|
||||
};
|
@ -37,21 +37,24 @@ auto ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_format
|
||||
|
||||
auto ModrinthAPI::latestVersion(QString hash,
|
||||
QString hash_format,
|
||||
std::list<Version> mcVersions,
|
||||
ModLoaderTypes loaders,
|
||||
std::optional<std::list<Version>> mcVersions,
|
||||
std::optional<ModLoaderTypes> loaders,
|
||||
QByteArray* response) -> NetJob::Ptr
|
||||
{
|
||||
auto* netJob = new NetJob(QString("Modrinth::GetLatestVersion"), APPLICATION->network());
|
||||
|
||||
QJsonObject body_obj;
|
||||
|
||||
Json::writeStringList(body_obj, "loaders", getModLoaderStrings(loaders));
|
||||
if (loaders.has_value())
|
||||
Json::writeStringList(body_obj, "loaders", getModLoaderStrings(loaders.value()));
|
||||
|
||||
QStringList game_versions;
|
||||
for (auto& ver : mcVersions) {
|
||||
game_versions.append(ver.toString());
|
||||
if (mcVersions.has_value()) {
|
||||
QStringList game_versions;
|
||||
for (auto& ver : mcVersions.value()) {
|
||||
game_versions.append(ver.toString());
|
||||
}
|
||||
Json::writeStringList(body_obj, "game_versions", game_versions);
|
||||
}
|
||||
Json::writeStringList(body_obj, "game_versions", game_versions);
|
||||
|
||||
QJsonDocument body(body_obj);
|
||||
auto body_raw = body.toJson();
|
||||
@ -66,8 +69,8 @@ auto ModrinthAPI::latestVersion(QString hash,
|
||||
|
||||
auto ModrinthAPI::latestVersions(const QStringList& hashes,
|
||||
QString hash_format,
|
||||
std::list<Version> mcVersions,
|
||||
ModLoaderTypes loaders,
|
||||
std::optional<std::list<Version>> mcVersions,
|
||||
std::optional<ModLoaderTypes> loaders,
|
||||
QByteArray* response) -> NetJob::Ptr
|
||||
{
|
||||
auto* netJob = new NetJob(QString("Modrinth::GetLatestVersions"), APPLICATION->network());
|
||||
@ -77,13 +80,16 @@ auto ModrinthAPI::latestVersions(const QStringList& hashes,
|
||||
Json::writeStringList(body_obj, "hashes", hashes);
|
||||
Json::writeString(body_obj, "algorithm", hash_format);
|
||||
|
||||
Json::writeStringList(body_obj, "loaders", getModLoaderStrings(loaders));
|
||||
if (loaders.has_value())
|
||||
Json::writeStringList(body_obj, "loaders", getModLoaderStrings(loaders.value()));
|
||||
|
||||
QStringList game_versions;
|
||||
for (auto& ver : mcVersions) {
|
||||
game_versions.append(ver.toString());
|
||||
if (mcVersions.has_value()) {
|
||||
QStringList game_versions;
|
||||
for (auto& ver : mcVersions.value()) {
|
||||
game_versions.append(ver.toString());
|
||||
}
|
||||
Json::writeStringList(body_obj, "game_versions", game_versions);
|
||||
}
|
||||
Json::writeStringList(body_obj, "game_versions", game_versions);
|
||||
|
||||
QJsonDocument body(body_obj);
|
||||
auto body_raw = body.toJson();
|
||||
@ -95,7 +101,7 @@ auto ModrinthAPI::latestVersions(const QStringList& hashes,
|
||||
return netJob;
|
||||
}
|
||||
|
||||
auto ModrinthAPI::getProjects(QStringList addonIds, QByteArray* response) const -> NetJob*
|
||||
NetJob::Ptr ModrinthAPI::getProjects(QStringList addonIds, QByteArray* response) const
|
||||
{
|
||||
auto netJob = new NetJob(QString("Modrinth::GetProjects"), APPLICATION->network());
|
||||
auto searchUrl = getMultipleModInfoURL(addonIds);
|
||||
|
@ -19,13 +19,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "BuildConfig.h"
|
||||
#include "modplatform/ModAPI.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/helpers/NetworkModAPI.h"
|
||||
#include "modplatform/helpers/NetworkResourceAPI.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
class ModrinthAPI : public NetworkModAPI {
|
||||
class ModrinthAPI : public NetworkResourceAPI {
|
||||
public:
|
||||
auto currentVersion(QString hash,
|
||||
QString hash_format,
|
||||
@ -37,17 +36,17 @@ class ModrinthAPI : public NetworkModAPI {
|
||||
|
||||
auto latestVersion(QString hash,
|
||||
QString hash_format,
|
||||
std::list<Version> mcVersions,
|
||||
ModLoaderTypes loaders,
|
||||
std::optional<std::list<Version>> mcVersions,
|
||||
std::optional<ModLoaderTypes> loaders,
|
||||
QByteArray* response) -> NetJob::Ptr;
|
||||
|
||||
auto latestVersions(const QStringList& hashes,
|
||||
QString hash_format,
|
||||
std::list<Version> mcVersions,
|
||||
ModLoaderTypes loaders,
|
||||
std::optional<std::list<Version>> mcVersions,
|
||||
std::optional<ModLoaderTypes> loaders,
|
||||
QByteArray* response) -> NetJob::Ptr;
|
||||
|
||||
auto getProjects(QStringList addonIds, QByteArray* response) const -> NetJob* override;
|
||||
NetJob::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
|
||||
|
||||
public:
|
||||
inline auto getAuthorURL(const QString& name) const -> QString { return "https://modrinth.com/user/" + name; };
|
||||
@ -55,15 +54,13 @@ class ModrinthAPI : public NetworkModAPI {
|
||||
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
|
||||
{
|
||||
QStringList l;
|
||||
for (auto loader : {Forge, Fabric, Quilt})
|
||||
{
|
||||
if ((types & loader) || types == Unspecified)
|
||||
{
|
||||
l << ModAPI::getModLoaderString(loader);
|
||||
for (auto loader : {Forge, Fabric, Quilt}) {
|
||||
if (types & loader) {
|
||||
l << getModLoaderString(loader);
|
||||
}
|
||||
}
|
||||
if ((types & Quilt) && (~types & Fabric)) // Add Fabric if Quilt is in use, if Fabric isn't already there
|
||||
l << ModAPI::getModLoaderString(Fabric);
|
||||
l << getModLoaderString(Fabric);
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -78,28 +75,54 @@ class ModrinthAPI : public NetworkModAPI {
|
||||
}
|
||||
|
||||
private:
|
||||
inline auto getModSearchURL(SearchArgs& args) const -> QString override
|
||||
[[nodiscard]] static QString resourceTypeParameter(ModPlatform::ResourceType type)
|
||||
{
|
||||
if (!validateModLoaders(args.loaders)) {
|
||||
qWarning() << "Modrinth only have Forge and Fabric-compatible mods!";
|
||||
return "";
|
||||
switch (type) {
|
||||
case ModPlatform::ResourceType::MOD:
|
||||
return "mod";
|
||||
default:
|
||||
qWarning() << "Invalid resource type for Modrinth API!";
|
||||
break;
|
||||
}
|
||||
|
||||
return QString(BuildConfig.MODRINTH_PROD_URL +
|
||||
"/search?"
|
||||
"offset=%1&"
|
||||
"limit=25&"
|
||||
"query=%2&"
|
||||
"index=%3&"
|
||||
"facets=[[%4],%5[\"project_type:mod\"]]")
|
||||
.arg(args.offset)
|
||||
.arg(args.search)
|
||||
.arg(args.sorting)
|
||||
.arg(getModLoaderFilters(args.loaders))
|
||||
.arg(getGameVersionsArray(args.versions));
|
||||
return "";
|
||||
}
|
||||
[[nodiscard]] QString createFacets(SearchArgs const& args) const
|
||||
{
|
||||
QStringList facets_list;
|
||||
|
||||
if (args.loaders.has_value())
|
||||
facets_list.append(QString("[%1]").arg(getModLoaderFilters(args.loaders.value())));
|
||||
if (args.versions.has_value())
|
||||
facets_list.append(QString("[%1]").arg(getGameVersionsArray(args.versions.value())));
|
||||
facets_list.append(QString("[\"project_type:%1\"]").arg(resourceTypeParameter(args.type)));
|
||||
|
||||
return QString("[%1]").arg(facets_list.join(','));
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] inline auto getSearchURL(SearchArgs const& args) const -> std::optional<QString> override
|
||||
{
|
||||
if (args.loaders.has_value()) {
|
||||
if (!validateModLoaders(args.loaders.value())) {
|
||||
qWarning() << "Modrinth only have Forge and Fabric-compatible mods!";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
QStringList get_arguments;
|
||||
get_arguments.append(QString("offset=%1").arg(args.offset));
|
||||
get_arguments.append(QString("limit=25"));
|
||||
if (args.search.has_value())
|
||||
get_arguments.append(QString("query=%1").arg(args.search.value()));
|
||||
if (args.sorting.has_value())
|
||||
get_arguments.append(QString("index=%1").arg(args.sorting.value()));
|
||||
get_arguments.append(QString("facets=%1").arg(createFacets(args)));
|
||||
|
||||
return BuildConfig.MODRINTH_PROD_URL + "/search?" + get_arguments.join('&');
|
||||
};
|
||||
|
||||
inline auto getModInfoURL(QString& id) const -> QString override
|
||||
inline auto getInfoURL(QString const& id) const -> std::optional<QString> override
|
||||
{
|
||||
return BuildConfig.MODRINTH_PROD_URL + "/project/" + id;
|
||||
};
|
||||
@ -109,15 +132,16 @@ class ModrinthAPI : public NetworkModAPI {
|
||||
return BuildConfig.MODRINTH_PROD_URL + QString("/projects?ids=[\"%1\"]").arg(ids.join("\",\""));
|
||||
};
|
||||
|
||||
inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override
|
||||
inline auto getVersionsURL(VersionSearchArgs const& args) const -> std::optional<QString> override
|
||||
{
|
||||
return QString(BuildConfig.MODRINTH_PROD_URL +
|
||||
"/project/%1/version?"
|
||||
"game_versions=[%2]&"
|
||||
"loaders=[\"%3\"]")
|
||||
.arg(args.addonId,
|
||||
getGameVersionsString(args.mcVersions),
|
||||
getModLoaderStrings(args.loaders).join("\",\""));
|
||||
QStringList get_arguments;
|
||||
if (args.mcVersions.has_value())
|
||||
get_arguments.append(QString("game_versions=[%1]").arg(getGameVersionsString(args.mcVersions.value())));
|
||||
if (args.loaders.has_value())
|
||||
get_arguments.append(QString("loaders=[\"%1\"]").arg(getModLoaderStrings(args.loaders.value()).join("\",\"")));
|
||||
|
||||
return QString("%1/project/%2/version%3%4")
|
||||
.arg(BuildConfig.MODRINTH_PROD_URL, args.addonId, get_arguments.isEmpty() ? "" : "?", get_arguments.join('&'));
|
||||
};
|
||||
|
||||
auto getGameVersionsArray(std::list<Version> mcVersions) const -> QString
|
||||
@ -127,12 +151,12 @@ class ModrinthAPI : public NetworkModAPI {
|
||||
s += QString("\"versions:%1\",").arg(ver.toString());
|
||||
}
|
||||
s.remove(s.length() - 1, 1); //remove last comma
|
||||
return s.isEmpty() ? QString() : QString("[%1],").arg(s);
|
||||
return s.isEmpty() ? QString() : s;
|
||||
}
|
||||
|
||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool
|
||||
{
|
||||
return (loaders == Unspecified) || (loaders & (Forge | Fabric | Quilt));
|
||||
return loaders & (Forge | Fabric | Quilt);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
#include "Json.h"
|
||||
|
||||
#include "ModDownloadTask.h"
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "modplatform/helpers/HashUtils.h"
|
||||
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "minecraft/mod/ResourceFolderModel.h"
|
||||
|
||||
static ModrinthAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
@ -34,7 +37,7 @@ void ModrinthCheckUpdate::executeTask()
|
||||
|
||||
// Create all hashes
|
||||
QStringList hashes;
|
||||
auto best_hash_type = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH).first();
|
||||
auto best_hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
|
||||
ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", 10);
|
||||
for (auto* mod : m_mods) {
|
||||
@ -108,11 +111,13 @@ void ModrinthCheckUpdate::executeTask()
|
||||
// Sometimes a version may have multiple files, one with "forge" and one with "fabric",
|
||||
// so we may want to filter it
|
||||
QString loader_filter;
|
||||
static auto flags = { ModAPI::ModLoaderType::Forge, ModAPI::ModLoaderType::Fabric, ModAPI::ModLoaderType::Quilt };
|
||||
for (auto flag : flags) {
|
||||
if (m_loaders.testFlag(flag)) {
|
||||
loader_filter = api.getModLoaderString(flag);
|
||||
break;
|
||||
if (m_loaders.has_value()) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,12 +157,12 @@ void ModrinthCheckUpdate::executeTask()
|
||||
for (auto& author : mod->authors())
|
||||
pack.authors.append({ author });
|
||||
pack.description = mod->description();
|
||||
pack.provider = ModPlatform::Provider::MODRINTH;
|
||||
pack.provider = ModPlatform::ResourceProvider::MODRINTH;
|
||||
|
||||
auto download_task = new ModDownloadTask(pack, project_ver, m_mods_folder);
|
||||
auto download_task = new ResourceDownloadTask(pack, project_ver, m_mods_folder);
|
||||
|
||||
m_updatable.emplace_back(pack.name, hash, mod->version(), project_ver.version_number, project_ver.changelog,
|
||||
ModPlatform::Provider::MODRINTH, download_task);
|
||||
ModPlatform::ResourceProvider::MODRINTH, download_task);
|
||||
}
|
||||
}
|
||||
} catch (Json::JsonException& e) {
|
||||
|
@ -8,7 +8,7 @@ class ModrinthCheckUpdate : public CheckUpdateTask {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModrinthCheckUpdate(QList<Mod*>& mods, std::list<Version>& mcVersions, ModAPI::ModLoaderTypes loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
ModrinthCheckUpdate(QList<Mod*>& mods, std::list<Version>& mcVersions, std::optional<ResourceAPI::ModLoaderTypes> loaders, std::shared_ptr<ModFolderModel> mods_folder)
|
||||
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
|
||||
{}
|
||||
|
||||
|
@ -33,7 +33,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
if (pack.addonId.toString().isEmpty())
|
||||
pack.addonId = Json::requireString(obj, "id");
|
||||
|
||||
pack.provider = ModPlatform::Provider::MODRINTH;
|
||||
pack.provider = ModPlatform::ResourceProvider::MODRINTH;
|
||||
pack.name = Json::requireString(obj, "title");
|
||||
|
||||
pack.slug = Json::ensureString(obj, "slug", "");
|
||||
@ -179,7 +179,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
file.hash = Json::requireString(hash_list, preferred_hash_type);
|
||||
file.hash_type = preferred_hash_type;
|
||||
} else {
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH);
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH);
|
||||
for (auto& hash_type : hash_types) {
|
||||
if (hash_list.contains(hash_type)) {
|
||||
file.hash = Json::requireString(hash_list, hash_type);
|
||||
|
@ -97,7 +97,7 @@ auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, Mo
|
||||
mod.name = mod_pack.name;
|
||||
mod.filename = mod_version.fileName;
|
||||
|
||||
if (mod_pack.provider == ModPlatform::Provider::FLAME) {
|
||||
if (mod_pack.provider == ModPlatform::ResourceProvider::FLAME) {
|
||||
mod.mode = "metadata:curseforge";
|
||||
} else {
|
||||
mod.mode = "url";
|
||||
@ -176,11 +176,11 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
||||
in_stream << QString("\n[update]\n");
|
||||
in_stream << QString("[update.%1]\n").arg(ProviderCaps.name(mod.provider));
|
||||
switch (mod.provider) {
|
||||
case (ModPlatform::Provider::FLAME):
|
||||
case (ModPlatform::ResourceProvider::FLAME):
|
||||
in_stream << QString("file-id = %1\n").arg(mod.file_id.toString());
|
||||
in_stream << QString("project-id = %1\n").arg(mod.project_id.toString());
|
||||
break;
|
||||
case (ModPlatform::Provider::MODRINTH):
|
||||
case (ModPlatform::ResourceProvider::MODRINTH):
|
||||
addToStream("mod-id", mod.mod_id().toString());
|
||||
addToStream("version", mod.version().toString());
|
||||
break;
|
||||
@ -273,7 +273,7 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod
|
||||
}
|
||||
|
||||
{ // [update] info
|
||||
using Provider = ModPlatform::Provider;
|
||||
using Provider = ModPlatform::ResourceProvider;
|
||||
|
||||
auto update_table = table["update"];
|
||||
if (!update_table || !update_table.is_table()) {
|
||||
|
@ -49,7 +49,7 @@ class V1 {
|
||||
QString hash {};
|
||||
|
||||
// [update]
|
||||
ModPlatform::Provider provider {};
|
||||
ModPlatform::ResourceProvider provider {};
|
||||
QVariant file_id {};
|
||||
QVariant project_id {};
|
||||
|
||||
|
Reference in New Issue
Block a user