feat: add very early mod.toml packwiz support

Also use it as a on-disk format for storing mod metadata. This will be
used later on to make better mod managment.
This commit is contained in:
flow 2022-04-13 19:16:36 -03:00 committed by flow
parent dca4ea5cea
commit b30b88716e
No known key found for this signature in database
GPG Key ID: 8D0F221F0A59F469
8 changed files with 202 additions and 0 deletions

View File

@ -331,6 +331,8 @@ set(MINECRAFT_SOURCES
minecraft/mod/ModFolderLoadTask.cpp
minecraft/mod/LocalModParseTask.h
minecraft/mod/LocalModParseTask.cpp
minecraft/mod/LocalModUpdateTask.h
minecraft/mod/LocalModUpdateTask.cpp
minecraft/mod/ResourcePackFolderModel.h
minecraft/mod/ResourcePackFolderModel.cpp
minecraft/mod/TexturePackFolderModel.h
@ -543,6 +545,11 @@ set(MODPACKSCH_SOURCES
modplatform/modpacksch/FTBPackManifest.cpp
)
set(PACKWIZ_SOURCES
modplatform/packwiz/Packwiz.h
modplatform/packwiz/Packwiz.cpp
)
set(TECHNIC_SOURCES
modplatform/technic/SingleZipPackInstallTask.h
modplatform/technic/SingleZipPackInstallTask.cpp
@ -596,6 +603,7 @@ set(LOGIC_SOURCES
${FLAME_SOURCES}
${MODRINTH_SOURCES}
${MODPACKSCH_SOURCES}
${PACKWIZ_SOURCES}
${TECHNIC_SOURCES}
${ATLAUNCHER_SOURCES}
)

View File

@ -0,0 +1,32 @@
#include "LocalModUpdateTask.h"
#include <toml.h>
#include "FileSystem.h"
#include "modplatform/packwiz/Packwiz.h"
LocalModUpdateTask::LocalModUpdateTask(QDir mods_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version)
: m_mod(mod), m_mod_version(mod_version)
{
// Ensure a '.index' folder exists in the mods folder, and create it if it does not
m_index_dir = { QString("%1/.index").arg(mods_dir.absolutePath()) };
if (!FS::ensureFolderPathExists(m_index_dir.path())) {
emitFailed(QString("Unable to create index for mod %1!").arg(m_mod.name));
}
}
void LocalModUpdateTask::executeTask()
{
setStatus(tr("Updating index for mod:\n%1").arg(m_mod.name));
auto pw_mod = Packwiz::createModFormat(m_index_dir, m_mod, m_mod_version);
Packwiz::updateModIndex(m_index_dir, pw_mod);
emitSucceeded();
}
bool LocalModUpdateTask::abort()
{
emitAborted();
return true;
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <QDir>
#include "tasks/Task.h"
#include "modplatform/ModIndex.h"
class LocalModUpdateTask : public Task {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<LocalModUpdateTask>;
explicit LocalModUpdateTask(QDir mods_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version);
bool canAbort() const override { return true; }
bool abort() override;
protected slots:
//! Entry point for tasks.
void executeTask() override;
private:
QDir m_index_dir;
ModPlatform::IndexedPack& m_mod;
ModPlatform::IndexedVersion& m_mod_version;
};

View File

@ -8,6 +8,35 @@
namespace ModPlatform {
enum class Provider{
MODRINTH,
FLAME
};
class ProviderCapabilities {
public:
static QString hashType(Provider p)
{
switch(p){
case Provider::MODRINTH:
return "sha256";
case Provider::FLAME:
return "murmur2";
}
return "";
}
static QString providerName(Provider p)
{
switch(p){
case Provider::MODRINTH:
return "modrinth";
case Provider::FLAME:
return "curseforge";
}
return "";
}
};
struct ModpackAuthor {
QString name;
QString url;
@ -26,6 +55,7 @@ struct IndexedVersion {
struct IndexedPack {
QVariant addonId;
Provider provider;
QString name;
QString description;
QList<ModpackAuthor> authors;
@ -40,3 +70,4 @@ struct IndexedPack {
} // namespace ModPlatform
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
Q_DECLARE_METATYPE(ModPlatform::Provider)

View File

@ -9,6 +9,7 @@
void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
pack.addonId = Json::requireInteger(obj, "id");
pack.provider = ModPlatform::Provider::FLAME;
pack.name = Json::requireString(obj, "name");
pack.websiteUrl = Json::ensureString(Json::ensureObject(obj, "links"), "websiteUrl", "");
pack.description = Json::ensureString(obj, "summary", "");

View File

@ -28,6 +28,7 @@ static ModrinthAPI api;
void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
pack.addonId = Json::requireString(obj, "project_id");
pack.provider = ModPlatform::Provider::MODRINTH;
pack.name = Json::requireString(obj, "title");
QString slug = Json::ensureString(obj, "slug", "");

View File

@ -0,0 +1,60 @@
#include "Packwiz.h"
#include "modplatform/ModIndex.h"
#include <QDebug>
#include <QDir>
#include <QObject>
auto Packwiz::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> Mod
{
Mod mod;
mod.name = mod_pack.name;
mod.filename = mod_version.fileName;
mod.url = mod_version.downloadUrl;
mod.hash_format = ModPlatform::ProviderCapabilities::hashType(mod_pack.provider);
mod.hash = ""; // FIXME
mod.provider = mod_pack.provider;
mod.file_id = mod_pack.addonId;
mod.project_id = mod_version.fileId;
return mod;
}
void Packwiz::updateModIndex(QDir& index_dir, Mod& mod)
{
// Ensure the corresponding mod's info exists, and create it if not
auto index_file_name = QString("%1.toml").arg(mod.name);
QFile index_file(index_dir.absoluteFilePath(index_file_name));
// There's already data on there!
if (index_file.exists()) { index_file.remove(); }
if (!index_file.open(QIODevice::ReadWrite)) {
qCritical() << "Could not open file " << index_file_name << "!";
return;
}
// Put TOML data into the file
QTextStream in_stream(&index_file);
auto addToStream = [&in_stream](QString&& key, QString value) { in_stream << QString("%1 = \"%2\"\n").arg(key, value); };
{
addToStream("name", mod.name);
addToStream("filename", mod.filename);
addToStream("side", mod.side);
in_stream << QString("\n[download]\n");
addToStream("url", mod.url.toString());
addToStream("hash-format", mod.hash_format);
addToStream("hash", mod.hash);
in_stream << QString("\n[update]\n");
in_stream << QString("[update.%1]\n").arg(ModPlatform::ProviderCapabilities::providerName(mod.provider));
addToStream("file-id", mod.file_id.toString());
addToStream("project-id", mod.project_id.toString());
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <QString>
#include <QUrl>
#include <QVariant>
namespace ModPlatform {
enum class Provider;
class IndexedPack;
class IndexedVersion;
} // namespace ModPlatform
class QDir;
class Packwiz {
public:
struct Mod {
QString name;
QString filename;
// FIXME: make side an enum
QString side = "both";
// [download]
QUrl url;
// FIXME: make hash-format an enum
QString hash_format;
QString hash;
// [update]
ModPlatform::Provider provider;
QVariant file_id;
QVariant project_id;
};
/* Generates the object representing the information in a mod.toml file via its common representation in the launcher */
static auto createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> Mod;
/* Updates the mod index for the provided mod.
* This creates a new index if one does not exist already
* TODO: Ask the user if they want to override, and delete the old mod's files, or keep the old one.
* */
static void updateModIndex(QDir& index_dir, Mod& mod);
};