aboutsummaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@users.noreply.github.com>2021-05-15 00:36:46 +0200
committerGitHub <noreply@github.com>2021-05-15 00:36:46 +0200
commit911074e9669b6399df983a570c734018c2abd139 (patch)
tree3c7874efd20c41c3d479b47b110b4161be240e86 /api
parentb8cd13bb217c0fa556d55d0c4c0d8332c556036a (diff)
parente2e5294fb9930024c18f8def55ce79c7f7767f2c (diff)
downloadPrismLauncher-911074e9669b6399df983a570c734018c2abd139.tar.gz
PrismLauncher-911074e9669b6399df983a570c734018c2abd139.tar.bz2
PrismLauncher-911074e9669b6399df983a570c734018c2abd139.zip
Merge pull request #3735 from kumquat-ir/develop
NOISSUE Parse META-INF/mods.toml for Forge 1.14+ mod metadata
Diffstat (limited to 'api')
-rw-r--r--api/logic/CMakeLists.txt2
-rw-r--r--api/logic/minecraft/mod/LocalModParseTask.cpp171
2 files changed, 171 insertions, 2 deletions
diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt
index beaa0c00..91155ea7 100644
--- a/api/logic/CMakeLists.txt
+++ b/api/logic/CMakeLists.txt
@@ -540,7 +540,7 @@ set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISI
generate_export_header(MultiMC_logic)
# Link
-target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare BuildConfig)
+target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare tomlc99 BuildConfig)
target_link_libraries(MultiMC_logic Qt5::Core Qt5::Xml Qt5::Network Qt5::Concurrent)
# Mark and export headers
diff --git a/api/logic/minecraft/mod/LocalModParseTask.cpp b/api/logic/minecraft/mod/LocalModParseTask.cpp
index 22ebd7d4..0d6972fb 100644
--- a/api/logic/minecraft/mod/LocalModParseTask.cpp
+++ b/api/logic/minecraft/mod/LocalModParseTask.cpp
@@ -6,6 +6,7 @@
#include <QJsonValue>
#include <quazip.h>
#include <quazipfile.h>
+#include <toml.h>
#include "settings/INIFile.h"
#include "FileSystem.h"
@@ -90,6 +91,124 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents)
return nullptr;
}
+// https://github.com/MinecraftForge/Documentation/blob/5ab4ba6cf9abc0ac4c0abd96ad187461aefd72af/docs/gettingstarted/structuring.md
+std::shared_ptr<ModDetails> ReadMCModTOML(QByteArray contents)
+{
+ std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>();
+
+ char errbuf[200];
+ // top-level table
+ toml_table_t* tomlData = toml_parse(contents.data(), errbuf, sizeof(errbuf));
+
+ if(!tomlData)
+ {
+ return nullptr;
+ }
+
+ // array defined by [[mods]]
+ toml_array_t* tomlModsArr = toml_array_in(tomlData, "mods");
+ // 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);
+
+ // mandatory properties - always in [[mods]]
+ toml_datum_t modIdDatum = toml_string_in(tomlModsTable0, "modId");
+ if(modIdDatum.ok)
+ {
+ details->mod_id = modIdDatum.u.s;
+ // library says this is required for strings
+ free(modIdDatum.u.s);
+ }
+ toml_datum_t versionDatum = toml_string_in(tomlModsTable0, "version");
+ if(versionDatum.ok)
+ {
+ details->version = versionDatum.u.s;
+ free(versionDatum.u.s);
+ }
+ toml_datum_t displayNameDatum = toml_string_in(tomlModsTable0, "displayName");
+ if(displayNameDatum.ok)
+ {
+ details->name = displayNameDatum.u.s;
+ free(displayNameDatum.u.s);
+ }
+ toml_datum_t descriptionDatum = toml_string_in(tomlModsTable0, "description");
+ if(descriptionDatum.ok)
+ {
+ details->description = descriptionDatum.u.s;
+ 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)
+ {
+ authors = authorsDatum.u.s;
+ free(authorsDatum.u.s);
+ }
+ }
+ if(!authors.isEmpty())
+ {
+ // author information is stored as a string now, not a list
+ details->authors.append(authors);
+ }
+ // is credits even used anywhere? including this for completion/parity with old data version
+ toml_datum_t creditsDatum = toml_string_in(tomlData, "credits");
+ QString credits = "";
+ if(creditsDatum.ok)
+ {
+ authors = creditsDatum.u.s;
+ free(creditsDatum.u.s);
+ }
+ else
+ {
+ creditsDatum = toml_string_in(tomlModsTable0, "credits");
+ if(creditsDatum.ok)
+ {
+ credits = creditsDatum.u.s;
+ free(creditsDatum.u.s);
+ }
+ }
+ details->credits = credits;
+ 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)
+ {
+ homeurl = homeurlDatum.u.s;
+ free(homeurlDatum.u.s);
+ }
+ }
+ if(!homeurl.isEmpty())
+ {
+ // fix up url.
+ if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
+ {
+ homeurl.prepend("http://");
+ }
+ }
+ details->homeurl = homeurl;
+
+ // this seems to be recursive, so it should free everything
+ toml_free(tomlData);
+
+ return details;
+}
+
// https://fabricmc.net/wiki/documentation:fabric_mod_json
std::shared_ptr<ModDetails> ReadFabricModInfo(QByteArray contents)
{
@@ -198,7 +317,57 @@ void LocalModParseTask::processAsZip()
QuaZipFile file(&zip);
- if (zip.setCurrentFile("mcmod.info"))
+ if (zip.setCurrentFile("META-INF/mods.toml"))
+ {
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ zip.close();
+ return;
+ }
+
+ m_result->details = ReadMCModTOML(file.readAll());
+ file.close();
+
+ // to replace ${file.jarVersion} with the actual version, as needed
+ if (m_result->details && m_result->details->version == "${file.jarVersion}")
+ {
+ 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";
+ }
+
+ m_result->details->version = manifestVersion;
+
+ file.close();
+ }
+ }
+
+ zip.close();
+ return;
+ }
+ else if (zip.setCurrentFile("mcmod.info"))
{
if (!file.open(QIODevice::ReadOnly))
{