2019-08-04 02:27:53 +01:00
|
|
|
#include "LocalModParseTask.h"
|
|
|
|
|
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonValue>
|
2022-06-17 15:21:43 +01:00
|
|
|
#include <QString>
|
2022-01-24 21:55:57 +00:00
|
|
|
#include <quazip/quazip.h>
|
|
|
|
#include <quazip/quazipfile.h>
|
2021-04-17 17:46:11 +01:00
|
|
|
#include <toml.h>
|
2019-08-04 02:27:53 +01:00
|
|
|
|
2022-05-15 22:00:09 +01:00
|
|
|
#include "Json.h"
|
2019-08-04 02:27:53 +01:00
|
|
|
#include "settings/INIFile.h"
|
|
|
|
#include "FileSystem.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// NEW format
|
|
|
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
|
|
|
|
|
|
|
|
// OLD format:
|
|
|
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadMCModInfo(QByteArray contents)
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
auto getInfoFromArray = [&](QJsonArray arr) -> ModDetails
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
|
|
|
if (!arr.at(0).isObject()) {
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2019-08-04 02:27:53 +01:00
|
|
|
auto firstObj = arr.at(0).toObject();
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mod_id = firstObj.value("modid").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
auto name = firstObj.value("name").toString();
|
|
|
|
// NOTE: ignore stupid example mods copies where the author didn't even bother to change the name
|
|
|
|
if(name != "Example Mod") {
|
2022-08-12 21:06:20 +01:00
|
|
|
details.name = name;
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
details.version = firstObj.value("version").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
auto homeurl = firstObj.value("url").toString().trimmed();
|
|
|
|
if(!homeurl.isEmpty())
|
|
|
|
{
|
|
|
|
// fix up url.
|
|
|
|
if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
|
|
|
|
{
|
|
|
|
homeurl.prepend("http://");
|
|
|
|
}
|
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
details.homeurl = homeurl;
|
|
|
|
details.description = firstObj.value("description").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
QJsonArray authors = firstObj.value("authorList").toArray();
|
|
|
|
if (authors.size() == 0) {
|
|
|
|
// FIXME: what is the format of this? is there any?
|
|
|
|
authors = firstObj.value("authors").toArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto author: authors)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors.append(author.toString());
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
return details;
|
|
|
|
};
|
|
|
|
QJsonParseError jsonError;
|
|
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
|
|
|
// this is the very old format that had just the array
|
|
|
|
if (jsonDoc.isArray())
|
|
|
|
{
|
|
|
|
return getInfoFromArray(jsonDoc.array());
|
|
|
|
}
|
|
|
|
else if (jsonDoc.isObject())
|
|
|
|
{
|
|
|
|
auto val = jsonDoc.object().value("modinfoversion");
|
|
|
|
if(val.isUndefined()) {
|
|
|
|
val = jsonDoc.object().value("modListVersion");
|
|
|
|
}
|
2022-06-17 15:21:43 +01:00
|
|
|
|
|
|
|
int version = Json::ensureInteger(val, -1);
|
|
|
|
|
|
|
|
// Some mods set the number with "", so it's a String instead
|
|
|
|
if (version < 0)
|
|
|
|
version = Json::ensureString(val, "").toInt();
|
|
|
|
|
2019-08-04 02:27:53 +01:00
|
|
|
if (version != 2)
|
|
|
|
{
|
|
|
|
qCritical() << "BAD stuff happened to mod json:";
|
|
|
|
qCritical() << contents;
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
auto arrVal = jsonDoc.object().value("modlist");
|
|
|
|
if(arrVal.isUndefined()) {
|
|
|
|
arrVal = jsonDoc.object().value("modList");
|
|
|
|
}
|
|
|
|
if (arrVal.isArray())
|
|
|
|
{
|
|
|
|
return getInfoFromArray(arrVal.toArray());
|
|
|
|
}
|
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
|
2021-04-17 18:33:45 +01:00
|
|
|
// https://github.com/MinecraftForge/Documentation/blob/5ab4ba6cf9abc0ac4c0abd96ad187461aefd72af/docs/gettingstarted/structuring.md
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadMCModTOML(QByteArray contents)
|
2021-04-16 21:33:56 +01:00
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2021-04-16 21:33:56 +01:00
|
|
|
|
2021-04-17 18:33:45 +01:00
|
|
|
char errbuf[200];
|
|
|
|
// top-level table
|
|
|
|
toml_table_t* tomlData = toml_parse(contents.data(), errbuf, sizeof(errbuf));
|
|
|
|
|
|
|
|
if(!tomlData)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2021-04-17 18:33:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// array defined by [[mods]]
|
|
|
|
toml_array_t* tomlModsArr = toml_array_in(tomlData, "mods");
|
2021-11-06 21:42:10 +00:00
|
|
|
if(!tomlModsArr)
|
|
|
|
{
|
|
|
|
qWarning() << "Corrupted mods.toml? Couldn't find [[mods]] array!";
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2021-11-06 21:42:10 +00:00
|
|
|
}
|
|
|
|
|
2021-04-17 18:33:45 +01:00
|
|
|
// we only really care about the first element, since multiple mods in one file is not supported by us at the moment
|
|
|
|
toml_table_t* tomlModsTable0 = toml_table_at(tomlModsArr, 0);
|
2021-11-06 21:42:10 +00:00
|
|
|
if(!tomlModsTable0)
|
|
|
|
{
|
|
|
|
qWarning() << "Corrupted mods.toml? [[mods]] didn't have an element at index 0!";
|
2022-08-12 21:06:20 +01:00
|
|
|
return {};
|
2021-11-06 21:42:10 +00:00
|
|
|
}
|
2021-04-17 18:33:45 +01:00
|
|
|
|
|
|
|
// mandatory properties - always in [[mods]]
|
|
|
|
toml_datum_t modIdDatum = toml_string_in(tomlModsTable0, "modId");
|
|
|
|
if(modIdDatum.ok)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mod_id = modIdDatum.u.s;
|
2021-04-17 18:33:45 +01:00
|
|
|
// library says this is required for strings
|
|
|
|
free(modIdDatum.u.s);
|
|
|
|
}
|
|
|
|
toml_datum_t versionDatum = toml_string_in(tomlModsTable0, "version");
|
|
|
|
if(versionDatum.ok)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.version = versionDatum.u.s;
|
2021-04-17 18:33:45 +01:00
|
|
|
free(versionDatum.u.s);
|
|
|
|
}
|
|
|
|
toml_datum_t displayNameDatum = toml_string_in(tomlModsTable0, "displayName");
|
|
|
|
if(displayNameDatum.ok)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.name = displayNameDatum.u.s;
|
2021-04-17 18:33:45 +01:00
|
|
|
free(displayNameDatum.u.s);
|
|
|
|
}
|
|
|
|
toml_datum_t descriptionDatum = toml_string_in(tomlModsTable0, "description");
|
|
|
|
if(descriptionDatum.ok)
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.description = descriptionDatum.u.s;
|
2021-04-17 18:33:45 +01:00
|
|
|
free(descriptionDatum.u.s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// optional properties - can be in the root table or [[mods]]
|
|
|
|
toml_datum_t authorsDatum = toml_string_in(tomlData, "authors");
|
|
|
|
QString authors = "";
|
|
|
|
if(authorsDatum.ok)
|
|
|
|
{
|
|
|
|
authors = authorsDatum.u.s;
|
|
|
|
free(authorsDatum.u.s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
authorsDatum = toml_string_in(tomlModsTable0, "authors");
|
|
|
|
if(authorsDatum.ok)
|
2021-04-16 21:33:56 +01:00
|
|
|
{
|
2021-04-17 18:33:45 +01:00
|
|
|
authors = authorsDatum.u.s;
|
|
|
|
free(authorsDatum.u.s);
|
2021-04-16 21:33:56 +01:00
|
|
|
}
|
2021-04-17 18:33:45 +01:00
|
|
|
}
|
|
|
|
if(!authors.isEmpty())
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors.append(authors);
|
2021-04-17 18:33:45 +01:00
|
|
|
}
|
2022-04-16 02:07:35 +01:00
|
|
|
|
2021-04-17 18:33:45 +01:00
|
|
|
toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL");
|
|
|
|
QString homeurl = "";
|
|
|
|
if(homeurlDatum.ok)
|
|
|
|
{
|
|
|
|
homeurl = homeurlDatum.u.s;
|
|
|
|
free(homeurlDatum.u.s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
homeurlDatum = toml_string_in(tomlModsTable0, "displayURL");
|
|
|
|
if(homeurlDatum.ok)
|
2021-04-16 21:33:56 +01:00
|
|
|
{
|
2021-04-17 18:33:45 +01:00
|
|
|
homeurl = homeurlDatum.u.s;
|
|
|
|
free(homeurlDatum.u.s);
|
2021-04-16 21:33:56 +01:00
|
|
|
}
|
2021-04-17 18:33:45 +01:00
|
|
|
}
|
|
|
|
if(!homeurl.isEmpty())
|
|
|
|
{
|
|
|
|
// fix up url.
|
|
|
|
if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
|
2021-04-16 21:33:56 +01:00
|
|
|
{
|
2021-04-17 18:33:45 +01:00
|
|
|
homeurl.prepend("http://");
|
2021-04-16 21:33:56 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
details.homeurl = homeurl;
|
2021-04-17 18:33:45 +01:00
|
|
|
|
|
|
|
// this seems to be recursive, so it should free everything
|
|
|
|
toml_free(tomlData);
|
|
|
|
|
2021-04-16 21:33:56 +01:00
|
|
|
return details;
|
|
|
|
}
|
2021-04-17 18:33:45 +01:00
|
|
|
|
2019-08-04 02:27:53 +01:00
|
|
|
// https://fabricmc.net/wiki/documentation:fabric_mod_json
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadFabricModInfo(QByteArray contents)
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
|
|
|
QJsonParseError jsonError;
|
|
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
|
|
|
auto object = jsonDoc.object();
|
|
|
|
auto schemaVersion = object.contains("schemaVersion") ? object.value("schemaVersion").toInt(0) : 0;
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2019-08-04 02:27:53 +01:00
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mod_id = object.value("id").toString();
|
|
|
|
details.version = object.value("version").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
details.name = object.contains("name") ? object.value("name").toString() : details.mod_id;
|
|
|
|
details.description = object.value("description").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
|
|
|
|
if (schemaVersion >= 1)
|
|
|
|
{
|
|
|
|
QJsonArray authors = object.value("authors").toArray();
|
|
|
|
for (auto author: authors)
|
|
|
|
{
|
|
|
|
if(author.isObject()) {
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors.append(author.toObject().value("name").toString());
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
else {
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors.append(author.toString());
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object.contains("contact"))
|
|
|
|
{
|
|
|
|
QJsonObject contact = object.value("contact").toObject();
|
|
|
|
|
|
|
|
if (contact.contains("homepage"))
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.homeurl = contact.value("homepage").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
2022-05-17 14:17:20 +01:00
|
|
|
// https://github.com/QuiltMC/rfcs/blob/master/specification/0002-quilt.mod.json.md
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadQuiltModInfo(QByteArray contents)
|
2022-05-15 22:00:09 +01:00
|
|
|
{
|
|
|
|
QJsonParseError jsonError;
|
|
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
|
|
|
auto object = Json::requireObject(jsonDoc, "quilt.mod.json");
|
|
|
|
auto schemaVersion = Json::ensureInteger(object.value("schema_version"), 0, "Quilt schema_version");
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2022-05-15 22:00:09 +01:00
|
|
|
|
2022-05-17 14:17:20 +01:00
|
|
|
// https://github.com/QuiltMC/rfcs/blob/be6ba280d785395fefa90a43db48e5bfc1d15eb4/specification/0002-quilt.mod.json.md
|
2022-05-15 22:00:09 +01:00
|
|
|
if (schemaVersion == 1)
|
|
|
|
{
|
|
|
|
auto modInfo = Json::requireObject(object.value("quilt_loader"), "Quilt mod info");
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mod_id = Json::requireString(modInfo.value("id"), "Mod ID");
|
|
|
|
details.version = Json::requireString(modInfo.value("version"), "Mod version");
|
2022-05-15 22:00:09 +01:00
|
|
|
|
|
|
|
auto modMetadata = Json::ensureObject(modInfo.value("metadata"));
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
details.name = Json::ensureString(modMetadata.value("name"), details.mod_id);
|
|
|
|
details.description = Json::ensureString(modMetadata.value("description"));
|
2022-05-15 22:00:09 +01:00
|
|
|
|
|
|
|
auto modContributors = Json::ensureObject(modMetadata.value("contributors"));
|
|
|
|
|
|
|
|
// We don't really care about the role of a contributor here
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors += modContributors.keys();
|
2022-05-15 22:00:09 +01:00
|
|
|
|
|
|
|
auto modContact = Json::ensureObject(modMetadata.value("contact"));
|
|
|
|
|
|
|
|
if (modContact.contains("homepage"))
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.homeurl = Json::requireString(modContact.value("homepage"));
|
2022-05-15 22:00:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadForgeInfo(QByteArray contents)
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2019-08-04 02:27:53 +01:00
|
|
|
// Read the data
|
2022-08-12 21:06:20 +01:00
|
|
|
details.name = "Minecraft Forge";
|
|
|
|
details.mod_id = "Forge";
|
|
|
|
details.homeurl = "http://www.minecraftforge.net/forum/";
|
2019-08-04 02:27:53 +01:00
|
|
|
INIFile ini;
|
|
|
|
if (!ini.loadFile(contents))
|
|
|
|
return details;
|
|
|
|
|
|
|
|
QString major = ini.get("forge.major.number", "0").toString();
|
|
|
|
QString minor = ini.get("forge.minor.number", "0").toString();
|
|
|
|
QString revision = ini.get("forge.revision.number", "0").toString();
|
|
|
|
QString build = ini.get("forge.build.number", "0").toString();
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
details.version = major + "." + minor + "." + revision + "." + build;
|
2019-08-04 02:27:53 +01:00
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails ReadLiteModInfo(QByteArray contents)
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
ModDetails details;
|
2019-08-04 02:27:53 +01:00
|
|
|
QJsonParseError jsonError;
|
|
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
|
|
|
auto object = jsonDoc.object();
|
|
|
|
if (object.contains("name"))
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mod_id = details.name = object.value("name").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
if (object.contains("version"))
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.version = object.value("version").toString("");
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-12 21:06:20 +01:00
|
|
|
details.version = object.value("revision").toString("");
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
details.mcversion = object.value("mcversion").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
auto author = object.value("author").toString();
|
|
|
|
if(!author.isEmpty()) {
|
2022-08-12 21:06:20 +01:00
|
|
|
details.authors.append(author);
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|
2022-08-12 21:06:20 +01:00
|
|
|
details.description = object.value("description").toString();
|
|
|
|
details.homeurl = object.value("url").toString();
|
2019-08-04 02:27:53 +01:00
|
|
|
return details;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile):
|
|
|
|
Task(nullptr, false),
|
2019-08-04 02:27:53 +01:00
|
|
|
m_token(token),
|
|
|
|
m_type(type),
|
|
|
|
m_modFile(modFile),
|
|
|
|
m_result(new Result())
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
{}
|
2019-08-04 02:27:53 +01:00
|
|
|
|
|
|
|
void LocalModParseTask::processAsZip()
|
|
|
|
{
|
|
|
|
QuaZip zip(m_modFile.filePath());
|
|
|
|
if (!zip.open(QuaZip::mdUnzip))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QuaZipFile file(&zip);
|
|
|
|
|
2021-04-17 18:33:45 +01:00
|
|
|
if (zip.setCurrentFile("META-INF/mods.toml"))
|
2021-04-16 21:33:56 +01:00
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_result->details = ReadMCModTOML(file.readAll());
|
|
|
|
file.close();
|
2021-04-17 01:45:55 +01:00
|
|
|
|
|
|
|
// to replace ${file.jarVersion} with the actual version, as needed
|
2022-08-12 21:06:20 +01:00
|
|
|
if (m_result->details.version == "${file.jarVersion}")
|
2021-04-17 01:45:55 +01:00
|
|
|
{
|
|
|
|
if (zip.setCurrentFile("META-INF/MANIFEST.MF"))
|
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// quick and dirty line-by-line parser
|
|
|
|
auto manifestLines = file.readAll().split('\n');
|
|
|
|
QString manifestVersion = "";
|
|
|
|
for (auto &line : manifestLines)
|
|
|
|
{
|
|
|
|
if (QString(line).startsWith("Implementation-Version: "))
|
|
|
|
{
|
|
|
|
manifestVersion = QString(line).remove("Implementation-Version: ");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// some mods use ${projectversion} in their build.gradle, causing this mess to show up in MANIFEST.MF
|
|
|
|
// also keep with forge's behavior of setting the version to "NONE" if none is found
|
|
|
|
if (manifestVersion.contains("task ':jar' property 'archiveVersion'") || manifestVersion == "")
|
|
|
|
{
|
|
|
|
manifestVersion = "NONE";
|
|
|
|
}
|
|
|
|
|
2022-08-12 21:06:20 +01:00
|
|
|
m_result->details.version = manifestVersion;
|
2021-04-17 01:45:55 +01:00
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-16 21:33:56 +01:00
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
2021-04-17 18:33:45 +01:00
|
|
|
else if (zip.setCurrentFile("mcmod.info"))
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_result->details = ReadMCModInfo(file.readAll());
|
|
|
|
file.close();
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
2022-05-18 13:33:58 +01:00
|
|
|
else if (zip.setCurrentFile("quilt.mod.json"))
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-18 13:33:58 +01:00
|
|
|
m_result->details = ReadQuiltModInfo(file.readAll());
|
2019-08-04 02:27:53 +01:00
|
|
|
file.close();
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
2022-05-18 13:33:58 +01:00
|
|
|
else if (zip.setCurrentFile("fabric.mod.json"))
|
2022-05-15 22:00:09 +01:00
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-18 13:33:58 +01:00
|
|
|
m_result->details = ReadFabricModInfo(file.readAll());
|
2022-05-15 22:00:09 +01:00
|
|
|
file.close();
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
2019-08-04 02:27:53 +01:00
|
|
|
else if (zip.setCurrentFile("forgeversion.properties"))
|
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_result->details = ReadForgeInfo(file.readAll());
|
|
|
|
file.close();
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
zip.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalModParseTask::processAsFolder()
|
|
|
|
{
|
|
|
|
QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info"));
|
|
|
|
if (mcmod_info.isFile())
|
|
|
|
{
|
|
|
|
QFile mcmod(mcmod_info.filePath());
|
|
|
|
if (!mcmod.open(QIODevice::ReadOnly))
|
|
|
|
return;
|
|
|
|
auto data = mcmod.readAll();
|
|
|
|
if (data.isEmpty() || data.isNull())
|
|
|
|
return;
|
|
|
|
m_result->details = ReadMCModInfo(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalModParseTask::processAsLitemod()
|
|
|
|
{
|
|
|
|
QuaZip zip(m_modFile.filePath());
|
|
|
|
if (!zip.open(QuaZip::mdUnzip))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QuaZipFile file(&zip);
|
|
|
|
|
|
|
|
if (zip.setCurrentFile("litemod.json"))
|
|
|
|
{
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
{
|
|
|
|
zip.close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_result->details = ReadLiteModInfo(file.readAll());
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
zip.close();
|
|
|
|
}
|
|
|
|
|
2022-08-12 21:09:56 +01:00
|
|
|
bool LocalModParseTask::abort()
|
|
|
|
{
|
|
|
|
m_aborted = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
void LocalModParseTask::executeTask()
|
2019-08-04 02:27:53 +01:00
|
|
|
{
|
|
|
|
switch(m_type)
|
|
|
|
{
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
case ResourceType::ZIPFILE:
|
2019-08-04 02:27:53 +01:00
|
|
|
processAsZip();
|
|
|
|
break;
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
case ResourceType::FOLDER:
|
2019-08-04 02:27:53 +01:00
|
|
|
processAsFolder();
|
|
|
|
break;
|
refactor: move general code from mod model to its own model
This aims to continue decoupling other types of resources (e.g. resource
packs, shader packs, etc) from mods, so that we don't have to
continuously watch our backs for changes to one of them affecting the
others.
To do so, this creates a more general list model for resources, based on
the mods one, that allows you to extend it with functionality for other
resources.
I had to do some template and preprocessor stuff to get around the
QObject limitation of not allowing templated classes, so that's sadge :c
On the other hand, I tried cleaning up most general-purpose code in the
mod model, and added some documentation, because it looks nice :D
Signed-off-by: flow <flowlnlnln@gmail.com>
2022-08-09 05:58:22 +01:00
|
|
|
case ResourceType::LITEMOD:
|
2019-08-04 02:27:53 +01:00
|
|
|
processAsLitemod();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-08-12 21:09:56 +01:00
|
|
|
|
|
|
|
if (m_aborted)
|
|
|
|
emitAborted();
|
|
|
|
else
|
|
|
|
emitSucceeded();
|
2019-08-04 02:27:53 +01:00
|
|
|
}
|