Merge branch 'develop' into data-packs

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad
2024-08-22 20:00:49 +01:00
committed by GitHub
516 changed files with 10962 additions and 7457 deletions

View File

@@ -74,6 +74,7 @@ void Flame::FileResolvingTask::netJobFinished()
setProgress(1, 3);
// job to check modrinth for blocked projects
m_checkJob.reset(new NetJob("Modrinth check", m_network));
m_checkJob->setAskRetry(false);
blockedProjects = QMap<File*, std::shared_ptr<QByteArray>>();
QJsonDocument doc;
@@ -103,7 +104,7 @@ void Flame::FileResolvingTask::netJobFinished()
auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash);
auto output = std::make_shared<QByteArray>();
auto dl = Net::ApiDownload::makeByteArray(QUrl(url), output);
QObject::connect(dl.get(), &Net::ApiDownload::succeeded, [&out]() { out.resolved = true; });
QObject::connect(dl.get(), &Task::succeeded, [&out]() { out.resolved = true; });
m_checkJob->addNetAction(dl);
blockedProjects.insert(&out, output);
@@ -119,7 +120,6 @@ void Flame::FileResolvingTask::netJobFinished()
connect(m_checkJob.get(), &NetJob::failed, this, [this, step_progress](QString reason) {
step_progress->state = TaskStepState::Failed;
stepProgress(*step_progress);
emitFailed(reason);
});
connect(m_checkJob.get(), &NetJob::stepProgress, this, &FileResolvingTask::propagateStepProgress);
connect(m_checkJob.get(), &NetJob::progress, this, [this, step_progress](qint64 current, qint64 total) {
@@ -176,7 +176,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished()
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId);
auto dl = Net::ApiDownload::makeByteArray(url, output);
qDebug() << "Fetching url slug for file:" << mod->fileName;
QObject::connect(dl.get(), &Net::ApiDownload::succeeded, [block, index, output]() {
QObject::connect(dl.get(), &Task::succeeded, [block, index, output]() {
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
auto json = QJsonDocument::fromJson(*output);
auto base =

View File

@@ -9,7 +9,7 @@ class FileResolvingTask : public Task {
Q_OBJECT
public:
explicit FileResolvingTask(const shared_qobject_ptr<QNetworkAccessManager>& network, Flame::Manifest& toProcess);
virtual ~FileResolvingTask(){};
virtual ~FileResolvingTask() {};
bool canAbort() const override { return true; }
bool abort() override;

View File

@@ -3,14 +3,16 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "FlameAPI.h"
#include <memory>
#include <optional>
#include "FlameModIndex.h"
#include "Application.h"
#include "Json.h"
#include "modplatform/ModIndex.h"
#include "net/ApiDownload.h"
#include "net/ApiUpload.h"
#include "net/NetJob.h"
#include "net/Upload.h"
Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response)
{
@@ -32,7 +34,7 @@ Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shar
return netJob;
}
auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
QString FlameAPI::getModFileChangelog(int modId, int fileId)
{
QEventLoop lock;
QString changelog;
@@ -67,7 +69,7 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
return changelog;
}
auto FlameAPI::getModDescription(int modId) -> QString
QString FlameAPI::getModDescription(int modId)
{
QEventLoop lock;
QString description;
@@ -100,7 +102,7 @@ auto FlameAPI::getModDescription(int modId) -> QString
return description;
}
auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion
QList<ModPlatform::IndexedVersion> FlameAPI::getLatestVersions(VersionSearchArgs&& args)
{
auto versions_url_optional = getVersionsURL(args);
if (!versions_url_optional.has_value())
@@ -112,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 response = std::make_shared<QByteArray>();
ModPlatform::IndexedVersion ver;
QList<ModPlatform::IndexedVersion> ver;
netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response));
@@ -132,9 +134,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
for (auto file : arr) {
auto file_obj = Json::requireObject(file);
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
if (file_tmp.date > ver.date && (!args.loaders.has_value() || !file_tmp.loaders || args.loaders.value() & file_tmp.loaders))
ver = file_tmp;
ver.append(FlameMod::loadIndexedPackVersion(file_obj));
}
} catch (Json::JsonException& e) {
@@ -144,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();
@@ -220,3 +220,65 @@ QList<ResourceAPI::SortingMethod> FlameAPI::getSortingMethods() const
{ 7, "Category", QObject::tr("Sort by Category") },
{ 8, "GameVersion", QObject::tr("Sort by Game Version") } };
}
Task::Ptr FlameAPI::getModCategories(std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Flame::GetCategories"), APPLICATION->network());
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl("https://api.curseforge.com/v1/categories?gameId=432&classId=6"), response));
QObject::connect(netJob.get(), &Task::failed, [](QString msg) { qDebug() << "Flame failed to get categories:" << msg; });
return netJob;
}
QList<ModPlatform::Category> FlameAPI::loadModCategories(std::shared_ptr<QByteArray> response)
{
QList<ModPlatform::Category> categories;
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
qWarning() << "Error while parsing JSON response from categories at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
return categories;
}
try {
auto obj = Json::requireObject(doc);
auto arr = Json::requireArray(obj, "data");
for (auto val : arr) {
auto cat = Json::requireObject(val);
auto id = Json::requireInteger(cat, "id");
auto name = Json::requireString(cat, "name");
categories.push_back({ name, QString::number(id) });
}
} catch (Json::JsonException& e) {
qCritical() << "Failed to parse response from a version request.";
qCritical() << e.what();
qDebug() << doc;
}
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);
}

