optimize: Improve mod versions request to Modrinth

This uses more arguments in the GET request for mod versions on the
Modrinth API, filtering what versions can be returned, decreasing load
on Modrinth servers and improving a little the time it takes for the versions to be
available to the user.

This also removes the now unneeded check on correct modloaders in
ModrinthPackIndex, since it is now filtered by the Modrinth server.

Lastly, this adds a couple of helper functions in ModModel.
This commit is contained in:
flow 2022-03-24 18:39:53 -03:00
parent e13ca94061
commit d00c320c00
No known key found for this signature in database
GPG Key ID: 8D0F221F0A59F469
8 changed files with 61 additions and 36 deletions

View File

@ -1,6 +1,7 @@
#pragma once
#include <QString>
#include <QList>
namespace ModPlatform {
class ListModel;
@ -25,5 +26,13 @@ class ModAPI {
};
virtual void searchMods(CallerType* caller, SearchArgs&& args) const = 0;
virtual void getVersions(CallerType* caller, const QString& addonId) const = 0;
struct VersionSearchArgs {
QString addonId;
QList<QString> mcVersions;
ModLoaderType loader;
};
virtual void getVersions(CallerType* caller, VersionSearchArgs&& args) const = 0;
};

View File

@ -25,8 +25,8 @@ class FlameAPI : public NetworkModAPI {
.arg(args.version);
};
inline auto getVersionsURL(const QString& addonId) const -> QString override
inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override
{
return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId);
return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(args.addonId);
};
};

View File

@ -31,14 +31,14 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const
netJob->start();
}
void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) const
void NetworkModAPI::getVersions(CallerType* caller, VersionSearchArgs&& args) const
{
auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(caller->debugName()).arg(addonId), APPLICATION->network());
auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(caller->debugName()).arg(args.addonId), APPLICATION->network());
auto response = new QByteArray();
netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response));
netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(args), response));
QObject::connect(netJob, &NetJob::succeeded, caller, [response, caller, addonId] {
QObject::connect(netJob, &NetJob::succeeded, caller, [response, caller, args] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
@ -48,7 +48,7 @@ void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) cons
return;
}
caller->versionRequestSucceeded(doc, addonId);
caller->versionRequestSucceeded(doc, args.addonId);
});
QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] {

View File

@ -5,9 +5,9 @@
class NetworkModAPI : public ModAPI {
public:
void searchMods(CallerType* caller, SearchArgs&& args) const override;
void getVersions(CallerType* caller, const QString& addonId) const override;
void getVersions(CallerType* caller, VersionSearchArgs&& args) const override;
protected:
virtual auto getModSearchURL(SearchArgs& args) const -> QString = 0;
virtual auto getVersionsURL(const QString& addonId) const -> QString = 0;
virtual auto getVersionsURL(VersionSearchArgs& args) const -> QString = 0;
};

View File

@ -30,11 +30,27 @@ class ModrinthAPI : public NetworkModAPI {
.arg(args.version);
};
inline auto getVersionsURL(const QString& addonId) const -> QString override
inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override
{
return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId);
return QString("https://api.modrinth.com/v2/project/%1/version?"
"game_versions=[%2]"
"loaders=[%3]")
.arg(args.addonId)
.arg(getGameVersionsString(args.mcVersions))
.arg(getModLoaderString(args.loader));
};
inline auto getGameVersionsString(QList<QString> mcVersions) const -> QString
{
QString s;
for(int i = 0; i < mcVersions.count(); i++){
s += mcVersions.at(i);
if(i < mcVersions.count() - 1)
s += ",";
}
return s;
}
inline auto getModLoaderString(ModLoaderType modLoader) const -> QString
{
switch (modLoader) {

View File

@ -30,7 +30,6 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
BaseInstance* inst)
{
QVector<ModPlatform::IndexedVersion> unsortedVersions;
bool hasFabric = !(static_cast<MinecraftInstance*>(inst))->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty();
QString mcVersion = (static_cast<MinecraftInstance*>(inst))->getPackProfile()->getComponentVersion("net.minecraft");
for (auto versionIter : arr) {
@ -61,17 +60,6 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
auto parent = files[i].toObject();
auto fileName = Json::requireString(parent, "filename");
// Grab the correct mod loader
if(hasFabric){
if(fileName.contains("forge",Qt::CaseInsensitive)){
i++;
continue;
}
} else if(fileName.contains("fabric", Qt::CaseInsensitive)){
i++;
continue;
}
// Grab the primary file, if available
if(Json::requireBoolean(parent, "primary"))
break;

View File

@ -16,7 +16,6 @@ auto ListModel::debugName() const -> QString
return m_parent->debugName();
}
/******** Make data requests ********/
void ListModel::fetchMore(const QModelIndex& parent)
@ -61,19 +60,14 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
void ListModel::requestModVersions(ModPlatform::IndexedPack const& current)
{
m_parent->apiProvider()->getVersions(this, current.addonId.toString());
m_parent->apiProvider()->getVersions(this,
{ current.addonId.toString(), getMineVersions(), hasFabric() ? ModAPI::ModLoaderType::Fabric : ModAPI::ModLoaderType::Forge });
}
void ListModel::performPaginatedSearch()
{
QString mcVersion = (dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))->getPackProfile()->getComponentVersion("net.minecraft");
bool hasFabric = !(dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))
->getPackProfile()
->getComponentVersion("net.fabricmc.fabric-loader")
.isEmpty();
m_parent->apiProvider()->searchMods(
this, { nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric ? ModAPI::Fabric : ModAPI::Forge, mcVersion });
m_parent->apiProvider()->searchMods(this,
{ nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric() ? ModAPI::Fabric : ModAPI::Forge, getMineVersions().at(0) });
}
void ListModel::searchWithTerm(const QString& term, const int sort)
@ -131,7 +125,6 @@ void ListModel::requestLogo(QString logo, QString url)
m_loadingLogos.append(logo);
}
/******** Request callbacks ********/
void ListModel::logoLoaded(QString logo, QIcon out)
@ -208,7 +201,7 @@ void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId)
{
auto& current = m_parent->getCurrent();
if (addonId != current.addonId) { return; }
QJsonArray arr = doc.array();
try {
loadIndexedPackVersions(current, arr);
@ -221,3 +214,19 @@ void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId)
}
} // namespace ModPlatform
/******** Helpers ********/
auto ModPlatform::ListModel::hasFabric() const -> bool
{
return !(dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))
->getPackProfile()
->getComponentVersion("net.fabricmc.fabric-loader")
.isEmpty();
}
auto ModPlatform::ListModel::getMineVersions() const -> QList<QString>
{
return { (dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))
->getPackProfile()
->getComponentVersion("net.minecraft") };
}

View File

@ -62,6 +62,9 @@ class ListModel : public QAbstractListModel {
void requestLogo(QString file, QString url);
inline auto hasFabric() const -> bool;
inline auto getMineVersions() const -> QList<QString>;
protected:
ModPage* m_parent;