From 878614ff68163bbc95cbfc35611765f21a83bfed Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 10 Dec 2022 00:52:50 -0700 Subject: [PATCH] feat: add a `ModUtils::validate` moves the reading of mod files into `ModUtils` namespace Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/DataPack.cpp | 2 - launcher/minecraft/mod/Mod.cpp | 10 ++ launcher/minecraft/mod/Mod.h | 3 + launcher/minecraft/mod/ModDetails.h | 6 +- .../mod/tasks/LocalDataPackParseTask.h | 5 +- .../minecraft/mod/tasks/LocalModParseTask.cpp | 153 +++++++++++------- .../minecraft/mod/tasks/LocalModParseTask.h | 19 +++ .../mod/tasks/LocalShaderPackParseTask copy.h | 0 .../mod/tasks/LocalShaderPackParseTask.h | 0 9 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h create mode 100644 launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h diff --git a/launcher/minecraft/mod/DataPack.cpp b/launcher/minecraft/mod/DataPack.cpp index 3f275160c..6c3332857 100644 --- a/launcher/minecraft/mod/DataPack.cpp +++ b/launcher/minecraft/mod/DataPack.cpp @@ -27,8 +27,6 @@ #include "Version.h" -#include "minecraft/mod/tasks/LocalDataPackParseTask.h" - // Values taken from: // https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22 static const QMap> s_pack_format_versions = { diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 39023f698..8b00354d8 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -43,6 +43,7 @@ #include "MetadataHandler.h" #include "Version.h" +#include "minecraft/mod/ModDetails.h" Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details() { @@ -68,6 +69,10 @@ void Mod::setMetadata(std::shared_ptr&& metadata) m_local_details.metadata = metadata; } +void Mod::setDetails(const ModDetails& details) { + m_local_details = details; +} + std::pair Mod::compare(const Resource& other, SortType type) const { auto cast_other = dynamic_cast(&other); @@ -190,3 +195,8 @@ void Mod::finishResolvingWithDetails(ModDetails&& details) if (metadata) setMetadata(std::move(metadata)); } + +bool Mod::valid() const +{ + return !m_local_details.mod_id.isEmpty(); +} \ No newline at end of file diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index f336bec4c..b6d264fef 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -68,6 +68,9 @@ public: void setStatus(ModStatus status); void setMetadata(std::shared_ptr&& metadata); void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared(metadata)); } + void setDetails(const ModDetails& details); + + bool valid() const override; [[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair override; [[nodiscard]] bool applyFilter(QRegularExpression filter) const override; diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index dd84b0a3f..176e4fc14 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -81,7 +81,7 @@ struct ModDetails ModDetails() = default; /** Metadata should be handled manually to properly set the mod status. */ - ModDetails(ModDetails& other) + ModDetails(const ModDetails& other) : mod_id(other.mod_id) , name(other.name) , version(other.version) @@ -92,7 +92,7 @@ struct ModDetails , status(other.status) {} - ModDetails& operator=(ModDetails& other) + ModDetails& operator=(const ModDetails& other) { this->mod_id = other.mod_id; this->name = other.name; @@ -106,7 +106,7 @@ struct ModDetails return *this; } - ModDetails& operator=(ModDetails&& other) + ModDetails& operator=(const ModDetails&& other) { this->mod_id = other.mod_id; this->name = other.name; diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h index ee64df461..9f6ece5cc 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h @@ -39,9 +39,10 @@ bool processFolder(DataPack& pack, ProcessingLevel level = ProcessingLevel::Full bool processMCMeta(DataPack& pack, QByteArray&& raw_data); -/** Checks whether a file is valid as a resource pack or not. */ +/** Checks whether a file is valid as a data pack or not. */ bool validate(QFileInfo file); -} // namespace ResourcePackUtils + +} // namespace DataPackUtils class LocalDataPackParseTask : public Task { Q_OBJECT diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 774f61145..e8fd39b6c 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -11,9 +11,10 @@ #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 @@ -283,35 +284,45 @@ ModDetails ReadLiteModInfo(QByteArray contents) return details; } -} // namespace +bool process(Mod& mod, ProcessingLevel level) { + 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 resource pack parse task!"; + return false; + } +} -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 processZIP(Mod& mod, ProcessingLevel level) { -void LocalModParseTask::processAsZip() -{ - 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("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 +341,134 @@ 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.readAll()); file.close(); zip.close(); - return; + + mod.setDetails(details); + return true; } zip.close(); + return false; // no valid mod found in archive } -void LocalModParseTask::processAsFolder() -{ - QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info")); - if (mcmod_info.isFile()) { +bool processFolder(Mod& mod, ProcessingLevel level) { + + 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() -{ - QuaZip zip(m_modFile.filePath()); +bool processLitemod(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("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); @@ -424,20 +476,11 @@ 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(); diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.h b/launcher/minecraft/mod/tasks/LocalModParseTask.h index 413eb2d18..c9512166a 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.h @@ -8,6 +8,25 @@ #include "tasks/Task.h" +namespace ModUtils { + +ModDetails ReadFabricModInfo(QByteArray contents); +ModDetails ReadQuiltModInfo(QByteArray contents); +ModDetails ReadForgeInfo(QByteArray contents); +ModDetails ReadLiteModInfo(QByteArray contents); + +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(Mod& mod, ProcessingLevel level = ProcessingLevel::Full); + +bool processZIP(Mod& mod, ProcessingLevel level = ProcessingLevel::Full); +bool processFolder(Mod& mod, ProcessingLevel level = ProcessingLevel::Full); +bool processLitemod(Mod& mod, ProcessingLevel level = ProcessingLevel::Full); + +/** Checks whether a file is valid as a mod or not. */ +bool validate(QFileInfo file); +} // namespace ModUtils + class LocalModParseTask : public Task { Q_OBJECT diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h new file mode 100644 index 000000000..e69de29bb diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h new file mode 100644 index 000000000..e69de29bb