Skip to content

Commit

Permalink
NOISSUE Curseforge makeover
Browse files Browse the repository at this point in the history
update UI to match other modpack platforms
add sorting
add version selection, fixes MultiMCGH-3667
add installing beta versions, fixes MultiMCGH-3611
  • Loading branch information
phit committed Apr 8, 2021
1 parent 5400d4e commit 1f8408c
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 221 deletions.
2 changes: 2 additions & 0 deletions api/logic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ set(FTB_SOURCES

set(FLAME_SOURCES
# Flame
modplatform/flame/FlamePackIndex.cpp
modplatform/flame/FlamePackIndex.h
modplatform/flame/PackManifest.h
modplatform/flame/PackManifest.cpp
modplatform/flame/FileResolvingTask.h
Expand Down
92 changes: 92 additions & 0 deletions api/logic/modplatform/flame/FlamePackIndex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "FlamePackIndex.h"

#include "Json.h"

void Flame::loadIndexedPack(Flame::IndexedPack & pack, QJsonObject & obj)
{
pack.addonId = Json::requireInteger(obj, "id");
pack.name = Json::requireString(obj, "name");
pack.websiteUrl = Json::ensureString(obj, "websiteUrl", "");
pack.description = Json::ensureString(obj, "summary", "");

bool thumbnailFound = false;
auto attachments = Json::requireArray(obj, "attachments");
for(auto attachmentRaw: attachments) {
auto attachmentObj = Json::requireObject(attachmentRaw);
bool isDefault = attachmentObj.value("isDefault").toBool(false);
if(isDefault) {
thumbnailFound = true;
pack.logoName = Json::requireString(attachmentObj, "title");
pack.logoUrl = Json::requireString(attachmentObj, "thumbnailUrl");
break;
}
}

if(!thumbnailFound) {
throw JSONValidationError(QString("Pack without an icon, skipping: %1").arg(pack.name));
}

auto authors = Json::requireArray(obj, "authors");
for(auto authorIter: authors) {
auto author = Json::requireObject(authorIter);
Flame::ModpackAuthor packAuthor;
packAuthor.name = Json::requireString(author, "name");
packAuthor.url = Json::requireString(author, "url");
pack.authors.append(packAuthor);
}
int defaultFileId = Json::requireInteger(obj, "defaultFileId");

bool found = false;
// check if there are some files before adding the pack
auto files = Json::requireArray(obj, "latestFiles");
for(auto fileIter: files) {
auto file = Json::requireObject(fileIter);
int id = Json::requireInteger(file, "id");

// NOTE: for now, ignore everything that's not the default...
if(id != defaultFileId) {
continue;
}

auto versionArray = Json::requireArray(file, "gameVersion");
if(versionArray.size() < 1) {
continue;
}

found = true;
break;
}
if(!found) {
throw JSONValidationError(QString("Pack with no good file, skipping: %1").arg(pack.name));
}
}

void Flame::loadIndexedPackVersions(Flame::IndexedPack & pack, QJsonArray & arr)
{
QVector<Flame::IndexedVersion> unsortedVersions;
for(auto versionIter: arr) {
auto version = Json::requireObject(versionIter);
Flame::IndexedVersion file;

file.addonId = pack.addonId;
file.fileId = Json::requireInteger(version, "id");
auto versionArray = Json::requireArray(version, "gameVersion");
if(versionArray.size() < 1) {
continue;
}

// pick the latest version supported
file.mcVersion = versionArray[0].toString();
file.version = Json::requireString(version, "displayName");
file.downloadUrl = Json::requireString(version, "downloadUrl");
unsortedVersions.append(file);
}

auto orderSortPredicate = [](const IndexedVersion & a, const IndexedVersion & b) -> bool
{
return a.fileId > b.fileId;
};
std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate);
pack.versions = unsortedVersions;
pack.versionsLoaded = true;
}
43 changes: 43 additions & 0 deletions api/logic/modplatform/flame/FlamePackIndex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <QList>
#include <QMetaType>
#include <QString>
#include <QVector>

#include "multimc_logic_export.h"

namespace Flame {

struct ModpackAuthor {
QString name;
QString url;
};

struct IndexedVersion {
int addonId;
int fileId;
QString version;
QString mcVersion;
QString downloadUrl;
};

struct IndexedPack
{
int addonId;
QString name;
QString description;
QList<ModpackAuthor> authors;
QString logoName;
QString logoUrl;
QString websiteUrl;

bool versionsLoaded = false;
QVector<IndexedVersion> versions;
};

MULTIMC_LOGIC_EXPORT void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
MULTIMC_LOGIC_EXPORT void loadIndexedPackVersions(IndexedPack & m, QJsonArray & arr);
}

Q_DECLARE_METATYPE(Flame::IndexedPack)
1 change: 0 additions & 1 deletion application/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ SET(MULTIMC_SOURCES
pages/modplatform/legacy_ftb/ListModel.h
pages/modplatform/legacy_ftb/ListModel.cpp

pages/modplatform/flame/FlameData.h
pages/modplatform/flame/FlameModel.cpp
pages/modplatform/flame/FlameModel.h
pages/modplatform/flame/FlamePage.cpp
Expand Down
38 changes: 0 additions & 38 deletions application/pages/modplatform/flame/FlameData.h

This file was deleted.

96 changes: 21 additions & 75 deletions application/pages/modplatform/flame/FlameModel.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "FlameModel.h"
#include "MultiMC.h"
#include <Json.h>

#include <MMCStrings.h>
#include <Version.h>
Expand Down Expand Up @@ -38,7 +39,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
return QString("INVALID INDEX %1").arg(pos);
}

Modpack pack = modpacks.at(pos);
IndexedPack pack = modpacks.at(pos);
if(role == Qt::DisplayRole)
{
return pack.name;
Expand Down Expand Up @@ -163,26 +164,26 @@ void ListModel::performPaginatedSearch()
"https://addons-ecs.forgesvc.net/api/v2/addon/search?"
"categoryId=0&"
"gameId=432&"
//"gameVersion=1.12.2&"
"index=%1&"
"pageSize=25&"
"searchFilter=%2&"
"sectionId=4471&"
"sort=0"
).arg(nextSearchOffset).arg(currentSearchTerm);
"sort=%3"
).arg(nextSearchOffset).arg(currentSearchTerm).arg(currentSort);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
jobPtr->start();
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed);
}