View File

@@ -4,7 +4,7 @@
#pragma once
#include <algorithm>
#include <QList>
#include <memory>
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
@@ -12,19 +12,25 @@
class FlameAPI : public NetworkResourceAPI {
public:
auto getModFileChangelog(int modId, int fileId) -> QString;
auto getModDescription(int modId) -> QString;
QString getModFileChangelog(int modId, int fileId);
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 matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response);
Task::Ptr getFiles(const QStringList& fileIds, std::shared_ptr<QByteArray> response) const;
Task::Ptr getFile(const QString& addonId, const QString& fileId, std::shared_ptr<QByteArray> response) const;
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
static Task::Ptr getModCategories(std::shared_ptr<QByteArray> response);
static QList<ModPlatform::Category> loadModCategories(std::shared_ptr<QByteArray> response);
static inline auto validateModLoaders(ModPlatform::ModLoaderTypes loaders) -> bool
[[nodiscard]] QList<ResourceAPI::SortingMethod> getSortingMethods() const override;
static inline bool validateModLoaders(ModPlatform::ModLoaderTypes loaders)
{
return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
}
@@ -64,7 +70,7 @@ class FlameAPI : public NetworkResourceAPI {
return 0;
}
static auto getModLoaderStrings(const ModPlatform::ModLoaderTypes types) -> const QStringList
static const QStringList getModLoaderStrings(const ModPlatform::ModLoaderTypes types)
{
QStringList l;
for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt }) {
@@ -75,10 +81,7 @@ class FlameAPI : public NetworkResourceAPI {
return l;
}
static auto getModLoaderFilters(ModPlatform::ModLoaderTypes types) -> const QString
{
return "[" + getModLoaderStrings(types).join(',') + "]";
}
static const QString getModLoaderFilters(ModPlatform::ModLoaderTypes types) { return "[" + getModLoaderStrings(types).join(',') + "]"; }
private:
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
@@ -97,6 +100,9 @@ class FlameAPI : public NetworkResourceAPI {
get_arguments.append("sortOrder=desc");
if (args.loaders.has_value())
get_arguments.append(QString("modLoaderTypes=%1").arg(getModLoaderFilters(args.loaders.value())));
if (args.categoryIds.has_value() && !args.categoryIds->empty())
get_arguments.append(QString("categoryIds=[%1]").arg(args.categoryIds->join(",")));
get_arguments.append(gameVersionStr);
return "https://api.curseforge.com/v1/mods/search?gameId=432&" + get_arguments.join('&');

View File

@@ -1,4 +1,5 @@
#include "FlameCheckUpdate.h"
#include "Application.h"
#include "FlameAPI.h"
#include "FlameModIndex.h"
@@ -24,7 +25,7 @@ bool FlameCheckUpdate::abort()
return true;
}
ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info)
ModPlatform::IndexedPack FlameCheckUpdate::getProjectInfo(ModPlatform::IndexedVersion& ver_info)
{
ModPlatform::IndexedPack pack;
@@ -57,6 +58,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info)
}
});
connect(get_project_job, &NetJob::failed, this, &FlameCheckUpdate::emitFailed);
QObject::connect(get_project_job, &NetJob::finished, [&loop, get_project_job] {
get_project_job->deleteLater();
loop.quit();
@@ -68,7 +70,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info)
return pack;
}
ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId)
ModPlatform::IndexedVersion FlameCheckUpdate::getFileInfo(int addonId, int fileId)
{
ModPlatform::IndexedVersion ver;
@@ -100,7 +102,7 @@ ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId)
qDebug() << doc;
}
});
connect(get_file_info_job, &NetJob::failed, this, &FlameCheckUpdate::emitFailed);
QObject::connect(get_file_info_job, &NetJob::finished, [&loop, get_file_info_job] {
get_file_info_job->deleteLater();
loop.quit();
@@ -123,33 +125,29 @@ void FlameCheckUpdate::executeTask()
int i = 0;
for (auto* mod : m_mods) {
if (!mod->enabled()) {
emit checkFailed(mod, tr("Disabled mods won't be updated, to prevent mod duplication issues!"));
continue;
}
setStatus(tr("Getting API response from CurseForge for '%1'...").arg(mod->name()));
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 });
// Check if we were aborted while getting the latest version
if (m_was_aborted) {
aborted();
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()));
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 "
"version / mod loader."));
continue;
}
if (latest_ver.downloadUrl.isEmpty() && latest_ver.fileId != mod->metadata()->file_id) {
auto pack = getProjectInfo(latest_ver);
auto recover_url = QString("%1/download/%2").arg(pack.websiteUrl, latest_ver.fileId.toString());
if (latest_ver->downloadUrl.isEmpty() && latest_ver->fileId != mod->metadata()->file_id) {
auto pack = getProjectInfo(latest_ver.value());
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);
continue;
@@ -165,19 +163,19 @@ void FlameCheckUpdate::executeTask()
pack->authors.append({ author });
pack->description = mod->description();
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();
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;
}
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver, m_mods_folder);
m_updatable.emplace_back(pack->name, mod->metadata()->hash, old_version, latest_ver.version, latest_ver.version_type,
api.getModFileChangelog(latest_ver.addonId.toInt(), latest_ver.fileId.toInt()),
ModPlatform::ResourceProvider::FLAME, download_task);
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,
api.getModFileChangelog(latest_ver->addonId.toInt(), latest_ver->fileId.toInt()),
ModPlatform::ResourceProvider::FLAME, download_task, mod->enabled());
}
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, latest_ver));
m_deps.append(std::make_shared<GetModDependenciesTask::PackDependency>(pack, latest_ver.value()));
}
emitSucceeded();

