Resolve issue with multiple loaders during update
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
parent
98d68bafeb
commit
e57c2180da
@ -58,7 +58,6 @@
|
|||||||
#include "ComponentUpdateTask.h"
|
#include "ComponentUpdateTask.h"
|
||||||
#include "PackProfile.h"
|
#include "PackProfile.h"
|
||||||
#include "PackProfile_p.h"
|
#include "PackProfile_p.h"
|
||||||
#include "minecraft/mod/Mod.h"
|
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
|
|
||||||
static const QMap<QString, ModPlatform::ModLoaderType> modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge },
|
static const QMap<QString, ModPlatform::ModLoaderType> modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge },
|
||||||
@ -1022,3 +1021,23 @@ std::optional<ModPlatform::ModLoaderTypes> PackProfile::getSupportedModLoaders()
|
|||||||
loaders |= ModPlatform::Forge;
|
loaders |= ModPlatform::Forge;
|
||||||
return loaders;
|
return loaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<ModPlatform::ModLoaderType> PackProfile::getModLoadersList()
|
||||||
|
{
|
||||||
|
QList<ModPlatform::ModLoaderType> result;
|
||||||
|
for (auto c : d->components) {
|
||||||
|
if (c->isEnabled() && modloaderMapping.contains(c->getID())) {
|
||||||
|
result.append(modloaderMapping[c->getID()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this or add version condition once Quilt drops official Fabric support
|
||||||
|
if (result.contains(ModPlatform::Quilt) && !result.contains(ModPlatform::Fabric)) {
|
||||||
|
result.append(ModPlatform::Fabric);
|
||||||
|
}
|
||||||
|
if (getComponentVersion("net.minecraft") == "1.20.1" && result.contains(ModPlatform::NeoForge) &&
|
||||||
|
!result.contains(ModPlatform::Forge)) {
|
||||||
|
result.append(ModPlatform::Forge);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -146,6 +146,7 @@ class PackProfile : public QAbstractListModel {
|
|||||||
std::optional<ModPlatform::ModLoaderTypes> getModLoaders();
|
std::optional<ModPlatform::ModLoaderTypes> getModLoaders();
|
||||||
// this returns aditional loaders(Quilt supports fabric and NeoForge supports Forge)
|
// this returns aditional loaders(Quilt supports fabric and NeoForge supports Forge)
|
||||||
std::optional<ModPlatform::ModLoaderTypes> getSupportedModLoaders();
|
std::optional<ModPlatform::ModLoaderTypes> getSupportedModLoaders();
|
||||||
|
QList<ModPlatform::ModLoaderType> getModLoadersList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void scheduleSave();
|
void scheduleSave();
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "minecraft/mod/Mod.h"
|
#include "minecraft/mod/Mod.h"
|
||||||
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
|
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/ResourceAPI.h"
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class ResourceDownloadTask;
|
class ResourceDownloadTask;
|
||||||
@ -16,8 +15,14 @@ class CheckUpdateTask : public Task {
|
|||||||
CheckUpdateTask(QList<Mod*>& mods,
|
CheckUpdateTask(QList<Mod*>& mods,
|
||||||
std::list<Version>& mcVersions,
|
std::list<Version>& mcVersions,
|
||||||
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
||||||
|
QList<ModPlatform::ModLoaderType> loadersList,
|
||||||
std::shared_ptr<ModFolderModel> mods_folder)
|
std::shared_ptr<ModFolderModel> mods_folder)
|
||||||
: Task(nullptr), m_mods(mods), m_game_versions(mcVersions), m_loaders(loaders), m_mods_folder(mods_folder){};
|
: Task(nullptr)
|
||||||
|
, m_mods(mods)
|
||||||
|
, m_game_versions(mcVersions)
|
||||||
|
, m_loaders(loaders)
|
||||||
|
, m_loaders_list(loadersList)
|
||||||
|
, m_mods_folder(mods_folder){};
|
||||||
|
|
||||||
struct UpdatableMod {
|
struct UpdatableMod {
|
||||||
QString name;
|
QString name;
|
||||||
@ -68,6 +73,7 @@ class CheckUpdateTask : public Task {
|
|||||||
QList<Mod*>& m_mods;
|
QList<Mod*>& m_mods;
|
||||||
std::list<Version>& m_game_versions;
|
std::list<Version>& m_game_versions;
|
||||||
std::optional<ModPlatform::ModLoaderTypes> m_loaders;
|
std::optional<ModPlatform::ModLoaderTypes> m_loaders;
|
||||||
|
QList<ModPlatform::ModLoaderType> m_loaders_list;
|
||||||
std::shared_ptr<ModFolderModel> m_mods_folder;
|
std::shared_ptr<ModFolderModel> m_mods_folder;
|
||||||
|
|
||||||
std::vector<UpdatableMod> m_updatable;
|
std::vector<UpdatableMod> m_updatable;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "FlameAPI.h"
|
#include "FlameAPI.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include "FlameModIndex.h"
|
#include "FlameModIndex.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
@ -12,7 +13,6 @@
|
|||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
#include "net/ApiUpload.h"
|
#include "net/ApiUpload.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "net/Upload.h"
|
|
||||||
|
|
||||||
Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response)
|
Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
@ -34,7 +34,7 @@ Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shar
|
|||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
|
QString FlameAPI::getModFileChangelog(int modId, int fileId)
|
||||||
{
|
{
|
||||||
QEventLoop lock;
|
QEventLoop lock;
|
||||||
QString changelog;
|
QString changelog;
|
||||||
@ -69,7 +69,7 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
|
|||||||
return changelog;
|
return changelog;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FlameAPI::getModDescription(int modId) -> QString
|
QString FlameAPI::getModDescription(int modId)
|
||||||
{
|
{
|
||||||
QEventLoop lock;
|
QEventLoop lock;
|
||||||
QString description;
|
QString description;
|
||||||
@ -102,7 +102,7 @@ auto FlameAPI::getModDescription(int modId) -> QString
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion
|
QList<ModPlatform::IndexedVersion> FlameAPI::getLatestVersions(VersionSearchArgs&& args)
|
||||||
{
|
{
|
||||||
auto versions_url_optional = getVersionsURL(args);
|
auto versions_url_optional = getVersionsURL(args);
|
||||||
if (!versions_url_optional.has_value())
|
if (!versions_url_optional.has_value())
|
||||||
@ -114,7 +114,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
|
|
||||||
auto netJob = makeShared<NetJob>(QString("Flame::GetLatestVersion(%1)").arg(args.pack.name), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Flame::GetLatestVersion(%1)").arg(args.pack.name), APPLICATION->network());
|
||||||
auto response = std::make_shared<QByteArray>();
|
auto response = std::make_shared<QByteArray>();
|
||||||
ModPlatform::IndexedVersion ver;
|
QList<ModPlatform::IndexedVersion> ver;
|
||||||
|
|
||||||
netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response));
|
netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response));
|
||||||
|
|
||||||
@ -134,9 +134,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
|
|
||||||
for (auto file : arr) {
|
for (auto file : arr) {
|
||||||
auto file_obj = Json::requireObject(file);
|
auto file_obj = Json::requireObject(file);
|
||||||
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
|
ver.append(FlameMod::loadIndexedPackVersion(file_obj));
|
||||||
if (file_tmp.date > ver.date && (!args.loaders.has_value() || !file_tmp.loaders || args.loaders.value() & file_tmp.loaders))
|
|
||||||
ver = file_tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Json::JsonException& e) {
|
} catch (Json::JsonException& e) {
|
||||||
@ -146,7 +144,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [&loop] { loop.quit(); });
|
QObject::connect(netJob.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
||||||
|
|
||||||
netJob->start();
|
netJob->start();
|
||||||
|
|
||||||
@ -260,4 +258,27 @@ QList<ModPlatform::Category> FlameAPI::loadModCategories(std::shared_ptr<QByteAr
|
|||||||
qDebug() << doc;
|
qDebug() << doc;
|
||||||
}
|
}
|
||||||
return categories;
|
return categories;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::optional<ModPlatform::IndexedVersion> FlameAPI::getLatestVersion(QList<ModPlatform::IndexedVersion> versions,
|
||||||
|
QList<ModPlatform::ModLoaderType> instanceLoaders,
|
||||||
|
ModPlatform::ModLoaderTypes modLoaders)
|
||||||
|
{
|
||||||
|
// edge case: mod has installed for forge but the instance is fabric => fabric version will be prioritizated on update
|
||||||
|
auto bestVersion = [&versions](ModPlatform::ModLoaderTypes loader) {
|
||||||
|
std::optional<ModPlatform::IndexedVersion> ver;
|
||||||
|
for (auto file_tmp : versions) {
|
||||||
|
if (file_tmp.loaders & loader && (!ver.has_value() || file_tmp.date > ver->date)) {
|
||||||
|
ver = file_tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ver;
|
||||||
|
};
|
||||||
|
for (auto l : instanceLoaders) {
|
||||||
|
auto ver = bestVersion(l);
|
||||||
|
if (ver.has_value()) {
|
||||||
|
return ver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestVersion(modLoaders);
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/ResourceAPI.h"
|
#include "modplatform/ResourceAPI.h"
|
||||||
@ -13,10 +12,13 @@
|
|||||||
|
|
||||||
class FlameAPI : public NetworkResourceAPI {
|
class FlameAPI : public NetworkResourceAPI {
|
||||||
public:
|
public:
|
||||||
auto getModFileChangelog(int modId, int fileId) -> QString;
|
QString getModFileChangelog(int modId, int fileId);
|
||||||
auto getModDescription(int modId) -> QString;
|
QString getModDescription(int modId);
|
||||||
|
|
||||||
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
|
QList<ModPlatform::IndexedVersion> getLatestVersions(VersionSearchArgs&& args);
|
||||||
|
std::optional<ModPlatform::IndexedVersion> getLatestVersion(QList<ModPlatform::IndexedVersion> versions,
|
||||||
|
QList<ModPlatform::ModLoaderType> instanceLoaders,
|
||||||
|
ModPlatform::ModLoaderTypes fallback);
|
||||||
|
|
||||||
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
|
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 matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response);
|
||||||
@ -26,9 +28,9 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
static Task::Ptr getModCategories(std::shared_ptr<QByteArray> response);
|
static Task::Ptr getModCategories(std::shared_ptr<QByteArray> response);
|
||||||
static QList<ModPlatform::Category> loadModCategories(std::shared_ptr<QByteArray> response);
|
static QList<ModPlatform::Category> loadModCategories(std::shared_ptr<QByteArray> response);
|
||||||
|
|
||||||
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
[[nodiscard]] QList<ResourceAPI::SortingMethod> getSortingMethods() const override;
|
||||||
|
|
||||||
static inline auto validateModLoaders(ModPlatform::ModLoaderTypes loaders) -> bool
|
static inline bool validateModLoaders(ModPlatform::ModLoaderTypes loaders)
|
||||||
{
|
{
|
||||||
return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
|
return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
|
||||||
}
|
}
|
||||||
@ -67,7 +69,7 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto getModLoaderStrings(const ModPlatform::ModLoaderTypes types) -> const QStringList
|
static const QStringList getModLoaderStrings(const ModPlatform::ModLoaderTypes types)
|
||||||
{
|
{
|
||||||
QStringList l;
|
QStringList l;
|
||||||
for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt }) {
|
for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt }) {
|
||||||
@ -78,10 +80,7 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto getModLoaderFilters(ModPlatform::ModLoaderTypes types) -> const QString
|
static const QString getModLoaderFilters(ModPlatform::ModLoaderTypes types) { return "[" + getModLoaderStrings(types).join(',') + "]"; }
|
||||||
{
|
|
||||||
return "[" + getModLoaderStrings(types).join(',') + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
|
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
|
||||||
|
@ -132,25 +132,26 @@ void FlameCheckUpdate::executeTask()
|
|||||||
setStatus(tr("Getting API response from CurseForge for '%1'...").arg(mod->name()));
|
setStatus(tr("Getting API response from CurseForge for '%1'...").arg(mod->name()));
|
||||||
setProgress(i++, m_mods.size());
|
setProgress(i++, m_mods.size());
|
||||||
|
|
||||||
auto latest_ver = api.getLatestVersion({ { mod->metadata()->project_id.toString() }, m_game_versions, m_loaders });
|
auto latest_vers = api.getLatestVersions({ { mod->metadata()->project_id.toString() }, m_game_versions, m_loaders });
|
||||||
|
|
||||||
// Check if we were aborted while getting the latest version
|
// Check if we were aborted while getting the latest version
|
||||||
if (m_was_aborted) {
|
if (m_was_aborted) {
|
||||||
aborted();
|
aborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto latest_ver = api.getLatestVersion(latest_vers, m_loaders_list, mod->loaders());
|
||||||
|
|
||||||
setStatus(tr("Parsing the API response from CurseForge for '%1'...").arg(mod->name()));
|
setStatus(tr("Parsing the API response from CurseForge for '%1'...").arg(mod->name()));
|
||||||
|
|
||||||
if (!latest_ver.addonId.isValid()) {
|
if (!latest_ver.has_value() || !latest_ver->addonId.isValid()) {
|
||||||
emit checkFailed(mod, tr("No valid version found for this mod. It's probably unavailable for the current game "
|
emit checkFailed(mod, tr("No valid version found for this mod. It's probably unavailable for the current game "
|
||||||
"version / mod loader."));
|
"version / mod loader."));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latest_ver.downloadUrl.isEmpty() && latest_ver.fileId != mod->metadata()->file_id) {
|
if (latest_ver->downloadUrl.isEmpty() && latest_ver->fileId != mod->metadata()->file_id) {
|
||||||
auto pack = getProjectInfo(latest_ver);
|
auto pack = getProjectInfo(latest_ver.value());
|
||||||
auto recover_url = QString("%1/download/%2").arg(pack.websiteUrl, latest_ver.fileId.toString());
|
auto recover_url = QString("%1/download/%2").arg(pack.websiteUrl, latest_ver->fileId.toString());
|
||||||
emit checkFailed(mod, tr("Mod has a new update available, but is not downloadable using CurseForge."), recover_url);
|
emit checkFailed(mod, tr("Mod has a new update available, but is not downloadable using CurseForge."), recover_url);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -166,19 +167,19 @@ void FlameCheckUpdate::executeTask()
|
|||||||
pack->authors.append({ author });
|
pack->authors.append({ author });
|
||||||
pack->description = mod->description();
|
pack->description = mod->description();
|
||||||
pack->provider = ModPlatform::ResourceProvider::FLAME;
|
pack->provider = ModPlatform::ResourceProvider::FLAME;
|
||||||
if (!latest_ver.hash.isEmpty() && (mod->metadata()->hash != latest_ver.hash || mod->status() == ModStatus::NotInstalled)) {
|
if (!latest_ver->hash.isEmpty() && (mod->metadata()->hash != latest_ver->hash || mod->status() == ModStatus::NotInstalled)) {
|
||||||
auto old_version = mod->version();
|
auto old_version = mod->version();
|
||||||
if (old_version.isEmpty() && mod->status() != ModStatus::NotInstalled) {
|
if (old_version.isEmpty() && mod->status() != ModStatus::NotInstalled) {
|
||||||
auto current_ver = getFileInfo(latest_ver.addonId.toInt(), mod->metadata()->file_id.toInt());
|
auto current_ver = getFileInfo(latest_ver->addonId.toInt(), mod->metadata()->file_id.toInt());
|
||||||
old_version = current_ver.version;
|
old_version = current_ver.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver, m_mods_folder);
|
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver.value(), m_mods_folder);
|
||||||
m_updatable.emplace_back(pack->name, mod->metadata()->hash, old_version, latest_ver.version, latest_ver.version_type,
|
m_updatable.emplace_back(pack->name, mod->metadata()->hash, old_version, latest_ver->version, latest_ver->version_type,
|
||||||
api.getModFileChangelog(latest_ver.addonId.toInt(), latest_ver.fileId.toInt()),
|
api.getModFileChangelog(latest_ver->addonId.toInt(), latest_ver->fileId.toInt()),
|
||||||
ModPlatform::ResourceProvider::FLAME, download_task);
|
ModPlatform::ResourceProvider::FLAME, download_task);
|
||||||
}
|
}
|
||||||
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, latest_ver));
|
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, latest_ver.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "modplatform/CheckUpdateTask.h"
|
#include "modplatform/CheckUpdateTask.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
@ -11,8 +10,9 @@ class FlameCheckUpdate : public CheckUpdateTask {
|
|||||||
FlameCheckUpdate(QList<Mod*>& mods,
|
FlameCheckUpdate(QList<Mod*>& mods,
|
||||||
std::list<Version>& mcVersions,
|
std::list<Version>& mcVersions,
|
||||||
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
||||||
|
QList<ModPlatform::ModLoaderType> loadersList,
|
||||||
std::shared_ptr<ModFolderModel> mods_folder)
|
std::shared_ptr<ModFolderModel> mods_folder)
|
||||||
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
|
: CheckUpdateTask(mods, mcVersions, loaders, loadersList, mods_folder)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -1,23 +1,32 @@
|
|||||||
#include "ModrinthCheckUpdate.h"
|
#include "ModrinthCheckUpdate.h"
|
||||||
|
#include "Application.h"
|
||||||
#include "ModrinthAPI.h"
|
#include "ModrinthAPI.h"
|
||||||
#include "ModrinthPackIndex.h"
|
#include "ModrinthPackIndex.h"
|
||||||
|
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
|
#include "QObjectPtr.h"
|
||||||
#include "ResourceDownloadTask.h"
|
#include "ResourceDownloadTask.h"
|
||||||
|
|
||||||
#include "modplatform/helpers/HashUtils.h"
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
|
|
||||||
#include "tasks/ConcurrentTask.h"
|
#include "tasks/ConcurrentTask.h"
|
||||||
|
|
||||||
#include "minecraft/mod/ModFolderModel.h"
|
|
||||||
|
|
||||||
static ModrinthAPI api;
|
static ModrinthAPI api;
|
||||||
|
|
||||||
|
ModrinthCheckUpdate::ModrinthCheckUpdate(QList<Mod*>& mods,
|
||||||
|
std::list<Version>& mcVersions,
|
||||||
|
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
||||||
|
QList<ModPlatform::ModLoaderType> loadersList,
|
||||||
|
std::shared_ptr<ModFolderModel> mods_folder)
|
||||||
|
: CheckUpdateTask(mods, mcVersions, loaders, loadersList, mods_folder)
|
||||||
|
, m_hash_type(ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first())
|
||||||
|
{}
|
||||||
|
|
||||||
bool ModrinthCheckUpdate::abort()
|
bool ModrinthCheckUpdate::abort()
|
||||||
{
|
{
|
||||||
if (m_net_job)
|
if (m_job)
|
||||||
return m_net_job->abort();
|
return m_job->abort();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,15 +38,10 @@ bool ModrinthCheckUpdate::abort()
|
|||||||
void ModrinthCheckUpdate::executeTask()
|
void ModrinthCheckUpdate::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Preparing mods for Modrinth..."));
|
setStatus(tr("Preparing mods for Modrinth..."));
|
||||||
setProgress(0, 3);
|
setProgress(0, 9);
|
||||||
|
|
||||||
QHash<QString, Mod*> mappings;
|
auto hashing_task =
|
||||||
|
makeShared<ConcurrentTask>(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
||||||
// Create all hashes
|
|
||||||
QStringList hashes;
|
|
||||||
auto best_hash_type = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
|
||||||
|
|
||||||
ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
|
||||||
for (auto* mod : m_mods) {
|
for (auto* mod : m_mods) {
|
||||||
if (!mod->enabled()) {
|
if (!mod->enabled()) {
|
||||||
emit checkFailed(mod, tr("Disabled mods won't be updated, to prevent mod duplication issues!"));
|
emit checkFailed(mod, tr("Disabled mods won't be updated, to prevent mod duplication issues!"));
|
||||||
@ -49,132 +53,176 @@ void ModrinthCheckUpdate::executeTask()
|
|||||||
// Sadly the API can only handle one hash type per call, se we
|
// Sadly the API can only handle one hash type per call, se we
|
||||||
// need to generate a new hash if the current one is innadequate
|
// need to generate a new hash if the current one is innadequate
|
||||||
// (though it will rarely happen, if at all)
|
// (though it will rarely happen, if at all)
|
||||||
if (mod->metadata()->hash_format != best_hash_type) {
|
if (mod->metadata()->hash_format != m_hash_type) {
|
||||||
auto hash_task = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::MODRINTH);
|
auto hash_task = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::MODRINTH);
|
||||||
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [&hashes, &mappings, mod](QString hash) {
|
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mappings.insert(hash, mod); });
|
||||||
hashes.append(hash);
|
|
||||||
mappings.insert(hash, mod);
|
|
||||||
});
|
|
||||||
connect(hash_task.get(), &Task::failed, [this] { failed("Failed to generate hash"); });
|
connect(hash_task.get(), &Task::failed, [this] { failed("Failed to generate hash"); });
|
||||||
hashing_task.addTask(hash_task);
|
hashing_task->addTask(hash_task);
|
||||||
} else {
|
} else {
|
||||||
hashes.append(hash);
|
m_mappings.insert(hash, mod);
|
||||||
mappings.insert(hash, mod);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QEventLoop loop;
|
connect(hashing_task.get(), &Task::finished, this, &ModrinthCheckUpdate::checkNextLoader);
|
||||||
connect(&hashing_task, &Task::finished, [&loop] { loop.quit(); });
|
m_job = hashing_task;
|
||||||
hashing_task.start();
|
hashing_task->start();
|
||||||
loop.exec();
|
}
|
||||||
|
|
||||||
auto response = std::make_shared<QByteArray>();
|
void ModrinthCheckUpdate::checkVersionsResponse(std::shared_ptr<QByteArray> response,
|
||||||
auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response);
|
ModPlatform::ModLoaderTypes loader,
|
||||||
|
bool forceModLoaderCheck)
|
||||||
|
{
|
||||||
|
QJsonParseError parse_error{};
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
|
qWarning() << "Error while parsing JSON response from ModrinthCheckUpdate at " << parse_error.offset
|
||||||
|
<< " reason: " << parse_error.errorString();
|
||||||
|
qWarning() << *response;
|
||||||
|
|
||||||
connect(job.get(), &Task::succeeded, this, [this, response, mappings, best_hash_type, job] {
|
emitFailed(parse_error.errorString());
|
||||||
QJsonParseError parse_error{};
|
return;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
}
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
|
||||||
qWarning() << "Error while parsing JSON response from ModrinthCheckUpdate at " << parse_error.offset
|
|
||||||
<< " reason: " << parse_error.errorString();
|
|
||||||
qWarning() << *response;
|
|
||||||
|
|
||||||
emitFailed(parse_error.errorString());
|
setStatus(tr("Parsing the API response from Modrinth..."));
|
||||||
return;
|
setProgress(m_next_loader_idx * 2, 9);
|
||||||
}
|
|
||||||
|
|
||||||
setStatus(tr("Parsing the API response from Modrinth..."));
|
try {
|
||||||
setProgress(2, 3);
|
for (auto hash : m_mappings.keys()) {
|
||||||
|
if (forceModLoaderCheck && !m_mappings[hash]->loaders().testAnyFlags(loader)) {
|
||||||
try {
|
continue;
|
||||||
for (auto hash : mappings.keys()) {
|
|
||||||
auto project_obj = doc[hash].toObject();
|
|
||||||
|
|
||||||
// If the returned project is empty, but we have Modrinth metadata,
|
|
||||||
// it means this specific version is not available
|
|
||||||
if (project_obj.isEmpty()) {
|
|
||||||
qDebug() << "Mod " << mappings.find(hash).value()->name() << " got an empty response.";
|
|
||||||
qDebug() << "Hash: " << hash;
|
|
||||||
|
|
||||||
emit checkFailed(
|
|
||||||
mappings.find(hash).value(),
|
|
||||||
tr("No valid version found for this mod. It's probably unavailable for the current game version / mod loader."));
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sometimes a version may have multiple files, one with "forge" and one with "fabric",
|
|
||||||
// so we may want to filter it
|
|
||||||
QString loader_filter;
|
|
||||||
if (m_loaders.has_value()) {
|
|
||||||
static auto flags = { ModPlatform::ModLoaderType::NeoForge, ModPlatform::ModLoaderType::Forge,
|
|
||||||
ModPlatform::ModLoaderType::Fabric, ModPlatform::ModLoaderType::Quilt };
|
|
||||||
for (auto flag : flags) {
|
|
||||||
if (m_loaders.value().testFlag(flag)) {
|
|
||||||
loader_filter = ModPlatform::getModLoaderAsString(flag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 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 .-.
|
|
||||||
|
|
||||||
auto project_ver = Modrinth::loadIndexedPackVersion(project_obj, best_hash_type, loader_filter);
|
|
||||||
if (project_ver.downloadUrl.isEmpty()) {
|
|
||||||
qCritical() << "Modrinth mod without download url!";
|
|
||||||
qCritical() << project_ver.fileName;
|
|
||||||
|
|
||||||
emit checkFailed(mappings.find(hash).value(), tr("Mod has an empty download URL"));
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mod_iter = mappings.find(hash);
|
|
||||||
if (mod_iter == mappings.end()) {
|
|
||||||
qCritical() << "Failed to remap mod from Modrinth!";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto mod = *mod_iter;
|
|
||||||
|
|
||||||
auto key = project_ver.hash;
|
|
||||||
|
|
||||||
// Fake pack with the necessary info to pass to the download task :)
|
|
||||||
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;
|
|
||||||
if ((key != hash && project_ver.is_preferred) || (mod->status() == ModStatus::NotInstalled)) {
|
|
||||||
if (mod->version() == project_ver.version_number)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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.version_type,
|
|
||||||
project_ver.changelog, ModPlatform::ResourceProvider::MODRINTH, download_task);
|
|
||||||
}
|
|
||||||
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, project_ver));
|
|
||||||
}
|
}
|
||||||
} catch (Json::JsonException& e) {
|
auto project_obj = doc[hash].toObject();
|
||||||
emitFailed(e.cause() + " : " + e.what());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emitSucceeded();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(job.get(), &Task::failed, this, &ModrinthCheckUpdate::emitFailed);
|
// If the returned project is empty, but we have Modrinth metadata,
|
||||||
|
// it means this specific version is not available
|
||||||
|
if (project_obj.isEmpty()) {
|
||||||
|
qDebug() << "Mod " << m_mappings.find(hash).value()->name() << " got an empty response."
|
||||||
|
<< "Hash: " << hash;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = { ModPlatform::ModLoaderType::NeoForge, ModPlatform::ModLoaderType::Forge,
|
||||||
|
ModPlatform::ModLoaderType::Quilt, ModPlatform::ModLoaderType::Fabric };
|
||||||
|
for (auto flag : flags) {
|
||||||
|
if (loader.testFlag(flag)) {
|
||||||
|
loader_filter = ModPlatform::getModLoaderAsString(flag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 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 .-.
|
||||||
|
|
||||||
|
auto project_ver = Modrinth::loadIndexedPackVersion(project_obj, m_hash_type, loader_filter);
|
||||||
|
if (project_ver.downloadUrl.isEmpty()) {
|
||||||
|
qCritical() << "Modrinth mod without download url!" << project_ver.fileName;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mod_iter = m_mappings.find(hash);
|
||||||
|
if (mod_iter == m_mappings.end()) {
|
||||||
|
qCritical() << "Failed to remap mod from Modrinth!";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto mod = *mod_iter;
|
||||||
|
m_mappings.remove(hash);
|
||||||
|
|
||||||
|
auto key = project_ver.hash;
|
||||||
|
|
||||||
|
// Fake pack with the necessary info to pass to the download task :)
|
||||||
|
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;
|
||||||
|
if ((key != hash && project_ver.is_preferred) || (mod->status() == ModStatus::NotInstalled)) {
|
||||||
|
if (mod->version() == project_ver.version_number)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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.version_type,
|
||||||
|
project_ver.changelog, ModPlatform::ResourceProvider::MODRINTH, download_task);
|
||||||
|
}
|
||||||
|
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, project_ver));
|
||||||
|
}
|
||||||
|
} catch (Json::JsonException& e) {
|
||||||
|
emitFailed(e.cause() + " : " + e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkNextLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModrinthCheckUpdate::getUpdateModsForLoader(ModPlatform::ModLoaderTypes loader, bool forceModLoaderCheck)
|
||||||
|
{
|
||||||
|
auto response = std::make_shared<QByteArray>();
|
||||||
|
QStringList hashes;
|
||||||
|
if (forceModLoaderCheck) {
|
||||||
|
for (auto hash : m_mappings.keys()) {
|
||||||
|
if (m_mappings[hash]->loaders().testAnyFlags(loader)) {
|
||||||
|
hashes.append(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hashes = m_mappings.keys();
|
||||||
|
}
|
||||||
|
auto job = api.latestVersions(hashes, m_hash_type, m_game_versions, loader, response);
|
||||||
|
|
||||||
|
connect(job.get(), &Task::succeeded, this,
|
||||||
|
[this, response, loader, forceModLoaderCheck] { checkVersionsResponse(response, loader, forceModLoaderCheck); });
|
||||||
|
|
||||||
|
connect(job.get(), &Task::failed, this, &ModrinthCheckUpdate::checkNextLoader);
|
||||||
|
|
||||||
setStatus(tr("Waiting for the API response from Modrinth..."));
|
setStatus(tr("Waiting for the API response from Modrinth..."));
|
||||||
setProgress(1, 3);
|
setProgress(m_next_loader_idx * 2 - 1, 9);
|
||||||
|
|
||||||
m_net_job = qSharedPointerObjectCast<NetJob, Task>(job);
|
m_job = job;
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModrinthCheckUpdate::checkNextLoader()
|
||||||
|
{
|
||||||
|
if (m_mappings.isEmpty()) {
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_next_loader_idx < m_loaders_list.size()) {
|
||||||
|
getUpdateModsForLoader(m_loaders_list.at(m_next_loader_idx));
|
||||||
|
m_next_loader_idx++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static auto flags = { ModPlatform::ModLoaderType::NeoForge, ModPlatform::ModLoaderType::Forge, ModPlatform::ModLoaderType::Quilt,
|
||||||
|
ModPlatform::ModLoaderType::Fabric };
|
||||||
|
for (auto flag : flags) {
|
||||||
|
if (!m_loaders_list.contains(flag)) {
|
||||||
|
m_loaders_list.append(flag);
|
||||||
|
m_next_loader_idx++;
|
||||||
|
setProgress(m_next_loader_idx * 2 - 1, 9);
|
||||||
|
for (auto m : m_mappings) {
|
||||||
|
if (m->loaders().testAnyFlag(flag)) {
|
||||||
|
getUpdateModsForLoader(flag, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setProgress(m_next_loader_idx * 2, 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto m : m_mappings) {
|
||||||
|
emit checkFailed(m,
|
||||||
|
tr("No valid version found for this mod. It's probably unavailable for the current game version / mod loader."));
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "modplatform/CheckUpdateTask.h"
|
#include "modplatform/CheckUpdateTask.h"
|
||||||
#include "net/NetJob.h"
|
|
||||||
|
|
||||||
class ModrinthCheckUpdate : public CheckUpdateTask {
|
class ModrinthCheckUpdate : public CheckUpdateTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -11,16 +9,21 @@ class ModrinthCheckUpdate : public CheckUpdateTask {
|
|||||||
ModrinthCheckUpdate(QList<Mod*>& mods,
|
ModrinthCheckUpdate(QList<Mod*>& mods,
|
||||||
std::list<Version>& mcVersions,
|
std::list<Version>& mcVersions,
|
||||||
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
std::optional<ModPlatform::ModLoaderTypes> loaders,
|
||||||
std::shared_ptr<ModFolderModel> mods_folder)
|
QList<ModPlatform::ModLoaderType> loadersList,
|
||||||
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
|
std::shared_ptr<ModFolderModel> mods_folder);
|
||||||
{}
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
void getUpdateModsForLoader(ModPlatform::ModLoaderTypes loader, bool forceModLoaderCheck = false);
|
||||||
|
void checkVersionsResponse(std::shared_ptr<QByteArray> response, ModPlatform::ModLoaderTypes loader, bool forceModLoaderCheck = false);
|
||||||
|
void checkNextLoader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetJob::Ptr m_net_job = nullptr;
|
Task::Ptr m_job = nullptr;
|
||||||
|
QHash<QString, Mod*> m_mappings;
|
||||||
|
QString m_hash_type;
|
||||||
|
int m_next_loader_idx = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "ModUpdateDialog.h"
|
#include "ModUpdateDialog.h"
|
||||||
|
#include "Application.h"
|
||||||
#include "ChooseProviderDialog.h"
|
#include "ChooseProviderDialog.h"
|
||||||
#include "CustomMessageBox.h"
|
#include "CustomMessageBox.h"
|
||||||
#include "ProgressDialog.h"
|
#include "ProgressDialog.h"
|
||||||
@ -32,7 +33,12 @@ static std::list<Version> mcVersions(BaseInstance* inst)
|
|||||||
|
|
||||||
static std::optional<ModPlatform::ModLoaderTypes> mcLoaders(BaseInstance* inst)
|
static std::optional<ModPlatform::ModLoaderTypes> mcLoaders(BaseInstance* inst)
|
||||||
{
|
{
|
||||||
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders() };
|
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QList<ModPlatform::ModLoaderType> mcLoadersList(BaseInstance* inst)
|
||||||
|
{
|
||||||
|
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoadersList();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModUpdateDialog::ModUpdateDialog(QWidget* parent,
|
ModUpdateDialog::ModUpdateDialog(QWidget* parent,
|
||||||
@ -87,11 +93,12 @@ void ModUpdateDialog::checkCandidates()
|
|||||||
|
|
||||||
auto versions = mcVersions(m_instance);
|
auto versions = mcVersions(m_instance);
|
||||||
auto loaders = mcLoaders(m_instance);
|
auto loaders = mcLoaders(m_instance);
|
||||||
|
auto loadersList = mcLoadersList(m_instance);
|
||||||
|
|
||||||
SequentialTask check_task(m_parent, tr("Checking for updates"));
|
SequentialTask check_task(m_parent, tr("Checking for updates"));
|
||||||
|
|
||||||
if (!m_modrinth_to_update.empty()) {
|
if (!m_modrinth_to_update.empty()) {
|
||||||
m_modrinth_check_task.reset(new ModrinthCheckUpdate(m_modrinth_to_update, versions, loaders, m_mod_model));
|
m_modrinth_check_task.reset(new ModrinthCheckUpdate(m_modrinth_to_update, versions, loaders, loadersList, m_mod_model));
|
||||||
connect(m_modrinth_check_task.get(), &CheckUpdateTask::checkFailed, this, [this](Mod* mod, QString reason, QUrl recover_url) {
|
connect(m_modrinth_check_task.get(), &CheckUpdateTask::checkFailed, this, [this](Mod* mod, QString reason, QUrl recover_url) {
|
||||||
m_failed_check_update.append({ mod, reason, recover_url });
|
m_failed_check_update.append({ mod, reason, recover_url });
|
||||||
});
|
});
|
||||||
@ -99,7 +106,7 @@ void ModUpdateDialog::checkCandidates()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_flame_to_update.empty()) {
|
if (!m_flame_to_update.empty()) {
|
||||||
m_flame_check_task.reset(new FlameCheckUpdate(m_flame_to_update, versions, loaders, m_mod_model));
|
m_flame_check_task.reset(new FlameCheckUpdate(m_flame_to_update, versions, loaders, loadersList, m_mod_model));
|
||||||
connect(m_flame_check_task.get(), &CheckUpdateTask::checkFailed, this, [this](Mod* mod, QString reason, QUrl recover_url) {
|
connect(m_flame_check_task.get(), &CheckUpdateTask::checkFailed, this, [this](Mod* mod, QString reason, QUrl recover_url) {
|
||||||
m_failed_check_update.append({ mod, reason, recover_url });
|
m_failed_check_update.append({ mod, reason, recover_url });
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user