void ListModel::searchWithTerm(const QString& term)
void ListModel::searchWithTerm(const QString& term, int sort)
{
if(currentSearchTerm == term) {
if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) {
return;
}
currentSearchTerm = term;
currentSort = sort;
if(jobPtr) {
jobPtr->abort();
searchState = ResetRequested;
Expand Down Expand Up @@ -210,79 +211,24 @@ void Flame::ListModel::searchRequestFinished()
return;
}

QList<Modpack> newList;
auto objs = doc.array();
for(auto projectIter: objs) {
Modpack pack;
auto project = projectIter.toObject();
pack.addonId = project.value("id").toInt(0);
if (pack.addonId == 0) {
qWarning() << "Pack without an ID, skipping: " << pack.name;
continue;
}
pack.name = project.value("name").toString();
pack.websiteUrl = project.value("websiteUrl").toString();
pack.description = project.value("summary").toString();
bool thumbnailFound = false;
auto attachments = project.value("attachments").toArray();
for(auto attachmentIter: attachments) {
auto attachment = attachmentIter.toObject();
bool isDefault = attachment.value("isDefault").toBool(false);
if(isDefault) {
thumbnailFound = true;
pack.logoName = attachment.value("title").toString();
pack.logoUrl = attachment.value("thumbnailUrl").toString();
break;
}
}
if(!thumbnailFound) {
qWarning() << "Pack without an icon, skipping: " << pack.name;
continue;
}
auto authors = project.value("authors").toArray();
for(auto authorIter: authors) {
auto author = authorIter.toObject();
ModpackAuthor packAuthor;
packAuthor.name = author.value("name").toString();
packAuthor.url = author.value("url").toString();
pack.authors.append(packAuthor);
}
int defaultFileId = project.value("defaultFileId").toInt(0);
if(defaultFileId == 0) {
qWarning() << "Pack without default file, skipping: " << pack.name;
continue;
}
bool found = false;
auto files = project.value("latestFiles").toArray();
for(auto fileIter: files) {
auto file = fileIter.toObject();
int id = file.value("id").toInt(0);
// NOTE: for now, ignore everything that's not the default...
if(id != defaultFileId) {
continue;
}
pack.latestFile.addonId = pack.addonId;
pack.latestFile.fileId = id;
auto versionArray = file.value("gameVersion").toArray();
if(versionArray.size() < 1) {
continue;
}

// pick the latest version supported
pack.latestFile.mcVersion = versionArray[0].toString();
pack.latestFile.version = file.value("displayName").toString();
pack.latestFile.downloadUrl = file.value("downloadUrl").toString();
found = true;
break;
QList<Flame::IndexedPack> newList;
auto packs = doc.array();
for(auto packRaw : packs) {
auto packObj = packRaw.toObject();

Flame::IndexedPack pack;
try
{
Flame::loadIndexedPack(pack, packObj);
newList.append(pack);
}
if(!found) {
qWarning() << "Pack with no good file, skipping: " << pack.name;
catch(const JSONValidationError &e)
{
qWarning() << "Error while loading pack from CurseForge: " << e.cause();
continue;
}
pack.broken = false;
newList.append(pack);
}
if(objs.size() < 25) {
if(packs.size() < 25) {
searchState = Finished;
} else {
nextSearchOffset += 25;
Expand Down
7 changes: 4 additions & 3 deletions application/pages/modplatform/flame/FlameModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <functional>
#include <net/NetJob.h>

#include "FlameData.h"
#include <modplatform/flame/FlamePackIndex.h>

namespace Flame {

Expand All @@ -39,7 +39,7 @@ class ListModel : public QAbstractListModel
void fetchMore(const QModelIndex & parent) override;

void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
void searchWithTerm(const QString & term);
void searchWithTerm(const QString & term, const int sort);

private slots:
void performPaginatedSearch();
Expand All @@ -54,13 +54,14 @@ private slots:
void requestLogo(QString file, QString url);

private:
QList<Modpack> modpacks;
QList<IndexedPack> modpacks;
QStringList m_failedLogos;
QStringList m_loadingLogos;
LogoMap m_logoMap;
QMap<QString, LogoCallback> waitingCallbacks;

QString currentSearchTerm;
int currentSort = 0;
int nextSearchOffset = 0;
enum SearchState {
None,
Expand Down
Loading

0 comments on commit 1f8408c

Please sign in to comment.