aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
diff options
context:
space:
mode:
authorTrial97 <alexandru.tripon97@gmail.com>2023-05-31 20:12:12 +0300
committerTrial97 <alexandru.tripon97@gmail.com>2023-05-31 20:12:12 +0300
commit29c3dc40ef7f5b1fce5ab5970a39613d0f7f5089 (patch)
treece92f8a86d08531879105a16194a14391c0ae2ea /launcher/minecraft/mod/tasks/LocalModParseTask.cpp
parente8ee4497f77a571b305a48b70f84c8729b800859 (diff)
parent954d4d701a136e79c25b58f9680d26a555a6e6fe (diff)
downloadPrismLauncher-29c3dc40ef7f5b1fce5ab5970a39613d0f7f5089.tar.gz
PrismLauncher-29c3dc40ef7f5b1fce5ab5970a39613d0f7f5089.tar.bz2
PrismLauncher-29c3dc40ef7f5b1fce5ab5970a39613d0f7f5089.zip
Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into logdir
Diffstat (limited to 'launcher/minecraft/mod/tasks/LocalModParseTask.cpp')
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp207
1 files changed, 151 insertions, 56 deletions
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index 774f6114..5342d693 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
@@ -3,6 +3,7 @@
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <toml++/toml.h>
+#include <qdcss.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
@@ -11,12 +12,13 @@
#include "FileSystem.h"
#include "Json.h"
+#include "minecraft/mod/ModDetails.h"
#include "settings/INIFile.h"
-namespace {
+namespace ModUtils {
// NEW format
-// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
+// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/c8d8f1929aff9979e322af79a59ce81f3e02db6a
// OLD format:
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
@@ -73,10 +75,11 @@ ModDetails ReadMCModInfo(QByteArray contents)
version = Json::ensureString(val, "").toInt();
if (version != 2) {
- qCritical() << "BAD stuff happened to mod json:";
- qCritical() << contents;
- return {};
+ qWarning() << QString(R"(The value of 'modListVersion' is "%1" (expected "2")! The file may be corrupted.)").arg(version);
+ qWarning() << "The contents of 'mcmod.info' are as follows:";
+ qWarning() << contents;
}
+
auto arrVal = jsonDoc.object().value("modlist");
if (arrVal.isUndefined()) {
arrVal = jsonDoc.object().value("modList");
@@ -239,7 +242,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
return details;
}
-ModDetails ReadForgeInfo(QByteArray contents)
+ModDetails ReadForgeInfo(QString fileName)
{
ModDetails details;
// Read the data
@@ -247,7 +250,7 @@ ModDetails ReadForgeInfo(QByteArray contents)
details.mod_id = "Forge";
details.homeurl = "http://www.minecraftforge.net/forum/";
INIFile ini;
- if (!ini.loadFile(contents))
+ if (!ini.loadFile(fileName))
return details;
QString major = ini.get("forge.major.number", "0").toString();
@@ -283,35 +286,72 @@ ModDetails ReadLiteModInfo(QByteArray contents)
return details;
}
-} // namespace
+// https://git.sleeping.town/unascribed/NilLoader/src/commit/d7fc87b255fc31019ff90f80d45894927fac6efc/src/main/java/nilloader/api/NilMetadata.java#L64
+ModDetails ReadNilModInfo(QByteArray contents, QString fname)
+{
+ ModDetails details;
+
+ QDCSS cssData = QDCSS(contents);
+ auto name = cssData.get("@nilmod.name");
+ auto desc = cssData.get("@nilmod.description");
+ auto authors = cssData.get("@nilmod.authors");
-LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
- : Task(nullptr, false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
-{}
+ if (name->has_value()) {
+ details.name = name->value();
+ }
+ if (desc->has_value()) {
+ details.description = desc->value();
+ }
+ if (authors->has_value()) {
+ details.authors.append(authors->value());
+ }
+ details.version = cssData.get("@nilmod.version")->value_or("?");
+
+ details.mod_id = fname.remove(".nilmod.css");
+
+ return details;
+}
-void LocalModParseTask::processAsZip()
+bool process(Mod& mod, ProcessingLevel level)
{
- QuaZip zip(m_modFile.filePath());
+ switch (mod.type()) {
+ case ResourceType::FOLDER:
+ return processFolder(mod, level);
+ case ResourceType::ZIPFILE:
+ return processZIP(mod, level);
+ case ResourceType::LITEMOD:
+ return processLitemod(mod);
+ default:
+ qWarning() << "Invalid type for mod parse task!";
+ return false;
+ }
+}
+
+bool processZIP(Mod& mod, ProcessingLevel level)
+{
+ ModDetails details;
+
+ QuaZip zip(mod.fileinfo().filePath());
if (!zip.open(QuaZip::mdUnzip))
- return;
+ return false;
QuaZipFile file(&zip);
if (zip.setCurrentFile("META-INF/mods.toml")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadMCModTOML(file.readAll());
+ details = ReadMCModTOML(file.readAll());
file.close();
// to replace ${file.jarVersion} with the actual version, as needed
- if (m_result->details.version == "${file.jarVersion}") {
+ if (details.version == "${file.jarVersion}") {
if (zip.setCurrentFile("META-INF/MANIFEST.MF")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
// quick and dirty line-by-line parser
@@ -330,93 +370,157 @@ void LocalModParseTask::processAsZip()
manifestVersion = "NONE";
}
- m_result->details.version = manifestVersion;
+ details.version = manifestVersion;
file.close();
}
}
zip.close();
- return;
+ mod.setDetails(details);
+
+ return true;
} else if (zip.setCurrentFile("mcmod.info")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadMCModInfo(file.readAll());
+ details = ReadMCModInfo(file.readAll());
file.close();
zip.close();
- return;
+
+ mod.setDetails(details);
+ return true;
} else if (zip.setCurrentFile("quilt.mod.json")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadQuiltModInfo(file.readAll());
+ details = ReadQuiltModInfo(file.readAll());
file.close();
zip.close();
- return;
+
+ mod.setDetails(details);
+ return true;
} else if (zip.setCurrentFile("fabric.mod.json")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadFabricModInfo(file.readAll());
+ details = ReadFabricModInfo(file.readAll());
file.close();
zip.close();
- return;
+
+ mod.setDetails(details);
+ return true;
} else if (zip.setCurrentFile("forgeversion.properties")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadForgeInfo(file.readAll());
+ details = ReadForgeInfo(file.getFileName());
file.close();
zip.close();
- return;
+
+ mod.setDetails(details);
+ return true;
+ } else if (zip.setCurrentFile("META-INF/nil/mappings.json")) {
+ // nilloader uses the filename of the metadata file for the modid, so we can't know the exact filename
+ // thankfully, there is a good file to use as a canary so we don't look for nil meta all the time
+
+ QString foundNilMeta;
+ for (auto& fname : zip.getFileNameList()) {
+ // nilmods can shade nilloader to be able to run as a standalone agent - which includes nilloader's own meta file
+ if (fname.endsWith(".nilmod.css") && fname != "nilloader.nilmod.css") {
+ foundNilMeta = fname;
+ break;
+ }
+ }
+
+ if (zip.setCurrentFile(foundNilMeta)) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ zip.close();
+ return false;
+ }
+
+ details = ReadNilModInfo(file.readAll(), foundNilMeta);
+ file.close();
+ zip.close();
+
+ mod.setDetails(details);
+ return true;
+ }
}
zip.close();
+ return false; // no valid mod found in archive
}
-void LocalModParseTask::processAsFolder()
+bool processFolder(Mod& mod, ProcessingLevel level)
{
- QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info"));
- if (mcmod_info.isFile()) {
+ ModDetails details;
+
+ QFileInfo mcmod_info(FS::PathCombine(mod.fileinfo().filePath(), "mcmod.info"));
+ if (mcmod_info.exists() && mcmod_info.isFile()) {
QFile mcmod(mcmod_info.filePath());
if (!mcmod.open(QIODevice::ReadOnly))
- return;
+ return false;
auto data = mcmod.readAll();
if (data.isEmpty() || data.isNull())
- return;
- m_result->details = ReadMCModInfo(data);
+ return false;
+ details = ReadMCModInfo(data);
+
+ mod.setDetails(details);
+ return true;
}
+
+ return false; // no valid mcmod.info file found
}
-void LocalModParseTask::processAsLitemod()
+bool processLitemod(Mod& mod, ProcessingLevel level)
{
- QuaZip zip(m_modFile.filePath());
+ ModDetails details;
+
+ QuaZip zip(mod.fileinfo().filePath());
if (!zip.open(QuaZip::mdUnzip))
- return;
+ return false;
QuaZipFile file(&zip);
if (zip.setCurrentFile("litemod.json")) {
if (!file.open(QIODevice::ReadOnly)) {
zip.close();
- return;
+ return false;
}
- m_result->details = ReadLiteModInfo(file.readAll());
+ details = ReadLiteModInfo(file.readAll());
file.close();
+
+ mod.setDetails(details);
+ return true;
}
zip.close();
+
+ return false; // no valid litemod.json found in archive
+}
+
+/** Checks whether a file is valid as a mod or not. */
+bool validate(QFileInfo file)
+{
+ Mod mod{ file };
+ return ModUtils::process(mod, ProcessingLevel::BasicInfoOnly) && mod.valid();
}
+} // namespace ModUtils
+
+LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
+ : Task(nullptr, false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
+{}
+
bool LocalModParseTask::abort()
{
m_aborted.store(true);
@@ -425,19 +529,10 @@ bool LocalModParseTask::abort()
void LocalModParseTask::executeTask()
{
- switch (m_type) {
- case ResourceType::ZIPFILE:
- processAsZip();
- break;
- case ResourceType::FOLDER:
- processAsFolder();
- break;
- case ResourceType::LITEMOD:
- processAsLitemod();
- break;
- default:
- break;
- }
+ Mod mod{ m_modFile };
+ ModUtils::process(mod, ModUtils::ProcessingLevel::Full);
+
+ m_result->details = mod.details();
if (m_aborted)
emit finished();