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>
This commit is contained in:
parent
25e23e50ca
commit
878614ff68
@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
|
|
||||||
#include "minecraft/mod/tasks/LocalDataPackParseTask.h"
|
|
||||||
|
|
||||||
// Values taken from:
|
// Values taken from:
|
||||||
// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22
|
// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22
|
||||||
static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = {
|
static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = {
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
#include "MetadataHandler.h"
|
#include "MetadataHandler.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
|
#include "minecraft/mod/ModDetails.h"
|
||||||
|
|
||||||
Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details()
|
Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details()
|
||||||
{
|
{
|
||||||
@ -68,6 +69,10 @@ void Mod::setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata)
|
|||||||
m_local_details.metadata = metadata;
|
m_local_details.metadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mod::setDetails(const ModDetails& details) {
|
||||||
|
m_local_details = details;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const
|
std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const
|
||||||
{
|
{
|
||||||
auto cast_other = dynamic_cast<Mod const*>(&other);
|
auto cast_other = dynamic_cast<Mod const*>(&other);
|
||||||
@ -190,3 +195,8 @@ void Mod::finishResolvingWithDetails(ModDetails&& details)
|
|||||||
if (metadata)
|
if (metadata)
|
||||||
setMetadata(std::move(metadata));
|
setMetadata(std::move(metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mod::valid() const
|
||||||
|
{
|
||||||
|
return !m_local_details.mod_id.isEmpty();
|
||||||
|
}
|
@ -68,6 +68,9 @@ public:
|
|||||||
void setStatus(ModStatus status);
|
void setStatus(ModStatus status);
|
||||||
void setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata);
|
void setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata);
|
||||||
void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared<Metadata::ModStruct>(metadata)); }
|
void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared<Metadata::ModStruct>(metadata)); }
|
||||||
|
void setDetails(const ModDetails& details);
|
||||||
|
|
||||||
|
bool valid() const override;
|
||||||
|
|
||||||
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
||||||
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
||||||
|
@ -81,7 +81,7 @@ struct ModDetails
|
|||||||
ModDetails() = default;
|
ModDetails() = default;
|
||||||
|
|
||||||
/** Metadata should be handled manually to properly set the mod status. */
|
/** Metadata should be handled manually to properly set the mod status. */
|
||||||
ModDetails(ModDetails& other)
|
ModDetails(const ModDetails& other)
|
||||||
: mod_id(other.mod_id)
|
: mod_id(other.mod_id)
|
||||||
, name(other.name)
|
, name(other.name)
|
||||||
, version(other.version)
|
, version(other.version)
|
||||||
@ -92,7 +92,7 @@ struct ModDetails
|
|||||||
, status(other.status)
|
, status(other.status)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ModDetails& operator=(ModDetails& other)
|
ModDetails& operator=(const ModDetails& other)
|
||||||
{
|
{
|
||||||
this->mod_id = other.mod_id;
|
this->mod_id = other.mod_id;
|
||||||
this->name = other.name;
|
this->name = other.name;
|
||||||
@ -106,7 +106,7 @@ struct ModDetails
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModDetails& operator=(ModDetails&& other)
|
ModDetails& operator=(const ModDetails&& other)
|
||||||
{
|
{
|
||||||
this->mod_id = other.mod_id;
|
this->mod_id = other.mod_id;
|
||||||
this->name = other.name;
|
this->name = other.name;
|
||||||
|
@ -39,9 +39,10 @@ bool processFolder(DataPack& pack, ProcessingLevel level = ProcessingLevel::Full
|
|||||||
|
|
||||||
bool processMCMeta(DataPack& pack, QByteArray&& raw_data);
|
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);
|
bool validate(QFileInfo file);
|
||||||
} // namespace ResourcePackUtils
|
|
||||||
|
} // namespace DataPackUtils
|
||||||
|
|
||||||
class LocalDataPackParseTask : public Task {
|
class LocalDataPackParseTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
#include "minecraft/mod/ModDetails.h"
|
||||||
#include "settings/INIFile.h"
|
#include "settings/INIFile.h"
|
||||||
|
|
||||||
namespace {
|
namespace ModUtils {
|
||||||
|
|
||||||
// NEW format
|
// NEW format
|
||||||
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
|
||||||
@ -283,35 +284,45 @@ ModDetails ReadLiteModInfo(QByteArray contents)
|
|||||||
return details;
|
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)
|
bool processZIP(Mod& mod, ProcessingLevel level) {
|
||||||
: Task(nullptr, false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
|
|
||||||
{}
|
|
||||||
|
|
||||||
void LocalModParseTask::processAsZip()
|
ModDetails details;
|
||||||
{
|
|
||||||
QuaZip zip(m_modFile.filePath());
|
QuaZip zip(mod.fileinfo().filePath());
|
||||||
if (!zip.open(QuaZip::mdUnzip))
|
if (!zip.open(QuaZip::mdUnzip))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
QuaZipFile file(&zip);
|
QuaZipFile file(&zip);
|
||||||
|
|
||||||
if (zip.setCurrentFile("META-INF/mods.toml")) {
|
if (zip.setCurrentFile("META-INF/mods.toml")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadMCModTOML(file.readAll());
|
details = ReadMCModTOML(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
// to replace ${file.jarVersion} with the actual version, as needed
|
// 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 (zip.setCurrentFile("META-INF/MANIFEST.MF")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// quick and dirty line-by-line parser
|
// quick and dirty line-by-line parser
|
||||||
@ -330,93 +341,134 @@ void LocalModParseTask::processAsZip()
|
|||||||
manifestVersion = "NONE";
|
manifestVersion = "NONE";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details.version = manifestVersion;
|
details.version = manifestVersion;
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
mod.setDetails(details);
|
||||||
|
|
||||||
|
return true;
|
||||||
} else if (zip.setCurrentFile("mcmod.info")) {
|
} else if (zip.setCurrentFile("mcmod.info")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadMCModInfo(file.readAll());
|
details = ReadMCModInfo(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
} else if (zip.setCurrentFile("quilt.mod.json")) {
|
} else if (zip.setCurrentFile("quilt.mod.json")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadQuiltModInfo(file.readAll());
|
details = ReadQuiltModInfo(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
} else if (zip.setCurrentFile("fabric.mod.json")) {
|
} else if (zip.setCurrentFile("fabric.mod.json")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadFabricModInfo(file.readAll());
|
details = ReadFabricModInfo(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
} else if (zip.setCurrentFile("forgeversion.properties")) {
|
} else if (zip.setCurrentFile("forgeversion.properties")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadForgeInfo(file.readAll());
|
details = ReadForgeInfo(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip.close();
|
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"));
|
ModDetails details;
|
||||||
if (mcmod_info.isFile()) {
|
|
||||||
|
QFileInfo mcmod_info(FS::PathCombine(mod.fileinfo().filePath(), "mcmod.info"));
|
||||||
|
if (mcmod_info.exists() && mcmod_info.isFile()) {
|
||||||
QFile mcmod(mcmod_info.filePath());
|
QFile mcmod(mcmod_info.filePath());
|
||||||
if (!mcmod.open(QIODevice::ReadOnly))
|
if (!mcmod.open(QIODevice::ReadOnly))
|
||||||
return;
|
return false;
|
||||||
auto data = mcmod.readAll();
|
auto data = mcmod.readAll();
|
||||||
if (data.isEmpty() || data.isNull())
|
if (data.isEmpty() || data.isNull())
|
||||||
return;
|
return false;
|
||||||
m_result->details = ReadMCModInfo(data);
|
details = ReadMCModInfo(data);
|
||||||
}
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalModParseTask::processAsLitemod()
|
return false; // no valid mcmod.info file found
|
||||||
{
|
}
|
||||||
QuaZip zip(m_modFile.filePath());
|
|
||||||
|
bool processLitemod(Mod& mod, ProcessingLevel level) {
|
||||||
|
|
||||||
|
ModDetails details;
|
||||||
|
|
||||||
|
QuaZip zip(mod.fileinfo().filePath());
|
||||||
if (!zip.open(QuaZip::mdUnzip))
|
if (!zip.open(QuaZip::mdUnzip))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
QuaZipFile file(&zip);
|
QuaZipFile file(&zip);
|
||||||
|
|
||||||
if (zip.setCurrentFile("litemod.json")) {
|
if (zip.setCurrentFile("litemod.json")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result->details = ReadLiteModInfo(file.readAll());
|
details = ReadLiteModInfo(file.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
mod.setDetails(details);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
zip.close();
|
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()
|
bool LocalModParseTask::abort()
|
||||||
{
|
{
|
||||||
m_aborted.store(true);
|
m_aborted.store(true);
|
||||||
@ -425,19 +477,10 @@ bool LocalModParseTask::abort()
|
|||||||
|
|
||||||
void LocalModParseTask::executeTask()
|
void LocalModParseTask::executeTask()
|
||||||
{
|
{
|
||||||
switch (m_type) {
|
Mod mod{ m_modFile };
|
||||||
case ResourceType::ZIPFILE:
|
ModUtils::process(mod, ModUtils::ProcessingLevel::Full);
|
||||||
processAsZip();
|
|
||||||
break;
|
m_result->details = mod.details();
|
||||||
case ResourceType::FOLDER:
|
|
||||||
processAsFolder();
|
|
||||||
break;
|
|
||||||
case ResourceType::LITEMOD:
|
|
||||||
processAsLitemod();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_aborted)
|
if (m_aborted)
|
||||||
emit finished();
|
emit finished();
|
||||||
|
@ -8,6 +8,25 @@
|
|||||||
|
|
||||||
#include "tasks/Task.h"
|
#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
|
class LocalModParseTask : public Task
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Loading…
Reference in New Issue
Block a user