Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into curse
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -33,6 +34,8 @@ enum class ResourceProvider { MODRINTH, FLAME };
|
||||
|
||||
enum class ResourceType { MOD, RESOURCE_PACK, SHADER_PACK };
|
||||
|
||||
enum class DependencyType { REQUIRED, OPTIONAL, INCOMPATIBLE, EMBEDDED, TOOL, INCLUDE, UNKNOWN };
|
||||
|
||||
class ProviderCapabilities {
|
||||
public:
|
||||
auto name(ResourceProvider) -> const char*;
|
||||
@ -52,6 +55,12 @@ struct DonationData {
|
||||
QString url;
|
||||
};
|
||||
|
||||
struct Dependency {
|
||||
QVariant addonId;
|
||||
DependencyType type;
|
||||
QString version;
|
||||
};
|
||||
|
||||
struct IndexedVersion {
|
||||
QVariant addonId;
|
||||
QVariant fileId;
|
||||
@ -66,6 +75,7 @@ struct IndexedVersion {
|
||||
QString hash;
|
||||
bool is_preferred = true;
|
||||
QString changelog;
|
||||
QList<Dependency> dependencies;
|
||||
|
||||
// For internal use, not provided by APIs
|
||||
bool is_currently_selected = false;
|
||||
@ -120,6 +130,22 @@ struct IndexedPack {
|
||||
};
|
||||
QString getMetaURL(ResourceProvider provider, QString slug);
|
||||
|
||||
struct OverrideDep {
|
||||
QString quilt;
|
||||
QString fabric;
|
||||
QString slug;
|
||||
ModPlatform::ResourceProvider provider;
|
||||
};
|
||||
|
||||
inline auto getOverrideDeps() -> QList<OverrideDep>
|
||||
{
|
||||
return { { "634179", "306612", "API", ModPlatform::ResourceProvider::FLAME },
|
||||
{ "720410", "308769", "KotlinLibraries", ModPlatform::ResourceProvider::FLAME },
|
||||
|
||||
{ "qvIfYCYJ", "P7dR8mSH", "API", ModPlatform::ResourceProvider::MODRINTH },
|
||||
{ "lwVhp9o5", "Ha28R6CL", "KotlinLibraries", ModPlatform::ResourceProvider::MODRINTH } };
|
||||
};
|
||||
|
||||
} // namespace ModPlatform
|
||||
|
||||
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
|
||||
|
@ -111,6 +111,16 @@ class ResourceAPI {
|
||||
std::function<void(QJsonDocument&, ModPlatform::IndexedPack)> on_succeed;
|
||||
};
|
||||
|
||||
struct DependencySearchArgs {
|
||||
ModPlatform::Dependency dependency;
|
||||
Version mcVersion;
|
||||
ModLoaderTypes loader;
|
||||
};
|
||||
|
||||
struct DependencySearchCallbacks {
|
||||
std::function<void(QJsonDocument&, const ModPlatform::Dependency&)> on_succeed;
|
||||
};
|
||||
|
||||
public:
|
||||
/** Gets a list of available sorting methods for this API. */
|
||||
[[nodiscard]] virtual auto getSortingMethods() const -> QList<SortingMethod> = 0;
|
||||
@ -143,6 +153,12 @@ class ResourceAPI {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static auto getModLoaderString(ModLoaderType type) -> const QString
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
#include "modplatform/helpers/NetworkResourceAPI.h"
|
||||
|
||||
class FlameAPI : public NetworkResourceAPI {
|
||||
@ -75,14 +77,44 @@ class FlameAPI : public NetworkResourceAPI {
|
||||
|
||||
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
|
||||
{
|
||||
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(args.pack.addonId.toString()) };
|
||||
auto mappedModLoader = getMappedModLoader(args.loaders.value());
|
||||
auto addonId = args.pack.addonId.toString();
|
||||
if (args.loaders.value() & Quilt) {
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
|
||||
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
|
||||
});
|
||||
if (over != overide.cend()) {
|
||||
mappedModLoader = 5;
|
||||
}
|
||||
}
|
||||
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) };
|
||||
|
||||
QStringList get_parameters;
|
||||
if (args.mcVersions.has_value())
|
||||
get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString()));
|
||||
if (args.loaders.has_value())
|
||||
get_parameters.append(QString("modLoaderType=%1").arg(getMappedModLoader(args.loaders.value())));
|
||||
get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader));
|
||||
|
||||
return url + get_parameters.join('&');
|
||||
};
|
||||
|
||||
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
||||
{
|
||||
auto mappedModLoader = getMappedModLoader(args.loader);
|
||||
auto addonId = args.dependency.addonId.toString();
|
||||
if (args.loader & Quilt) {
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
|
||||
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
|
||||
});
|
||||
if (over != overide.cend()) {
|
||||
mappedModLoader = 5;
|
||||
}
|
||||
}
|
||||
return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&gameVersion=%2&modLoaderType=%3")
|
||||
.arg(addonId)
|
||||
.arg(args.mcVersion.toString())
|
||||
.arg(mappedModLoader);
|
||||
};
|
||||
};
|
||||
|
@ -39,15 +39,15 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
auto links_obj = Json::ensureObject(obj, "links");
|
||||
|
||||
pack.extraData.issuesUrl = Json::ensureString(links_obj, "issuesUrl");
|
||||
if(pack.extraData.issuesUrl.endsWith('/'))
|
||||
if (pack.extraData.issuesUrl.endsWith('/'))
|
||||
pack.extraData.issuesUrl.chop(1);
|
||||
|
||||
pack.extraData.sourceUrl = Json::ensureString(links_obj, "sourceUrl");
|
||||
if(pack.extraData.sourceUrl.endsWith('/'))
|
||||
if (pack.extraData.sourceUrl.endsWith('/'))
|
||||
pack.extraData.sourceUrl.chop(1);
|
||||
|
||||
pack.extraData.wikiUrl = Json::ensureString(links_obj, "wikiUrl");
|
||||
if(pack.extraData.wikiUrl.endsWith('/'))
|
||||
if (pack.extraData.wikiUrl.endsWith('/'))
|
||||
pack.extraData.wikiUrl.chop(1);
|
||||
|
||||
if (!pack.extraData.body.isEmpty())
|
||||
@ -56,7 +56,7 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
|
||||
void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
{
|
||||
pack.extraData.body = api.getModDescription(pack.addonId.toInt());
|
||||
pack.extraData.body = api.getModDescription(pack.addonId.toInt());
|
||||
|
||||
if (!pack.extraData.issuesUrl.isEmpty() || !pack.extraData.sourceUrl.isEmpty() || !pack.extraData.wikiUrl.isEmpty())
|
||||
pack.extraDataLoaded = true;
|
||||
@ -64,12 +64,12 @@ void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
|
||||
static QString enumToString(int hash_algorithm)
|
||||
{
|
||||
switch(hash_algorithm){
|
||||
default:
|
||||
case 1:
|
||||
return "sha1";
|
||||
case 2:
|
||||
return "md5";
|
||||
switch (hash_algorithm) {
|
||||
default:
|
||||
case 1:
|
||||
return "sha1";
|
||||
case 2:
|
||||
return "md5";
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,12 +84,12 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
|
||||
for (auto versionIter : arr) {
|
||||
auto obj = versionIter.toObject();
|
||||
|
||||
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
if(!file.addonId.isValid())
|
||||
if (!file.addonId.isValid())
|
||||
file.addonId = pack.addonId;
|
||||
|
||||
if(file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
unsortedVersions.append(file);
|
||||
}
|
||||
|
||||
@ -136,8 +136,61 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
||||
}
|
||||
}
|
||||
|
||||
if(load_changelog)
|
||||
auto dependencies = Json::ensureArray(obj, "dependencies");
|
||||
for (auto d : dependencies) {
|
||||
auto dep = Json::ensureObject(d);
|
||||
ModPlatform::Dependency dependency;
|
||||
dependency.addonId = Json::requireInteger(dep, "modId");
|
||||
switch (Json::requireInteger(dep, "relationType")) {
|
||||
case 1: // EmbeddedLibrary
|
||||
dependency.type = ModPlatform::DependencyType::EMBEDDED;
|
||||
break;
|
||||
case 2: // OptionalDependency
|
||||
dependency.type = ModPlatform::DependencyType::OPTIONAL;
|
||||
break;
|
||||
case 3: // RequiredDependency
|
||||
dependency.type = ModPlatform::DependencyType::REQUIRED;
|
||||
break;
|
||||
case 4: // Tool
|
||||
dependency.type = ModPlatform::DependencyType::TOOL;
|
||||
break;
|
||||
case 5: // Incompatible
|
||||
dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
|
||||
break;
|
||||
case 6: // Include
|
||||
dependency.type = ModPlatform::DependencyType::INCLUDE;
|
||||
break;
|
||||
default:
|
||||
dependency.type = ModPlatform::DependencyType::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
file.dependencies.append(dependency);
|
||||
}
|
||||
|
||||
if (load_changelog)
|
||||
file.changelog = api.getModFileChangelog(file.addonId.toInt(), file.fileId.toInt());
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr)
|
||||
{
|
||||
QVector<ModPlatform::IndexedVersion> versions;
|
||||
for (auto versionIter : arr) {
|
||||
auto obj = versionIter.toObject();
|
||||
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
if (!file.addonId.isValid())
|
||||
file.addonId = m.addonId;
|
||||
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
versions.append(file);
|
||||
}
|
||||
|
||||
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
||||
// dates are in RFC 3339 format
|
||||
return a.date > b.date;
|
||||
};
|
||||
std::sort(versions.begin(), versions.end(), orderSortPredicate);
|
||||
return versions.front();
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include "BaseInstance.h"
|
||||
|
||||
namespace FlameMod {
|
||||
|
||||
@ -19,5 +19,5 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
const shared_qobject_ptr<QNetworkAccessManager>& network,
|
||||
const BaseInstance* inst);
|
||||
auto loadIndexedPackVersion(QJsonObject& obj, bool load_changelog = false) -> ModPlatform::IndexedVersion;
|
||||
|
||||
} // namespace FlameMod
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
|
||||
} // namespace FlameMod
|
@ -4,6 +4,7 @@
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
namespace Flame {
|
||||
|
||||
@ -27,8 +28,7 @@ struct ModpackExtra {
|
||||
QString sourceUrl;
|
||||
};
|
||||
|
||||
struct IndexedPack
|
||||
{
|
||||
struct IndexedPack {
|
||||
int addonId;
|
||||
QString name;
|
||||
QString description;
|
||||
@ -43,9 +43,9 @@ struct IndexedPack
|
||||
ModpackExtra extra;
|
||||
};
|
||||
|
||||
void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
|
||||
void loadIndexedPack(IndexedPack& m, QJsonObject& obj);
|
||||
void loadIndexedInfo(IndexedPack&, QJsonObject&);
|
||||
void loadIndexedPackVersions(IndexedPack & m, QJsonArray & arr);
|
||||
}
|
||||
void loadIndexedPackVersions(IndexedPack& m, QJsonArray& arr);
|
||||
} // namespace Flame
|
||||
|
||||
Q_DECLARE_METATYPE(Flame::IndexedPack)
|
||||
|
@ -117,3 +117,32 @@ Task::Ptr NetworkResourceAPI::getProject(QString addonId, std::shared_ptr<QByteA
|
||||
|
||||
return netJob;
|
||||
}
|
||||
|
||||
Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, DependencySearchCallbacks&& callbacks) const
|
||||
{
|
||||
auto versions_url_optional = getDependencyURL(args);
|
||||
if (!versions_url_optional.has_value())
|
||||
return nullptr;
|
||||
|
||||
auto versions_url = versions_url_optional.value();
|
||||
|
||||
auto netJob = makeShared<NetJob>(QString("%1::Dependency").arg(args.dependency.addonId.toString()), APPLICATION->network());
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, [=] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response for getting versions at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.on_succeed(doc, args.dependency);
|
||||
});
|
||||
|
||||
return netJob;
|
||||
};
|
||||
|
@ -15,9 +15,11 @@ class NetworkResourceAPI : public ResourceAPI {
|
||||
|
||||
Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
|
||||
Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const override;
|
||||
Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const override;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] virtual auto getSearchURL(SearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getInfoURL(QString const& id) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getVersionsURL(VersionSearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getDependencyURL(DependencySearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
};
|
||||
|
@ -38,7 +38,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
|
||||
{
|
||||
QStringList l;
|
||||
for (auto loader : {Forge, Fabric, Quilt}) {
|
||||
for (auto loader : { Forge, Fabric, Quilt }) {
|
||||
if (types & loader) {
|
||||
l << getModLoaderString(loader);
|
||||
}
|
||||
@ -51,8 +51,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
static auto getModLoaderFilters(ModLoaderTypes types) -> const QString
|
||||
{
|
||||
QStringList l;
|
||||
for (auto loader : getModLoaderStrings(types))
|
||||
{
|
||||
for (auto loader : getModLoaderStrings(types)) {
|
||||
l << QString("\"categories:%1\"").arg(loader);
|
||||
}
|
||||
return l.join(',');
|
||||
@ -135,16 +134,22 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
auto getGameVersionsArray(std::list<Version> mcVersions) const -> QString
|
||||
{
|
||||
QString s;
|
||||
for(auto& ver : mcVersions){
|
||||
for (auto& ver : mcVersions) {
|
||||
s += QString("\"versions:%1\",").arg(ver.toString());
|
||||
}
|
||||
s.remove(s.length() - 1, 1); //remove last comma
|
||||
s.remove(s.length() - 1, 1); // remove last comma
|
||||
return s.isEmpty() ? QString() : s;
|
||||
}
|
||||
|
||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool
|
||||
{
|
||||
return loaders & (Forge | Fabric | Quilt);
|
||||
}
|
||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool { return loaders & (Forge | Fabric | Quilt); }
|
||||
|
||||
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
||||
{
|
||||
return args.dependency.version.length() != 0 ? QString("%1/version/%2").arg(BuildConfig.MODRINTH_PROD_URL, args.dependency.version)
|
||||
: QString("%1/project/%2/version?game_versions=[\"%3\"]&loaders=[\"%4\"]")
|
||||
.arg(BuildConfig.MODRINTH_PROD_URL)
|
||||
.arg(args.dependency.addonId.toString())
|
||||
.arg(args.mcVersion.toString())
|
||||
.arg(getModLoaderStrings(args.loader).join("\",\""));
|
||||
};
|
||||
};
|
||||
|
@ -136,8 +136,8 @@ void ModrinthPackExportTask::collectHashes()
|
||||
QCryptographicHash sha1(QCryptographicHash::Algorithm::Sha1);
|
||||
sha1.addData(data);
|
||||
|
||||
ResolvedFile file{ sha1.result().toHex(), sha512.result().toHex(), url.toString(), openFile.size() };
|
||||
resolvedFiles[relative] = file;
|
||||
ResolvedFile resolvedFile{ sha1.result().toHex(), sha512.result().toHex(), url.toEncoded(), openFile.size() };
|
||||
resolvedFiles[relative] = resolvedFile;
|
||||
|
||||
// nice! we've managed to resolve based on local metadata!
|
||||
// no need to enqueue it
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "Json.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "net/NetJob.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
static ModrinthAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
@ -140,6 +140,28 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
file.version_number = Json::requireString(obj, "version_number");
|
||||
file.changelog = Json::requireString(obj, "changelog");
|
||||
|
||||
auto dependencies = Json::ensureArray(obj, "dependencies");
|
||||
for (auto d : dependencies) {
|
||||
auto dep = Json::ensureObject(d);
|
||||
ModPlatform::Dependency dependency;
|
||||
dependency.addonId = Json::ensureString(dep, "project_id");
|
||||
dependency.version = Json::ensureString(dep, "version_id");
|
||||
auto depType = Json::requireString(dep, "dependency_type");
|
||||
|
||||
if (depType == "required")
|
||||
dependency.type = ModPlatform::DependencyType::REQUIRED;
|
||||
else if (depType == "optional")
|
||||
dependency.type = ModPlatform::DependencyType::OPTIONAL;
|
||||
else if (depType == "incompatible")
|
||||
dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
|
||||
else if (depType == "embedded")
|
||||
dependency.type = ModPlatform::DependencyType::EMBEDDED;
|
||||
else
|
||||
dependency.type = ModPlatform::DependencyType::UNKNOWN;
|
||||
|
||||
file.dependencies.append(dependency);
|
||||
}
|
||||
|
||||
auto files = Json::requireArray(obj, "files");
|
||||
int i = 0;
|
||||
|
||||
@ -195,3 +217,22 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Modrinth::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
QVector<ModPlatform::IndexedVersion> versions;
|
||||
|
||||
for (auto versionIter : arr) {
|
||||
auto obj = versionIter.toObject();
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
versions.append(file);
|
||||
}
|
||||
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
||||
// dates are in RFC 3339 format
|
||||
return a.date > b.date;
|
||||
};
|
||||
std::sort(versions.begin(), versions.end(), orderSortPredicate);
|
||||
return versions.length() != 0 ? versions.front() : ModPlatform::IndexedVersion();
|
||||
}
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include "BaseInstance.h"
|
||||
|
||||
namespace Modrinth {
|
||||
|
||||
@ -31,5 +31,6 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
const shared_qobject_ptr<QNetworkAccessManager>& network,
|
||||
const BaseInstance* inst);
|
||||
auto loadIndexedPackVersion(QJsonObject& obj, QString hash_type = "sha512", QString filename_prefer = "") -> ModPlatform::IndexedVersion;
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
|
||||
|
||||
} // namespace Modrinth
|
||||
|
Reference in New Issue
Block a user