View File

@@ -1,6 +1,5 @@
#pragma once
#include "Application.h"
#include "modplatform/CheckUpdateTask.h"
#include "net/NetJob.h"
@@ -10,9 +9,9 @@ class FlameCheckUpdate : public CheckUpdateTask {
public:
FlameCheckUpdate(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, mods_folder)
: CheckUpdateTask(mods, mcVersions, loadersList, mods_folder)
{}
public slots:
@@ -22,6 +21,9 @@ class FlameCheckUpdate : public CheckUpdateTask {
void executeTask() override;
private:
ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info);
ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId);
NetJob* m_net_job = nullptr;
bool m_was_aborted = false;

View File

@@ -227,6 +227,7 @@ bool FlameCreationTask::updateInstance()
m_files_to_remove.append(old_minecraft_dir.absoluteFilePath(relative_path));
}
});
connect(job.get(), &Task::failed, this, [](QString reason) { qCritical() << "Failed to get files: " << reason; });
connect(job.get(), &Task::finished, &loop, &QEventLoop::quit);
m_process_update_file_info_job = job;
@@ -321,7 +322,7 @@ bool FlameCreationTask::createInstance()
// Keep index file in case we need it some other time (like when changing versions)
QString new_index_place(FS::PathCombine(parent_folder, "manifest.json"));
FS::ensureFilePathExists(new_index_place);
QFile::rename(index_path, new_index_place);
FS::move(index_path, new_index_place);
} catch (const JSONValidationError& e) {
setError(tr("Could not understand pack manifest:\n") + e.cause());
@@ -335,7 +336,7 @@ bool FlameCreationTask::createInstance()
Override::createOverrides("overrides", parent_folder, overridePath);
QString mcPath = FS::PathCombine(m_stagingPath, "minecraft");
if (!QFile::rename(overridePath, mcPath)) {
if (!FS::move(overridePath, mcPath)) {
setError(tr("Could not rename the overrides folder:\n") + m_pack.overrides);
return false;
}
@@ -353,6 +354,8 @@ bool FlameCreationTask::createInstance()
auto id = loader.id;
if (id.startsWith("neoforge-")) {
id.remove("neoforge-");
if (id.startsWith("1.20.1-"))
id.remove("1.20.1-"); // this is a mess for curseforge
loaderType = "neoforge";
loaderUid = "net.neoforged";
} else if (id.startsWith("forge-")) {
@@ -427,6 +430,9 @@ bool FlameCreationTask::createInstance()
// Don't add managed info to packs without an ID (most likely imported from ZIP)
if (!m_managed_id.isEmpty())
instance.setManagedPack("flame", m_managed_id, m_pack.name, m_managed_version_id, m_pack.version);
else
instance.setManagedPack("flame", "", name(), "", "");
instance.setName(name());
m_mod_id_resolver.reset(new Flame::FileResolvingTask(APPLICATION->network(), m_pack));
@@ -531,7 +537,10 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
selectedOptionalMods = optionalModDialog.getResult();
}
for (const auto& result : results) {
auto relpath = FS::PathCombine(result.targetFolder, result.fileName);
auto fileName = result.fileName;
fileName = FS::RemoveInvalidPathChars(fileName);
auto relpath = FS::PathCombine(result.targetFolder, fileName);
if (!result.required && !selectedOptionalMods.contains(relpath)) {
relpath += ".disabled";
}

View File

@@ -1,12 +1,12 @@
#include "FlameModIndex.h"
#include "FileSystem.h"
#include "Json.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "modplatform/flame/FlameAPI.h"
static FlameAPI api;
static ModPlatform::ProviderCapabilities ProviderCaps;
void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
@@ -20,6 +20,9 @@ void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
QJsonObject logo = Json::ensureObject(obj, "logo");
pack.logoName = Json::ensureString(logo, "title");
pack.logoUrl = Json::ensureString(logo, "thumbnailUrl");
if (pack.logoUrl.isEmpty()) {
pack.logoUrl = Json::ensureString(logo, "url");
}
auto authors = Json::ensureArray(obj, "authors");
for (auto authorIter : authors) {
@@ -79,10 +82,6 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
const BaseInstance* inst)
{
QVector<ModPlatform::IndexedVersion> unsortedVersions;
auto profile = (dynamic_cast<const MinecraftInstance*>(inst))->getPackProfile();
QString mcVersion = profile->getComponentVersion("net.minecraft");
auto loaders = profile->getSupportedModLoaders();
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
@@ -90,8 +89,7 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
if (!file.addonId.isValid())
file.addonId = pack.addonId;
if (file.fileId.isValid() &&
(!loaders.has_value() || !file.loaders || loaders.value() & file.loaders)) // Heuristic to check if the returned value is valid
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
unsortedVersions.append(file);
}
@@ -117,19 +115,25 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
if (str.contains('.'))
file.mcVersion.append(str);
auto loader = str.toLower();
if (loader == "neoforge")
if (auto loader = str.toLower(); loader == "neoforge")
file.loaders |= ModPlatform::NeoForge;
if (loader == "forge")
else if (loader == "forge")
file.loaders |= ModPlatform::Forge;
if (loader == "cauldron")
else if (loader == "cauldron")
file.loaders |= ModPlatform::Cauldron;
if (loader == "liteloader")
else if (loader == "liteloader")
file.loaders |= ModPlatform::LiteLoader;
if (loader == "fabric")
else if (loader == "fabric")
file.loaders |= ModPlatform::Fabric;
if (loader == "quilt")
else if (loader == "quilt")
file.loaders |= ModPlatform::Quilt;
else if (loader == "server" || loader == "client") {
if (file.side.isEmpty())
file.side = loader;
else if (file.side != loader)
file.side = "both";
}
}
file.addonId = Json::requireInteger(obj, "modId");
@@ -138,6 +142,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
file.version = Json::requireString(obj, "displayName");
file.downloadUrl = Json::ensureString(obj, "downloadUrl");
file.fileName = Json::requireString(obj, "fileName");
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
ModPlatform::IndexedVersionType::VersionType ver_type;
switch (Json::requireInteger(obj, "releaseType")) {
@@ -158,7 +163,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::ResourceProvider::FLAME);
auto hash_types = ModPlatform::ProviderCapabilities::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");

View File

@@ -116,7 +116,7 @@ void FlamePackExportTask::collectHashes()
if (relative.startsWith("resourcepacks/") &&
(relative.endsWith(".zip") || relative.endsWith(".zip.disabled"))) { // is resourcepack
auto hashTask = Hashing::createFlameHasher(file.absoluteFilePath());
auto hashTask = Hashing::createHasher(file.absoluteFilePath(), ModPlatform::ResourceProvider::FLAME);
connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, relative, file](QString hash) {
if (m_state == Task::State::Running) {
pendingHashes.insert(hash, { relative, file.absoluteFilePath(), relative.endsWith(".zip") });
@@ -140,7 +140,7 @@ void FlamePackExportTask::collectHashes()
continue;
}
auto hashTask = Hashing::createFlameHasher(mod->fileinfo().absoluteFilePath());
auto hashTask = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::FLAME);
connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) {
if (m_state == Task::State::Running) {
pendingHashes.insert(hash, { mod->name(), mod->fileinfo().absoluteFilePath(), mod->enabled(), true });
@@ -201,7 +201,7 @@ void FlamePackExportTask::makeApiRequest()
<< " reason: " << parseError.errorString();
qWarning() << *response;
failed(parseError.errorString());
emitFailed(parseError.errorString());
return;
}
@@ -213,6 +213,7 @@ void FlamePackExportTask::makeApiRequest()
if (dataArr.isEmpty()) {
qWarning() << "No matches found for fingerprint search!";
getProjectsInfo();
return;
}
for (auto match : dataArr) {
@@ -243,9 +244,9 @@ void FlamePackExportTask::makeApiRequest()
qDebug() << doc;
}
pendingHashes.clear();
getProjectsInfo();
});
connect(task.get(), &Task::finished, this, &FlamePackExportTask::getProjectsInfo);
connect(task.get(), &NetJob::failed, this, &FlamePackExportTask::emitFailed);
connect(task.get(), &Task::failed, this, &FlamePackExportTask::getProjectsInfo);
task->start();
}
@@ -279,7 +280,7 @@ void FlamePackExportTask::getProjectsInfo()
qWarning() << "Error while parsing JSON response from CurseForge projects task at " << parseError.offset
<< " reason: " << parseError.errorString();
qWarning() << *response;
failed(parseError.errorString());
emitFailed(parseError.errorString());
return;
}
@@ -323,6 +324,7 @@ void FlamePackExportTask::getProjectsInfo()
}
buildZip();
});
connect(projTask.get(), &Task::failed, this, &FlamePackExportTask::emitFailed);
task.reset(projTask);
task->start();
}
@@ -332,7 +334,7 @@ void FlamePackExportTask::buildZip()
setStatus(tr("Adding files..."));
setProgress(4, 5);
auto zipTask = makeShared<MMCZip::ExportToZipTask>(output, gameRoot, files, "overrides/", true);
auto zipTask = makeShared<MMCZip::ExportToZipTask>(output, gameRoot, files, "overrides/", true, false);
zipTask->addExtraFile("manifest.json", generateIndex());
zipTask->addExtraFile("modlist.html", generateHTML());
@@ -392,13 +394,17 @@ QByteArray FlamePackExportTask::generateIndex()
version["version"] = minecraft->m_version;
QString id;
if (quilt != nullptr)
id = "quilt-" + quilt->getVersion();
id = "quilt-" + quilt->m_version;
else if (fabric != nullptr)
id = "fabric-" + fabric->getVersion();
id = "fabric-" + fabric->m_version;
else if (forge != nullptr)
id = "forge-" + forge->getVersion();
else if (neoforge != nullptr)
id = "neoforge-" + neoforge->getVersion();
id = "forge-" + forge->m_version;
else if (neoforge != nullptr) {
id = "neoforge-";
if (minecraft->m_version == "1.20.1")
id += "1.20.1-";
id += neoforge->m_version;
}
version["modLoaders"] = QJsonArray();
if (!id.isEmpty()) {
QJsonObject loader;