From 64c51a70a3aa110131fb6ad0cabc07ccfdcbb1c0 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 9 Dec 2022 20:26:05 -0700 Subject: feat: add initial support for parseing datapacks Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 169 +++++++++++++++++++++ .../minecraft/mod/tasks/LocalDataPackParseTask.h | 64 ++++++++ .../mod/tasks/LocalResourcePackParseTask.cpp | 82 +++++++--- .../mod/tasks/LocalResourcePackParseTask.h | 8 +- .../mod/tasks/LocalTexturePackParseTask.cpp | 59 ++++--- .../mod/tasks/LocalTexturePackParseTask.h | 8 +- 6 files changed, 341 insertions(+), 49 deletions(-) create mode 100644 launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp create mode 100644 launcher/minecraft/mod/tasks/LocalDataPackParseTask.h (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp new file mode 100644 index 00000000..8bc8278b --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -0,0 +1,169 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "LocalDataPackParseTask.h" + +#include "FileSystem.h" +#include "Json.h" + +#include +#include +#include + +#include + +namespace DataPackUtils { + +bool process(DataPack& pack, ProcessingLevel level) +{ + switch (pack.type()) { + case ResourceType::FOLDER: + return DataPackUtils::processFolder(pack, level); + case ResourceType::ZIPFILE: + return DataPackUtils::processZIP(pack, level); + default: + qWarning() << "Invalid type for resource pack parse task!"; + return false; + } +} + +bool processFolder(DataPack& pack, ProcessingLevel level) +{ + Q_ASSERT(pack.type() == ResourceType::FOLDER); + + QFileInfo mcmeta_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.mcmeta")); + if (mcmeta_file_info.exists() && mcmeta_file_info.isFile()) { + QFile mcmeta_file(mcmeta_file_info.filePath()); + if (!mcmeta_file.open(QIODevice::ReadOnly)) + return false; // can't open mcmeta file + + auto data = mcmeta_file.readAll(); + + bool mcmeta_result = DataPackUtils::processMCMeta(pack, std::move(data)); + + mcmeta_file.close(); + if (!mcmeta_result) { + return false; // mcmeta invalid + } + } else { + return false; // mcmeta file isn't a valid file + } + + QFileInfo data_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "data")); + if (!data_dir_info.exists() || !data_dir_info.isDir()) { + return false; // data dir does not exists or isn't valid + } + + if (level == ProcessingLevel::BasicInfoOnly) { + return true; // only need basic info already checked + } + + return true; // all tests passed +} + +bool processZIP(DataPack& pack, ProcessingLevel level) +{ + Q_ASSERT(pack.type() == ResourceType::ZIPFILE); + + QuaZip zip(pack.fileinfo().filePath()); + if (!zip.open(QuaZip::mdUnzip)) + return false; // can't open zip file + + QuaZipFile file(&zip); + + if (zip.setCurrentFile("pack.mcmeta")) { + if (!file.open(QIODevice::ReadOnly)) { + qCritical() << "Failed to open file in zip."; + zip.close(); + return false; + } + + auto data = file.readAll(); + + bool mcmeta_result = DataPackUtils::processMCMeta(pack, std::move(data)); + + file.close(); + if (!mcmeta_result) { + return false; // mcmeta invalid + } + } else { + return false; // could not set pack.mcmeta as current file. + } + + QuaZipDir zipDir(&zip); + if (!zipDir.exists("/data")) { + return false; // data dir does not exists at zip root + } + + if (level == ProcessingLevel::BasicInfoOnly) { + zip.close(); + return true; // only need basic info already checked + } + + zip.close(); + + return true; +} + +// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta +bool processMCMeta(DataPack& pack, QByteArray&& raw_data) +{ + try { + auto json_doc = QJsonDocument::fromJson(raw_data); + auto pack_obj = Json::requireObject(json_doc.object(), "pack", {}); + + pack.setPackFormat(Json::ensureInteger(pack_obj, "pack_format", 0)); + pack.setDescription(Json::ensureString(pack_obj, "description", "")); + } catch (Json::JsonException& e) { + qWarning() << "JsonException: " << e.what() << e.cause(); + return false; + } + return true; +} + +bool validate(QFileInfo file) +{ + DataPack dp{ file }; + return DataPackUtils::process(dp, ProcessingLevel::BasicInfoOnly) && dp.valid(); +} + +} // namespace DataPackUtils + +LocalDataPackParseTask::LocalDataPackParseTask(int token, DataPack& dp) + : Task(nullptr, false), m_token(token), m_resource_pack(dp) +{} + +bool LocalDataPackParseTask::abort() +{ + m_aborted = true; + return true; +} + +void LocalDataPackParseTask::executeTask() +{ + if (!DataPackUtils::process(m_resource_pack)) + return; + + if (m_aborted) + emitAborted(); + else + emitSucceeded(); +} diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h new file mode 100644 index 00000000..ee64df46 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include "minecraft/mod/DataPack.h" + +#include "tasks/Task.h" + +namespace DataPackUtils { + +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(DataPack& pack, ProcessingLevel level = ProcessingLevel::Full); + +bool processZIP(DataPack& pack, ProcessingLevel level = ProcessingLevel::Full); +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. */ +bool validate(QFileInfo file); +} // namespace ResourcePackUtils + +class LocalDataPackParseTask : public Task { + Q_OBJECT + public: + LocalDataPackParseTask(int token, DataPack& rp); + + [[nodiscard]] bool canAbort() const override { return true; } + bool abort() override; + + void executeTask() override; + + [[nodiscard]] int token() const { return m_token; } + + private: + int m_token; + + DataPack& m_resource_pack; + + bool m_aborted = false; +}; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 6fd4b024..18d7383d 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -23,6 +23,7 @@ #include #include +#include #include @@ -32,58 +33,74 @@ bool process(ResourcePack& pack, ProcessingLevel level) { switch (pack.type()) { case ResourceType::FOLDER: - ResourcePackUtils::processFolder(pack, level); - return true; + return ResourcePackUtils::processFolder(pack, level); case ResourceType::ZIPFILE: - ResourcePackUtils::processZIP(pack, level); - return true; + return ResourcePackUtils::processZIP(pack, level); default: qWarning() << "Invalid type for resource pack parse task!"; return false; } } -void processFolder(ResourcePack& pack, ProcessingLevel level) +bool processFolder(ResourcePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); QFileInfo mcmeta_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.mcmeta")); - if (mcmeta_file_info.isFile()) { + if (mcmeta_file_info.exists() && mcmeta_file_info.isFile()) { QFile mcmeta_file(mcmeta_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return; + return false; // can't open mcmeta file auto data = mcmeta_file.readAll(); - ResourcePackUtils::processMCMeta(pack, std::move(data)); + bool mcmeta_result = ResourcePackUtils::processMCMeta(pack, std::move(data)); mcmeta_file.close(); + if (!mcmeta_result) { + return false; // mcmeta invalid + } + } else { + return false; // mcmeta file isn't a valid file } - if (level == ProcessingLevel::BasicInfoOnly) - return; + QFileInfo assets_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "assets")); + if (!assets_dir_info.exists() || !assets_dir_info.isDir()) { + return false; // assets dir does not exists or isn't valid + } + if (level == ProcessingLevel::BasicInfoOnly) { + return true; // only need basic info already checked + } + QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); - if (image_file_info.isFile()) { + if (image_file_info.exists() && image_file_info.isFile()) { QFile mcmeta_file(image_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return; + return false; // can't open pack.png file auto data = mcmeta_file.readAll(); - ResourcePackUtils::processPackPNG(pack, std::move(data)); + bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data)); mcmeta_file.close(); + if (!pack_png_result) { + return false; // pack.png invalid + } + } else { + return false; // pack.png does not exists or is not a valid file. } + + return true; // all tests passed } -void processZIP(ResourcePack& pack, ProcessingLevel level) +bool processZIP(ResourcePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); QuaZip zip(pack.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return; + return false; // can't open zip file QuaZipFile file(&zip); @@ -91,40 +108,57 @@ void processZIP(ResourcePack& pack, ProcessingLevel level) if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return; + return false; } auto data = file.readAll(); - ResourcePackUtils::processMCMeta(pack, std::move(data)); + bool mcmeta_result = ResourcePackUtils::processMCMeta(pack, std::move(data)); file.close(); + if (!mcmeta_result) { + return false; // mcmeta invalid + } + } else { + return false; // could not set pack.mcmeta as current file. + } + + QuaZipDir zipDir(&zip); + if (!zipDir.exists("/assets")) { + return false; // assets dir does not exists at zip root } if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return; + return true; // only need basic info already checked } if (zip.setCurrentFile("pack.png")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return; + return false; } auto data = file.readAll(); - ResourcePackUtils::processPackPNG(pack, std::move(data)); + bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data)); file.close(); + if (!pack_png_result) { + return false; // pack.png invalid + } + } else { + return false; // could not set pack.mcmeta as current file. } zip.close(); + + return true; } // https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta -void processMCMeta(ResourcePack& pack, QByteArray&& raw_data) +bool processMCMeta(ResourcePack& pack, QByteArray&& raw_data) { try { auto json_doc = QJsonDocument::fromJson(raw_data); @@ -134,17 +168,21 @@ void processMCMeta(ResourcePack& pack, QByteArray&& raw_data) pack.setDescription(Json::ensureString(pack_obj, "description", "")); } catch (Json::JsonException& e) { qWarning() << "JsonException: " << e.what() << e.cause(); + return false; } + return true; } -void processPackPNG(ResourcePack& pack, QByteArray&& raw_data) +bool processPackPNG(ResourcePack& pack, QByteArray&& raw_data) { auto img = QImage::fromData(raw_data); if (!img.isNull()) { pack.setImage(img); } else { qWarning() << "Failed to parse pack.png."; + return false; } + return true; } bool validate(QFileInfo file) diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h index 69dbd6ad..d0c24c2b 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h @@ -31,11 +31,11 @@ enum class ProcessingLevel { Full, BasicInfoOnly }; bool process(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processZIP(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processFolder(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processZIP(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processFolder(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processMCMeta(ResourcePack& pack, QByteArray&& raw_data); -void processPackPNG(ResourcePack& pack, QByteArray&& raw_data); +bool processMCMeta(ResourcePack& pack, QByteArray&& raw_data); +bool processPackPNG(ResourcePack& pack, QByteArray&& raw_data); /** Checks whether a file is valid as a resource pack or not. */ bool validate(QFileInfo file); diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp index adb19aca..e4492f12 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp @@ -32,18 +32,16 @@ bool process(TexturePack& pack, ProcessingLevel level) { switch (pack.type()) { case ResourceType::FOLDER: - TexturePackUtils::processFolder(pack, level); - return true; + return TexturePackUtils::processFolder(pack, level); case ResourceType::ZIPFILE: - TexturePackUtils::processZIP(pack, level); - return true; + return TexturePackUtils::processZIP(pack, level); default: qWarning() << "Invalid type for resource pack parse task!"; return false; } } -void processFolder(TexturePack& pack, ProcessingLevel level) +bool processFolder(TexturePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); @@ -51,39 +49,51 @@ void processFolder(TexturePack& pack, ProcessingLevel level) if (mcmeta_file_info.isFile()) { QFile mcmeta_file(mcmeta_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return; + return false; auto data = mcmeta_file.readAll(); - TexturePackUtils::processPackTXT(pack, std::move(data)); + bool packTXT_result = TexturePackUtils::processPackTXT(pack, std::move(data)); mcmeta_file.close(); + if (!packTXT_result) { + return false; + } + } else { + return false; } if (level == ProcessingLevel::BasicInfoOnly) - return; + return true; QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.isFile()) { QFile mcmeta_file(image_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return; + return false; auto data = mcmeta_file.readAll(); - TexturePackUtils::processPackPNG(pack, std::move(data)); + bool packPNG_result = TexturePackUtils::processPackPNG(pack, std::move(data)); mcmeta_file.close(); + if (!packPNG_result) { + return false; + } + } else { + return false; } + + return true; } -void processZIP(TexturePack& pack, ProcessingLevel level) +bool processZIP(TexturePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); QuaZip zip(pack.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return; + return false; QuaZipFile file(&zip); @@ -91,51 +101,62 @@ void processZIP(TexturePack& pack, ProcessingLevel level) if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return; + return false; } auto data = file.readAll(); - TexturePackUtils::processPackTXT(pack, std::move(data)); + bool packTXT_result = TexturePackUtils::processPackTXT(pack, std::move(data)); file.close(); + if (!packTXT_result) { + return false; + } } if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return; + return false; } if (zip.setCurrentFile("pack.png")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return; + return false; } auto data = file.readAll(); - TexturePackUtils::processPackPNG(pack, std::move(data)); + bool packPNG_result = TexturePackUtils::processPackPNG(pack, std::move(data)); file.close(); + if (!packPNG_result) { + return false; + } } zip.close(); + + return true; } -void processPackTXT(TexturePack& pack, QByteArray&& raw_data) +bool processPackTXT(TexturePack& pack, QByteArray&& raw_data) { pack.setDescription(QString(raw_data)); + return true; } -void processPackPNG(TexturePack& pack, QByteArray&& raw_data) +bool processPackPNG(TexturePack& pack, QByteArray&& raw_data) { auto img = QImage::fromData(raw_data); if (!img.isNull()) { pack.setImage(img); } else { qWarning() << "Failed to parse pack.png."; + return false; } + return true; } bool validate(QFileInfo file) diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h index 9f7aab75..1589f8cb 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h @@ -32,11 +32,11 @@ enum class ProcessingLevel { Full, BasicInfoOnly }; bool process(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full); -void processPackTXT(TexturePack& pack, QByteArray&& raw_data); -void processPackPNG(TexturePack& pack, QByteArray&& raw_data); +bool processPackTXT(TexturePack& pack, QByteArray&& raw_data); +bool processPackPNG(TexturePack& pack, QByteArray&& raw_data); /** Checks whether a file is valid as a texture pack or not. */ bool validate(QFileInfo file); -- cgit 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: 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 +- .../minecraft/mod/tasks/LocalDataPackParseTask.h | 5 +- launcher/minecraft/mod/tasks/LocalModParseTask.cpp | 153 +++++++++++++-------- launcher/minecraft/mod/tasks/LocalModParseTask.h | 19 +++ .../mod/tasks/LocalShaderPackParseTask copy.h | 0 .../minecraft/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 (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/DataPack.cpp b/launcher/minecraft/mod/DataPack.cpp index 3f275160..6c333285 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 39023f69..8b00354d 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 f336bec4..b6d264fe 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 dd84b0a3..176e4fc1 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 ee64df46..9f6ece5c 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 774f6114..e8fd39b6 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 413eb2d1..c9512166 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 00000000..e69de29b diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h new file mode 100644 index 00000000..e69de29b -- cgit From ccfe605920fba14d9e798bb26642d22ee45fe860 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 24 Dec 2022 11:22:06 -0700 Subject: feat: add shaderpack validation Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/ShaderPack.cpp | 39 +++++++ launcher/minecraft/mod/ShaderPack.h | 66 ++++++++++++ .../minecraft/mod/tasks/LocalDataPackParseTask.h | 2 +- .../mod/tasks/LocalResourcePackParseTask.cpp | 8 +- .../mod/tasks/LocalShaderPackParseTask copy.h | 0 .../mod/tasks/LocalShaderPackParseTask.cpp | 116 +++++++++++++++++++++ .../minecraft/mod/tasks/LocalShaderPackParseTask.h | 63 +++++++++++ 7 files changed, 289 insertions(+), 5 deletions(-) create mode 100644 launcher/minecraft/mod/ShaderPack.cpp create mode 100644 launcher/minecraft/mod/ShaderPack.h delete mode 100644 launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h create mode 100644 launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/ShaderPack.cpp b/launcher/minecraft/mod/ShaderPack.cpp new file mode 100644 index 00000000..b8d427c7 --- /dev/null +++ b/launcher/minecraft/mod/ShaderPack.cpp @@ -0,0 +1,39 @@ + +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ShaderPack.h" + +#include "minecraft/mod/tasks/LocalShaderPackParseTask.h" + + +void ShaderPack::setPackFormat(ShaderPackFormat new_format) +{ + QMutexLocker locker(&m_data_lock); + + + m_pack_format = new_format; +} + +bool ShaderPack::valid() const +{ + return m_pack_format != ShaderPackFormat::INVALID; +} diff --git a/launcher/minecraft/mod/ShaderPack.h b/launcher/minecraft/mod/ShaderPack.h new file mode 100644 index 00000000..e6ee0757 --- /dev/null +++ b/launcher/minecraft/mod/ShaderPack.h @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "Resource.h" + +/* Info: + * Currently For Optifine / Iris shader packs, + * could be expanded to support others should they exsist? + * + * This class and enum are mostly here as placeholders for validating + * that a shaderpack exsists and is in the right format, + * namely that they contain a folder named 'shaders'. + * + * In the technical sense it would be possible to parse files like `shaders/shaders.properties` + * to get information like the availble profiles but this is not all that usefull without more knoledge of the + * shader mod used to be able to change settings + * + */ + +#include + +enum ShaderPackFormat { + VALID, + INVALID +}; + +class ShaderPack : public Resource { + Q_OBJECT + public: + using Ptr = shared_qobject_ptr; + + [[nodiscard]] ShaderPackFormat packFormat() const { return m_pack_format; } + + ShaderPack(QObject* parent = nullptr) : Resource(parent) {} + ShaderPack(QFileInfo file_info) : Resource(file_info) {} + + /** Thread-safe. */ + void setPackFormat(ShaderPackFormat new_format); + + bool valid() const override; + + protected: + mutable QMutex m_data_lock; + + ShaderPackFormat m_pack_format = ShaderPackFormat::INVALID; +}; diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h index 9f6ece5c..54e3d398 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h @@ -47,7 +47,7 @@ bool validate(QFileInfo file); class LocalDataPackParseTask : public Task { Q_OBJECT public: - LocalDataPackParseTask(int token, DataPack& rp); + LocalDataPackParseTask(int token, DataPack& dp); [[nodiscard]] bool canAbort() const override { return true; } bool abort() override; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 18d7383d..2c41c9ae 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -75,15 +75,15 @@ bool processFolder(ResourcePack& pack, ProcessingLevel level) QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.exists() && image_file_info.isFile()) { - QFile mcmeta_file(image_file_info.filePath()); - if (!mcmeta_file.open(QIODevice::ReadOnly)) + QFile pack_png_file(image_file_info.filePath()); + if (!pack_png_file.open(QIODevice::ReadOnly)) return false; // can't open pack.png file - auto data = mcmeta_file.readAll(); + auto data = pack_png_file.readAll(); bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data)); - mcmeta_file.close(); + pack_png_file.close(); if (!pack_png_result) { return false; // pack.png invalid } diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask copy.h deleted file mode 100644 index e69de29b..00000000 diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp new file mode 100644 index 00000000..088853b9 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "LocalShaderPackParseTask.h" + +#include "FileSystem.h" + +#include +#include +#include + +namespace ShaderPackUtils { + +bool process(ShaderPack& pack, ProcessingLevel level) +{ + switch (pack.type()) { + case ResourceType::FOLDER: + return ShaderPackUtils::processFolder(pack, level); + case ResourceType::ZIPFILE: + return ShaderPackUtils::processZIP(pack, level); + default: + qWarning() << "Invalid type for shader pack parse task!"; + return false; + } +} + +bool processFolder(ShaderPack& pack, ProcessingLevel level) +{ + Q_ASSERT(pack.type() == ResourceType::FOLDER); + + QFileInfo shaders_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "shaders")); + if (!shaders_dir_info.exists() || !shaders_dir_info.isDir()) { + return false; // assets dir does not exists or isn't valid + } + pack.setPackFormat(ShaderPackFormat::VALID); + + if (level == ProcessingLevel::BasicInfoOnly) { + return true; // only need basic info already checked + } + + return true; // all tests passed +} + +bool processZIP(ShaderPack& pack, ProcessingLevel level) +{ + Q_ASSERT(pack.type() == ResourceType::ZIPFILE); + + QuaZip zip(pack.fileinfo().filePath()); + if (!zip.open(QuaZip::mdUnzip)) + return false; // can't open zip file + + QuaZipFile file(&zip); + + QuaZipDir zipDir(&zip); + if (!zipDir.exists("/shaders")) { + return false; // assets dir does not exists at zip root + } + pack.setPackFormat(ShaderPackFormat::VALID); + + if (level == ProcessingLevel::BasicInfoOnly) { + zip.close(); + return true; // only need basic info already checked + } + + zip.close(); + + return true; +} + + +bool validate(QFileInfo file) +{ + ShaderPack sp{ file }; + return ShaderPackUtils::process(sp, ProcessingLevel::BasicInfoOnly) && sp.valid(); +} + +} // namespace ShaderPackUtils + +LocalShaderPackParseTask::LocalShaderPackParseTask(int token, ShaderPack& sp) + : Task(nullptr, false), m_token(token), m_shader_pack(sp) +{} + +bool LocalShaderPackParseTask::abort() +{ + m_aborted = true; + return true; +} + +void LocalShaderPackParseTask::executeTask() +{ + if (!ShaderPackUtils::process(m_shader_pack)) + return; + + if (m_aborted) + emitAborted(); + else + emitSucceeded(); +} diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h index e69de29b..5d113508 100644 --- a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#pragma once + +#include +#include + +#include "minecraft/mod/ShaderPack.h" + +#include "tasks/Task.h" + +namespace ShaderPackUtils { + +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); + +bool processZIP(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processFolder(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); + +/** Checks whether a file is valid as a resource pack or not. */ +bool validate(QFileInfo file); +} // namespace ShaderPackUtils + +class LocalShaderPackParseTask : public Task { + Q_OBJECT + public: + LocalShaderPackParseTask(int token, ShaderPack& sp); + + [[nodiscard]] bool canAbort() const override { return true; } + bool abort() override; + + void executeTask() override; + + [[nodiscard]] int token() const { return m_token; } + + private: + int m_token; + + ShaderPack& m_shader_pack; + + bool m_aborted = false; +}; -- cgit From eb31a951a18287f943a1e3d021629dde8b73fd15 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 24 Dec 2022 15:58:24 -0700 Subject: feat: worldSave parsing and validation Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/WorldSave.cpp | 45 ++++++ launcher/minecraft/mod/WorldSave.h | 67 ++++++++ .../mod/tasks/LocalWorldSaveParseTask.cpp | 177 +++++++++++++++++++++ .../minecraft/mod/tasks/LocalWorldSaveParseTask.h | 62 ++++++++ 4 files changed, 351 insertions(+) create mode 100644 launcher/minecraft/mod/WorldSave.cpp create mode 100644 launcher/minecraft/mod/WorldSave.h create mode 100644 launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp create mode 100644 launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/WorldSave.cpp b/launcher/minecraft/mod/WorldSave.cpp new file mode 100644 index 00000000..9a626fc1 --- /dev/null +++ b/launcher/minecraft/mod/WorldSave.cpp @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "WorldSave.h" + +#include "minecraft/mod/tasks/LocalWorldSaveParseTask.h" + +void WorldSave::setSaveFormat(WorldSaveFormat new_save_format) +{ + QMutexLocker locker(&m_data_lock); + + + m_save_format = new_save_format; +} + +void WorldSave::setSaveDirName(QString dir_name) +{ + QMutexLocker locker(&m_data_lock); + + + m_save_dir_name = dir_name; +} + +bool WorldSave::valid() const +{ + return m_save_format != WorldSaveFormat::INVALID; +} \ No newline at end of file diff --git a/launcher/minecraft/mod/WorldSave.h b/launcher/minecraft/mod/WorldSave.h new file mode 100644 index 00000000..f48f42b9 --- /dev/null +++ b/launcher/minecraft/mod/WorldSave.h @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "Resource.h" + +#include + +class Version; + +enum WorldSaveFormat { + SINGLE, + MULTI, + INVALID +}; + +class WorldSave : public Resource { + Q_OBJECT + public: + using Ptr = shared_qobject_ptr; + + WorldSave(QObject* parent = nullptr) : Resource(parent) {} + WorldSave(QFileInfo file_info) : Resource(file_info) {} + + /** Gets the format of the save. */ + [[nodiscard]] WorldSaveFormat saveFormat() const { return m_save_format; } + /** Gets the name of the save dir (first found in multi mode). */ + [[nodiscard]] QString saveDirName() const { return m_save_dir_name; } + + /** Thread-safe. */ + void setSaveFormat(WorldSaveFormat new_save_format); + /** Thread-safe. */ + void setSaveDirName(QString dir_name); + + bool valid() const override; + + + protected: + mutable QMutex m_data_lock; + + /* The 'version' of a resource pack, as defined in the pack.mcmeta file. + * See https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta + */ + WorldSaveFormat m_save_format = WorldSaveFormat::INVALID; + + QString m_save_dir_name; + +}; diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp new file mode 100644 index 00000000..5405d308 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp @@ -0,0 +1,177 @@ + +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "LocalWorldSaveParseTask.h" + +#include "FileSystem.h" + +#include +#include +#include +#include +#include +#include + +namespace WorldSaveUtils { + +bool process(WorldSave& pack, ProcessingLevel level) +{ + switch (pack.type()) { + case ResourceType::FOLDER: + return WorldSaveUtils::processFolder(pack, level); + case ResourceType::ZIPFILE: + return WorldSaveUtils::processZIP(pack, level); + default: + qWarning() << "Invalid type for shader pack parse task!"; + return false; + } +} + + +static std::tuple contains_level_dat(QDir dir, bool saves = false) +{ + for(auto const& entry : dir.entryInfoList()) { + if (!entry.isDir()) { + continue; + } + if (!saves && entry.fileName() == "saves") { + return contains_level_dat(QDir(entry.filePath()), true); + } + QFileInfo level_dat(FS::PathCombine(entry.filePath(), "level.dat")); + if (level_dat.exists() && level_dat.isFile()) { + return std::make_tuple(true, entry.fileName(), saves); + } + } + return std::make_tuple(false, "", saves); +} + + +bool processFolder(WorldSave& save, ProcessingLevel level) +{ + Q_ASSERT(save.type() == ResourceType::FOLDER); + + auto [ found, save_dir_name, found_saves_dir ] = contains_level_dat(QDir(save.fileinfo().filePath())); + + if (!found) { + return false; + } + + save.setSaveDirName(save_dir_name); + + if (found_saves_dir) { + save.setSaveFormat(WorldSaveFormat::MULTI); + } else { + save.setSaveFormat(WorldSaveFormat::SINGLE); + } + + if (level == ProcessingLevel::BasicInfoOnly) { + return true; // only need basic info already checked + } + + // resurved for more intensive processing + + return true; // all tests passed +} + +static std::tuple contains_level_dat(QuaZip& zip) +{ + bool saves = false; + QuaZipDir zipDir(&zip); + if (zipDir.exists("/saves")) { + saves = true; + zipDir.cd("/saves"); + } + + for (auto const& entry : zipDir.entryList()) { + zipDir.cd(entry); + if (zipDir.exists("level.dat")) { + return std::make_tuple(true, entry, saves); + } + zipDir.cd(".."); + } + return std::make_tuple(false, "", saves); +} + +bool processZIP(WorldSave& save, ProcessingLevel level) +{ + Q_ASSERT(save.type() == ResourceType::ZIPFILE); + + QuaZip zip(save.fileinfo().filePath()); + if (!zip.open(QuaZip::mdUnzip)) + return false; // can't open zip file + + auto [ found, save_dir_name, found_saves_dir ] = contains_level_dat(zip); + + + if (!found) { + return false; + } + + save.setSaveDirName(save_dir_name); + + if (found_saves_dir) { + save.setSaveFormat(WorldSaveFormat::MULTI); + } else { + save.setSaveFormat(WorldSaveFormat::SINGLE); + } + + if (level == ProcessingLevel::BasicInfoOnly) { + zip.close(); + return true; // only need basic info already checked + } + + // resurved for more intensive processing + + zip.close(); + + return true; +} + + +bool validate(QFileInfo file) +{ + WorldSave sp{ file }; + return WorldSaveUtils::process(sp, ProcessingLevel::BasicInfoOnly) && sp.valid(); +} + +} // namespace WorldSaveUtils + +LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) + : Task(nullptr, false), m_token(token), m_save(save) +{} + +bool LocalWorldSaveParseTask::abort() +{ + m_aborted = true; + return true; +} + +void LocalWorldSaveParseTask::executeTask() +{ + if (!WorldSaveUtils::process(m_save)) + return; + + if (m_aborted) + emitAborted(); + else + emitSucceeded(); +} diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h new file mode 100644 index 00000000..44153735 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include "minecraft/mod/WorldSave.h" + +#include "tasks/Task.h" + +namespace WorldSaveUtils { + +enum class ProcessingLevel { Full, BasicInfoOnly }; + +bool process(WorldSave& save, ProcessingLevel level = ProcessingLevel::Full); + +bool processZIP(WorldSave& pack, ProcessingLevel level = ProcessingLevel::Full); +bool processFolder(WorldSave& pack, ProcessingLevel level = ProcessingLevel::Full); + +bool validate(QFileInfo file); + +} // namespace WorldSaveUtils + +class LocalWorldSaveParseTask : public Task { + Q_OBJECT + public: + LocalWorldSaveParseTask(int token, WorldSave& save); + + [[nodiscard]] bool canAbort() const override { return true; } + bool abort() override; + + void executeTask() override; + + [[nodiscard]] int token() const { return m_token; } + + private: + int m_token; + + WorldSave& m_save; + + bool m_aborted = false; +}; \ No newline at end of file -- cgit From a7c9b2f172754aa476a23deabe074a649cefdd11 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 24 Dec 2022 17:43:43 -0700 Subject: feat: validate world saves Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/CMakeLists.txt | 8 ++ launcher/minecraft/mod/ShaderPack.h | 2 +- launcher/minecraft/mod/WorldSave.h | 2 +- .../mod/tasks/LocalWorldSaveParseTask.cpp | 3 + tests/CMakeLists.txt | 6 ++ tests/DataPackParse_test.cpp | 7 +- tests/ShaderPackParse_test.cpp | 77 +++++++++++++++++ tests/WorldSaveParse_test.cpp | 94 +++++++++++++++++++++ tests/testdata/ShaderPackParse/shaderpack1.zip | Bin 0 -> 242 bytes .../shaderpack2/shaders/shaders.properties | 0 tests/testdata/ShaderPackParse/shaderpack3.zip | Bin 0 -> 128 bytes tests/testdata/WorldSaveParse/minecraft_save_1.zip | Bin 0 -> 184 bytes tests/testdata/WorldSaveParse/minecraft_save_2.zip | Bin 0 -> 352 bytes .../minecraft_save_3/world_3/level.dat | 0 .../minecraft_save_4/saves/world_4/level.dat | 0 15 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 tests/ShaderPackParse_test.cpp create mode 100644 tests/WorldSaveParse_test.cpp create mode 100644 tests/testdata/ShaderPackParse/shaderpack1.zip create mode 100644 tests/testdata/ShaderPackParse/shaderpack2/shaders/shaders.properties create mode 100644 tests/testdata/ShaderPackParse/shaderpack3.zip create mode 100644 tests/testdata/WorldSaveParse/minecraft_save_1.zip create mode 100644 tests/testdata/WorldSaveParse/minecraft_save_2.zip create mode 100644 tests/testdata/WorldSaveParse/minecraft_save_3/world_3/level.dat create mode 100644 tests/testdata/WorldSaveParse/minecraft_save_4/saves/world_4/level.dat (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index c12e6740..853e1c03 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -339,6 +339,10 @@ set(MINECRAFT_SOURCES minecraft/mod/ResourcePackFolderModel.cpp minecraft/mod/TexturePack.h minecraft/mod/TexturePack.cpp + minecraft/mod/ShaderPack.h + minecraft/mod/ShaderPack.cpp + minecraft/mod/WorldSave.h + minecraft/mod/WorldSave.cpp minecraft/mod/TexturePackFolderModel.h minecraft/mod/TexturePackFolderModel.cpp minecraft/mod/ShaderPackFolderModel.h @@ -355,6 +359,10 @@ set(MINECRAFT_SOURCES minecraft/mod/tasks/LocalResourcePackParseTask.cpp minecraft/mod/tasks/LocalTexturePackParseTask.h minecraft/mod/tasks/LocalTexturePackParseTask.cpp + minecraft/mod/tasks/LocalShaderPackParseTask.h + minecraft/mod/tasks/LocalShaderPackParseTask.cpp + minecraft/mod/tasks/LocalWorldSaveParseTask.h + minecraft/mod/tasks/LocalWorldSaveParseTask.cpp # Assets minecraft/AssetsUtils.h diff --git a/launcher/minecraft/mod/ShaderPack.h b/launcher/minecraft/mod/ShaderPack.h index e6ee0757..a0dad7a1 100644 --- a/launcher/minecraft/mod/ShaderPack.h +++ b/launcher/minecraft/mod/ShaderPack.h @@ -39,7 +39,7 @@ #include -enum ShaderPackFormat { +enum class ShaderPackFormat { VALID, INVALID }; diff --git a/launcher/minecraft/mod/WorldSave.h b/launcher/minecraft/mod/WorldSave.h index f48f42b9..f703f34c 100644 --- a/launcher/minecraft/mod/WorldSave.h +++ b/launcher/minecraft/mod/WorldSave.h @@ -27,7 +27,7 @@ class Version; -enum WorldSaveFormat { +enum class WorldSaveFormat { SINGLE, MULTI, INVALID diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp index 5405d308..b7f2420a 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp @@ -121,6 +121,9 @@ bool processZIP(WorldSave& save, ProcessingLevel level) auto [ found, save_dir_name, found_saves_dir ] = contains_level_dat(zip); + if (save_dir_name.endsWith("/")) { + save_dir_name.chop(1); + } if (!found) { return false; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be33b8db..9f84a9a7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,12 @@ ecm_add_test(TexturePackParse_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERS ecm_add_test(DataPackParse_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test TEST_NAME DataPackParse) +ecm_add_test(ShaderPackParse_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test + TEST_NAME ShaderPackParse) + +ecm_add_test(WorldSaveParse_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test + TEST_NAME WorldSaveParse) + ecm_add_test(ParseUtils_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test TEST_NAME ParseUtils) diff --git a/tests/DataPackParse_test.cpp b/tests/DataPackParse_test.cpp index 7307035f..61ce1e2b 100644 --- a/tests/DataPackParse_test.cpp +++ b/tests/DataPackParse_test.cpp @@ -1,7 +1,10 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// // SPDX-License-Identifier: GPL-3.0-only + /* - * PolyMC - Minecraft Launcher - * Copyright (c) 2022 flowln + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/tests/ShaderPackParse_test.cpp b/tests/ShaderPackParse_test.cpp new file mode 100644 index 00000000..7df105c6 --- /dev/null +++ b/tests/ShaderPackParse_test.cpp @@ -0,0 +1,77 @@ + +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include + +#include +#include + +class ShaderPackParseTest : public QObject { + Q_OBJECT + + private slots: + void test_parseZIP() + { + QString source = QFINDTESTDATA("testdata/ShaderPackParse"); + + QString zip_sp = FS::PathCombine(source, "shaderpack1.zip"); + ShaderPack pack { QFileInfo(zip_sp) }; + + bool valid = ShaderPackUtils::processZIP(pack); + + QVERIFY(pack.packFormat() == ShaderPackFormat::VALID); + QVERIFY(valid == true); + } + + void test_parseFolder() + { + QString source = QFINDTESTDATA("testdata/ShaderPackParse"); + + QString folder_sp = FS::PathCombine(source, "shaderpack2"); + ShaderPack pack { QFileInfo(folder_sp) }; + + bool valid = ShaderPackUtils::processFolder(pack); + + QVERIFY(pack.packFormat() == ShaderPackFormat::VALID); + QVERIFY(valid == true); + } + + void test_parseZIP2() + { + QString source = QFINDTESTDATA("testdata/ShaderPackParse"); + + QString folder_sp = FS::PathCombine(source, "shaderpack3.zip"); + ShaderPack pack { QFileInfo(folder_sp) }; + + bool valid = ShaderPackUtils::process(pack); + + QVERIFY(pack.packFormat() == ShaderPackFormat::INVALID); + QVERIFY(valid == false); + } +}; + +QTEST_GUILESS_MAIN(ShaderPackParseTest) + +#include "ShaderPackParse_test.moc" diff --git a/tests/WorldSaveParse_test.cpp b/tests/WorldSaveParse_test.cpp new file mode 100644 index 00000000..4a8c3d29 --- /dev/null +++ b/tests/WorldSaveParse_test.cpp @@ -0,0 +1,94 @@ + +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include + +#include +#include + +class WorldSaveParseTest : public QObject { + Q_OBJECT + + private slots: + void test_parseZIP() + { + QString source = QFINDTESTDATA("testdata/WorldSaveParse"); + + QString zip_ws = FS::PathCombine(source, "minecraft_save_1.zip") ; + WorldSave save { QFileInfo(zip_ws) }; + + bool valid = WorldSaveUtils::processZIP(save); + + QVERIFY(save.saveFormat() == WorldSaveFormat::SINGLE); + QVERIFY(save.saveDirName() == "world_1"); + QVERIFY(valid == true); + } + + void test_parse_ZIP2() + { + QString source = QFINDTESTDATA("testdata/WorldSaveParse"); + + QString zip_ws = FS::PathCombine(source, "minecraft_save_2.zip") ; + WorldSave save { QFileInfo(zip_ws) }; + + bool valid = WorldSaveUtils::processZIP(save); + + QVERIFY(save.saveFormat() == WorldSaveFormat::MULTI); + QVERIFY(save.saveDirName() == "world_2"); + QVERIFY(valid == true); + } + + void test_parseFolder() + { + QString source = QFINDTESTDATA("testdata/WorldSaveParse"); + + QString folder_ws = FS::PathCombine(source, "minecraft_save_3"); + WorldSave save { QFileInfo(folder_ws) }; + + bool valid = WorldSaveUtils::processFolder(save); + + QVERIFY(save.saveFormat() == WorldSaveFormat::SINGLE); + QVERIFY(save.saveDirName() == "world_3"); + QVERIFY(valid == true); + } + + void test_parseFolder2() + { + QString source = QFINDTESTDATA("testdata/WorldSaveParse"); + + QString folder_ws = FS::PathCombine(source, "minecraft_save_4"); + WorldSave save { QFileInfo(folder_ws) }; + + bool valid = WorldSaveUtils::process(save); + + QVERIFY(save.saveFormat() == WorldSaveFormat::MULTI); + QVERIFY(save.saveDirName() == "world_4"); + QVERIFY(valid == true); + } +}; + +QTEST_GUILESS_MAIN(WorldSaveParseTest) + +#include "WorldSaveParse_test.moc" diff --git a/tests/testdata/ShaderPackParse/shaderpack1.zip b/tests/testdata/ShaderPackParse/shaderpack1.zip new file mode 100644 index 00000000..9a8fb186 Binary files /dev/null and b/tests/testdata/ShaderPackParse/shaderpack1.zip differ diff --git a/tests/testdata/ShaderPackParse/shaderpack2/shaders/shaders.properties b/tests/testdata/ShaderPackParse/shaderpack2/shaders/shaders.properties new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/ShaderPackParse/shaderpack3.zip b/tests/testdata/ShaderPackParse/shaderpack3.zip new file mode 100644 index 00000000..dbec042d Binary files /dev/null and b/tests/testdata/ShaderPackParse/shaderpack3.zip differ diff --git a/tests/testdata/WorldSaveParse/minecraft_save_1.zip b/tests/testdata/WorldSaveParse/minecraft_save_1.zip new file mode 100644 index 00000000..832a243d Binary files /dev/null and b/tests/testdata/WorldSaveParse/minecraft_save_1.zip differ diff --git a/tests/testdata/WorldSaveParse/minecraft_save_2.zip b/tests/testdata/WorldSaveParse/minecraft_save_2.zip new file mode 100644 index 00000000..6c895176 Binary files /dev/null and b/tests/testdata/WorldSaveParse/minecraft_save_2.zip differ diff --git a/tests/testdata/WorldSaveParse/minecraft_save_3/world_3/level.dat b/tests/testdata/WorldSaveParse/minecraft_save_3/world_3/level.dat new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/WorldSaveParse/minecraft_save_4/saves/world_4/level.dat b/tests/testdata/WorldSaveParse/minecraft_save_4/saves/world_4/level.dat new file mode 100644 index 00000000..e69de29b -- cgit From cfce54fe46f7d3db39e50c4113cb9fc74d6719e2 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 24 Dec 2022 18:08:08 -0700 Subject: fix: update parse tests Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- .../minecraft/mod/tasks/LocalTexturePackParseTask.cpp | 2 +- launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h | 2 +- tests/ResourcePackParse_test.cpp | 9 ++++++--- tests/TexturePackParse_test.cpp | 9 ++++++--- .../ResourcePackParse/test_resource_pack_idk.zip | Bin 322 -> 804 bytes 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp index e4492f12..38f1d7c1 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp @@ -116,7 +116,7 @@ bool processZIP(TexturePack& pack, ProcessingLevel level) if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return false; + return true; } if (zip.setCurrentFile("pack.png")) { diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h index 44153735..aa5db0c2 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h @@ -37,7 +37,7 @@ bool process(WorldSave& save, ProcessingLevel level = ProcessingLevel::Full); bool processZIP(WorldSave& pack, ProcessingLevel level = ProcessingLevel::Full); bool processFolder(WorldSave& pack, ProcessingLevel level = ProcessingLevel::Full); -bool validate(QFileInfo file); +bool validate(QFileInfo file); } // namespace WorldSaveUtils diff --git a/tests/ResourcePackParse_test.cpp b/tests/ResourcePackParse_test.cpp index 568c3b63..4192da31 100644 --- a/tests/ResourcePackParse_test.cpp +++ b/tests/ResourcePackParse_test.cpp @@ -35,10 +35,11 @@ class ResourcePackParseTest : public QObject { QString zip_rp = FS::PathCombine(source, "test_resource_pack_idk.zip"); ResourcePack pack { QFileInfo(zip_rp) }; - ResourcePackUtils::processZIP(pack); + bool valid = ResourcePackUtils::processZIP(pack, ResourcePackUtils::ProcessingLevel::BasicInfoOnly); QVERIFY(pack.packFormat() == 3); QVERIFY(pack.description() == "um dois, feijão com arroz, três quatro, feijão no prato, cinco seis, café inglês, sete oito, comer biscoito, nove dez comer pastéis!!"); + QVERIFY(valid == true); } void test_parseFolder() @@ -48,10 +49,11 @@ class ResourcePackParseTest : public QObject { QString folder_rp = FS::PathCombine(source, "test_folder"); ResourcePack pack { QFileInfo(folder_rp) }; - ResourcePackUtils::processFolder(pack); + bool valid = ResourcePackUtils::processFolder(pack, ResourcePackUtils::ProcessingLevel::BasicInfoOnly); QVERIFY(pack.packFormat() == 1); QVERIFY(pack.description() == "Some resource pack maybe"); + QVERIFY(valid == true); } void test_parseFolder2() @@ -61,10 +63,11 @@ class ResourcePackParseTest : public QObject { QString folder_rp = FS::PathCombine(source, "another_test_folder"); ResourcePack pack { QFileInfo(folder_rp) }; - ResourcePackUtils::process(pack); + bool valid = ResourcePackUtils::process(pack, ResourcePackUtils::ProcessingLevel::BasicInfoOnly); QVERIFY(pack.packFormat() == 6); QVERIFY(pack.description() == "o quartel pegou fogo, policia deu sinal, acode acode acode a bandeira nacional"); + QVERIFY(valid == false); } }; diff --git a/tests/TexturePackParse_test.cpp b/tests/TexturePackParse_test.cpp index 0771f79f..4ddc0a3a 100644 --- a/tests/TexturePackParse_test.cpp +++ b/tests/TexturePackParse_test.cpp @@ -36,9 +36,10 @@ class TexturePackParseTest : public QObject { QString zip_rp = FS::PathCombine(source, "test_texture_pack_idk.zip"); TexturePack pack { QFileInfo(zip_rp) }; - TexturePackUtils::processZIP(pack); + bool valid = TexturePackUtils::processZIP(pack); QVERIFY(pack.description() == "joe biden, wake up"); + QVERIFY(valid == true); } void test_parseFolder() @@ -48,9 +49,10 @@ class TexturePackParseTest : public QObject { QString folder_rp = FS::PathCombine(source, "test_texturefolder"); TexturePack pack { QFileInfo(folder_rp) }; - TexturePackUtils::processFolder(pack); + bool valid = TexturePackUtils::processFolder(pack, TexturePackUtils::ProcessingLevel::BasicInfoOnly); QVERIFY(pack.description() == "Some texture pack surely"); + QVERIFY(valid == true); } void test_parseFolder2() @@ -60,9 +62,10 @@ class TexturePackParseTest : public QObject { QString folder_rp = FS::PathCombine(source, "another_test_texturefolder"); TexturePack pack { QFileInfo(folder_rp) }; - TexturePackUtils::process(pack); + bool valid = TexturePackUtils::process(pack, TexturePackUtils::ProcessingLevel::BasicInfoOnly); QVERIFY(pack.description() == "quieres\nfor real"); + QVERIFY(valid == true); } }; diff --git a/tests/testdata/ResourcePackParse/test_resource_pack_idk.zip b/tests/testdata/ResourcePackParse/test_resource_pack_idk.zip index 52b91cdc..b4e66a60 100644 Binary files a/tests/testdata/ResourcePackParse/test_resource_pack_idk.zip and b/tests/testdata/ResourcePackParse/test_resource_pack_idk.zip differ -- cgit From 3691f3a2963c77dbd7b469b4b90ca79b61014d43 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 26 Dec 2022 14:29:13 -0700 Subject: fix: cleanup and suggested changes Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/DataPack.cpp | 6 +-- launcher/minecraft/mod/DataPack.h | 8 +-- launcher/minecraft/mod/Mod.cpp | 2 +- launcher/minecraft/mod/ResourcePack.cpp | 11 ++-- launcher/minecraft/mod/ShaderPack.cpp | 2 - launcher/minecraft/mod/ShaderPack.h | 24 ++++----- launcher/minecraft/mod/WorldSave.cpp | 6 +-- launcher/minecraft/mod/WorldSave.h | 14 ++--- .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 46 ++++++++++------- .../minecraft/mod/tasks/LocalDataPackParseTask.h | 2 +- launcher/minecraft/mod/tasks/LocalModParseTask.cpp | 36 ++++++------- launcher/minecraft/mod/tasks/LocalModParseTask.h | 15 +++--- .../mod/tasks/LocalResourcePackParseTask.cpp | 60 ++++++++++++++-------- .../mod/tasks/LocalShaderPackParseTask.cpp | 23 ++++----- .../minecraft/mod/tasks/LocalShaderPackParseTask.h | 3 +- .../mod/tasks/LocalWorldSaveParseTask.cpp | 56 +++++++++++--------- .../minecraft/mod/tasks/LocalWorldSaveParseTask.h | 2 +- .../flame/FlameInstanceCreationTask.cpp | 43 ++++++++-------- tests/ResourcePackParse_test.cpp | 2 +- 19 files changed, 187 insertions(+), 174 deletions(-) (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/DataPack.cpp b/launcher/minecraft/mod/DataPack.cpp index ea1d097b..5c58f6b2 100644 --- a/launcher/minecraft/mod/DataPack.cpp +++ b/launcher/minecraft/mod/DataPack.cpp @@ -30,9 +30,9 @@ // Values taken from: // https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22 static const QMap> s_pack_format_versions = { - { 4, { Version("1.13"), Version("1.14.4") } }, { 5, { Version("1.15"), Version("1.16.1") } }, - { 6, { Version("1.16.2"), Version("1.16.5") } }, { 7, { Version("1.17"), Version("1.17.1") } }, - { 8, { Version("1.18"), Version("1.18.1") } }, { 9, { Version("1.18.2"), Version("1.18.2") } }, + { 4, { Version("1.13"), Version("1.14.4") } }, { 5, { Version("1.15"), Version("1.16.1") } }, + { 6, { Version("1.16.2"), Version("1.16.5") } }, { 7, { Version("1.17"), Version("1.17.1") } }, + { 8, { Version("1.18"), Version("1.18.1") } }, { 9, { Version("1.18.2"), Version("1.18.2") } }, { 10, { Version("1.19"), Version("1.19.3") } }, }; diff --git a/launcher/minecraft/mod/DataPack.h b/launcher/minecraft/mod/DataPack.h index 17d9b65e..fc2703c7 100644 --- a/launcher/minecraft/mod/DataPack.h +++ b/launcher/minecraft/mod/DataPack.h @@ -45,7 +45,7 @@ class DataPack : public Resource { /** Gets, respectively, the lower and upper versions supported by the set pack format. */ [[nodiscard]] std::pair compatibleVersions() const; - /** Gets the description of the resource pack. */ + /** Gets the description of the data pack. */ [[nodiscard]] QString description() const { return m_description; } /** Thread-safe. */ @@ -62,12 +62,12 @@ class DataPack : public Resource { protected: mutable QMutex m_data_lock; - /* The 'version' of a resource pack, as defined in the pack.mcmeta file. - * See https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta + /* The 'version' of a data pack, as defined in the pack.mcmeta file. + * See https://minecraft.fandom.com/wiki/Data_pack#pack.mcmeta */ int m_pack_format = 0; - /** The resource pack's description, as defined in the pack.mcmeta file. + /** The data pack's description, as defined in the pack.mcmeta file. */ QString m_description; }; diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 8b00354d..3439b6ee 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -199,4 +199,4 @@ void Mod::finishResolvingWithDetails(ModDetails&& details) bool Mod::valid() const { return !m_local_details.mod_id.isEmpty(); -} \ No newline at end of file +} diff --git a/launcher/minecraft/mod/ResourcePack.cpp b/launcher/minecraft/mod/ResourcePack.cpp index 87995215..876d5c3e 100644 --- a/launcher/minecraft/mod/ResourcePack.cpp +++ b/launcher/minecraft/mod/ResourcePack.cpp @@ -13,12 +13,11 @@ // Values taken from: // https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta static const QMap> s_pack_format_versions = { - { 1, { Version("1.6.1"), Version("1.8.9") } }, { 2, { Version("1.9"), Version("1.10.2") } }, - { 3, { Version("1.11"), Version("1.12.2") } }, { 4, { Version("1.13"), Version("1.14.4") } }, - { 5, { Version("1.15"), Version("1.16.1") } }, { 6, { Version("1.16.2"), Version("1.16.5") } }, - { 7, { Version("1.17"), Version("1.17.1") } }, { 8, { Version("1.18"), Version("1.18.2") } }, - { 9, { Version("1.19"), Version("1.19.2") } }, - // { 11, { Version("22w42a"), Version("22w44a") } } + { 1, { Version("1.6.1"), Version("1.8.9") } }, { 2, { Version("1.9"), Version("1.10.2") } }, + { 3, { Version("1.11"), Version("1.12.2") } }, { 4, { Version("1.13"), Version("1.14.4") } }, + { 5, { Version("1.15"), Version("1.16.1") } }, { 6, { Version("1.16.2"), Version("1.16.5") } }, + { 7, { Version("1.17"), Version("1.17.1") } }, { 8, { Version("1.18"), Version("1.18.2") } }, + { 9, { Version("1.19"), Version("1.19.2") } }, { 11, { Version("22w42a"), Version("22w44a") } }, { 12, { Version("1.19.3"), Version("1.19.3") } }, }; diff --git a/launcher/minecraft/mod/ShaderPack.cpp b/launcher/minecraft/mod/ShaderPack.cpp index b8d427c7..6a9641de 100644 --- a/launcher/minecraft/mod/ShaderPack.cpp +++ b/launcher/minecraft/mod/ShaderPack.cpp @@ -24,12 +24,10 @@ #include "minecraft/mod/tasks/LocalShaderPackParseTask.h" - void ShaderPack::setPackFormat(ShaderPackFormat new_format) { QMutexLocker locker(&m_data_lock); - m_pack_format = new_format; } diff --git a/launcher/minecraft/mod/ShaderPack.h b/launcher/minecraft/mod/ShaderPack.h index a0dad7a1..ec0f9404 100644 --- a/launcher/minecraft/mod/ShaderPack.h +++ b/launcher/minecraft/mod/ShaderPack.h @@ -24,31 +24,27 @@ #include "Resource.h" /* Info: - * Currently For Optifine / Iris shader packs, - * could be expanded to support others should they exsist? + * Currently For Optifine / Iris shader packs, + * could be expanded to support others should they exist? * - * This class and enum are mostly here as placeholders for validating - * that a shaderpack exsists and is in the right format, + * This class and enum are mostly here as placeholders for validating + * that a shaderpack exists and is in the right format, * namely that they contain a folder named 'shaders'. * - * In the technical sense it would be possible to parse files like `shaders/shaders.properties` - * to get information like the availble profiles but this is not all that usefull without more knoledge of the - * shader mod used to be able to change settings - * + * In the technical sense it would be possible to parse files like `shaders/shaders.properties` + * to get information like the available profiles but this is not all that useful without more knowledge of the + * shader mod used to be able to change settings. */ #include -enum class ShaderPackFormat { - VALID, - INVALID -}; +enum class ShaderPackFormat { VALID, INVALID }; class ShaderPack : public Resource { Q_OBJECT public: using Ptr = shared_qobject_ptr; - + [[nodiscard]] ShaderPackFormat packFormat() const { return m_pack_format; } ShaderPack(QObject* parent = nullptr) : Resource(parent) {} @@ -62,5 +58,5 @@ class ShaderPack : public Resource { protected: mutable QMutex m_data_lock; - ShaderPackFormat m_pack_format = ShaderPackFormat::INVALID; + ShaderPackFormat m_pack_format = ShaderPackFormat::INVALID; }; diff --git a/launcher/minecraft/mod/WorldSave.cpp b/launcher/minecraft/mod/WorldSave.cpp index 9a626fc1..7123f512 100644 --- a/launcher/minecraft/mod/WorldSave.cpp +++ b/launcher/minecraft/mod/WorldSave.cpp @@ -27,7 +27,6 @@ void WorldSave::setSaveFormat(WorldSaveFormat new_save_format) { QMutexLocker locker(&m_data_lock); - m_save_format = new_save_format; } @@ -35,11 +34,10 @@ void WorldSave::setSaveDirName(QString dir_name) { QMutexLocker locker(&m_data_lock); - m_save_dir_name = dir_name; } bool WorldSave::valid() const { - return m_save_format != WorldSaveFormat::INVALID; -} \ No newline at end of file + return m_save_format != WorldSaveFormat::INVALID; +} diff --git a/launcher/minecraft/mod/WorldSave.h b/launcher/minecraft/mod/WorldSave.h index f703f34c..5985fc8a 100644 --- a/launcher/minecraft/mod/WorldSave.h +++ b/launcher/minecraft/mod/WorldSave.h @@ -27,11 +27,7 @@ class Version; -enum class WorldSaveFormat { - SINGLE, - MULTI, - INVALID -}; +enum class WorldSaveFormat { SINGLE, MULTI, INVALID }; class WorldSave : public Resource { Q_OBJECT @@ -53,15 +49,13 @@ class WorldSave : public Resource { bool valid() const override; - protected: mutable QMutex m_data_lock; - /* The 'version' of a resource pack, as defined in the pack.mcmeta file. - * See https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta + /** The format in which the save file is in. + * Since saves can be distributed in various slightly different ways, this allows us to treat them separately. */ WorldSaveFormat m_save_format = WorldSaveFormat::INVALID; - QString m_save_dir_name; - + QString m_save_dir_name; }; diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 8bc8278b..3fcb2110 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -25,8 +25,8 @@ #include "Json.h" #include -#include #include +#include #include @@ -40,7 +40,7 @@ bool process(DataPack& pack, ProcessingLevel level) case ResourceType::ZIPFILE: return DataPackUtils::processZIP(pack, level); default: - qWarning() << "Invalid type for resource pack parse task!"; + qWarning() << "Invalid type for data pack parse task!"; return false; } } @@ -49,11 +49,16 @@ bool processFolder(DataPack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); + auto mcmeta_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + return false; // the mcmeta is not optional + }; + QFileInfo mcmeta_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.mcmeta")); if (mcmeta_file_info.exists() && mcmeta_file_info.isFile()) { QFile mcmeta_file(mcmeta_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return false; // can't open mcmeta file + return mcmeta_invalid(); // can't open mcmeta file auto data = mcmeta_file.readAll(); @@ -61,22 +66,22 @@ bool processFolder(DataPack& pack, ProcessingLevel level) mcmeta_file.close(); if (!mcmeta_result) { - return false; // mcmeta invalid + return mcmeta_invalid(); // mcmeta invalid } } else { - return false; // mcmeta file isn't a valid file + return mcmeta_invalid(); // mcmeta file isn't a valid file } QFileInfo data_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "data")); if (!data_dir_info.exists() || !data_dir_info.isDir()) { - return false; // data dir does not exists or isn't valid + return false; // data dir does not exists or isn't valid } if (level == ProcessingLevel::BasicInfoOnly) { - return true; // only need basic info already checked + return true; // only need basic info already checked } - return true; // all tests passed + return true; // all tests passed } bool processZIP(DataPack& pack, ProcessingLevel level) @@ -85,15 +90,20 @@ bool processZIP(DataPack& pack, ProcessingLevel level) QuaZip zip(pack.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return false; // can't open zip file + return false; // can't open zip file QuaZipFile file(&zip); + auto mcmeta_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + return false; // the mcmeta is not optional + }; + if (zip.setCurrentFile("pack.mcmeta")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return false; + return mcmeta_invalid(); } auto data = file.readAll(); @@ -102,20 +112,20 @@ bool processZIP(DataPack& pack, ProcessingLevel level) file.close(); if (!mcmeta_result) { - return false; // mcmeta invalid + return mcmeta_invalid(); // mcmeta invalid } } else { - return false; // could not set pack.mcmeta as current file. + return mcmeta_invalid(); // could not set pack.mcmeta as current file. } QuaZipDir zipDir(&zip); if (!zipDir.exists("/data")) { - return false; // data dir does not exists at zip root + return false; // data dir does not exists at zip root } if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return true; // only need basic info already checked + return true; // only need basic info already checked } zip.close(); @@ -123,7 +133,7 @@ bool processZIP(DataPack& pack, ProcessingLevel level) return true; } -// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta +// https://minecraft.fandom.com/wiki/Data_pack#pack.mcmeta bool processMCMeta(DataPack& pack, QByteArray&& raw_data) { try { @@ -147,9 +157,7 @@ bool validate(QFileInfo file) } // namespace DataPackUtils -LocalDataPackParseTask::LocalDataPackParseTask(int token, DataPack& dp) - : Task(nullptr, false), m_token(token), m_resource_pack(dp) -{} +LocalDataPackParseTask::LocalDataPackParseTask(int token, DataPack& dp) : Task(nullptr, false), m_token(token), m_data_pack(dp) {} bool LocalDataPackParseTask::abort() { @@ -159,7 +167,7 @@ bool LocalDataPackParseTask::abort() void LocalDataPackParseTask::executeTask() { - if (!DataPackUtils::process(m_resource_pack)) + if (!DataPackUtils::process(m_data_pack)) return; if (m_aborted) diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h index 54e3d398..12fd8c82 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h @@ -59,7 +59,7 @@ class LocalDataPackParseTask : public Task { private: int m_token; - DataPack& m_resource_pack; + DataPack& m_data_pack; bool m_aborted = false; }; diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index e8fd39b6..8bfe2c84 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -284,7 +284,8 @@ ModDetails ReadLiteModInfo(QByteArray contents) return details; } -bool process(Mod& mod, ProcessingLevel level) { +bool process(Mod& mod, ProcessingLevel level) +{ switch (mod.type()) { case ResourceType::FOLDER: return processFolder(mod, level); @@ -293,13 +294,13 @@ bool process(Mod& mod, ProcessingLevel level) { case ResourceType::LITEMOD: return processLitemod(mod); default: - qWarning() << "Invalid type for resource pack parse task!"; + qWarning() << "Invalid type for mod parse task!"; return false; } } -bool processZIP(Mod& mod, ProcessingLevel level) { - +bool processZIP(Mod& mod, ProcessingLevel level) +{ ModDetails details; QuaZip zip(mod.fileinfo().filePath()); @@ -316,7 +317,7 @@ bool processZIP(Mod& mod, ProcessingLevel level) { details = ReadMCModTOML(file.readAll()); file.close(); - + // to replace ${file.jarVersion} with the actual version, as needed if (details.version == "${file.jarVersion}") { if (zip.setCurrentFile("META-INF/MANIFEST.MF")) { @@ -347,7 +348,6 @@ bool processZIP(Mod& mod, ProcessingLevel level) { } } - zip.close(); mod.setDetails(details); @@ -403,11 +403,11 @@ bool processZIP(Mod& mod, ProcessingLevel level) { } zip.close(); - return false; // no valid mod found in archive + return false; // no valid mod found in archive } -bool processFolder(Mod& mod, ProcessingLevel level) { - +bool processFolder(Mod& mod, ProcessingLevel level) +{ ModDetails details; QFileInfo mcmod_info(FS::PathCombine(mod.fileinfo().filePath(), "mcmod.info")); @@ -424,13 +424,13 @@ bool processFolder(Mod& mod, ProcessingLevel level) { return true; } - return false; // no valid mcmod.info file found + return false; // no valid mcmod.info file found } -bool processLitemod(Mod& mod, ProcessingLevel level) { - +bool processLitemod(Mod& mod, ProcessingLevel level) +{ ModDetails details; - + QuaZip zip(mod.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) return false; @@ -451,24 +451,22 @@ bool processLitemod(Mod& mod, ProcessingLevel level) { } zip.close(); - return false; // no valid litemod.json found in archive + return false; // no valid litemod.json found in archive } /** Checks whether a file is valid as a mod or not. */ -bool validate(QFileInfo file) { - +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); @@ -476,7 +474,7 @@ bool LocalModParseTask::abort() } void LocalModParseTask::executeTask() -{ +{ Mod mod{ m_modFile }; ModUtils::process(mod, ModUtils::ProcessingLevel::Full); diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.h b/launcher/minecraft/mod/tasks/LocalModParseTask.h index c9512166..38dae135 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.h @@ -27,32 +27,29 @@ bool processLitemod(Mod& mod, ProcessingLevel level = ProcessingLevel::Full); bool validate(QFileInfo file); } // namespace ModUtils -class LocalModParseTask : public Task -{ +class LocalModParseTask : public Task { Q_OBJECT -public: + public: struct Result { ModDetails details; }; using ResultPtr = std::shared_ptr; - ResultPtr result() const { - return m_result; - } + ResultPtr result() const { return m_result; } [[nodiscard]] bool canAbort() const override { return true; } bool abort() override; - LocalModParseTask(int token, ResourceType type, const QFileInfo & modFile); + LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile); void executeTask() override; [[nodiscard]] int token() const { return m_token; } -private: + private: void processAsZip(); void processAsFolder(); void processAsLitemod(); -private: + private: int m_token; ResourceType m_type; QFileInfo m_modFile; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 2c41c9ae..4bf0b80d 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -22,8 +22,8 @@ #include "Json.h" #include -#include #include +#include #include @@ -46,11 +46,16 @@ bool processFolder(ResourcePack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); + auto mcmeta_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + return false; // the mcmeta is not optional + }; + QFileInfo mcmeta_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.mcmeta")); if (mcmeta_file_info.exists() && mcmeta_file_info.isFile()) { QFile mcmeta_file(mcmeta_file_info.filePath()); if (!mcmeta_file.open(QIODevice::ReadOnly)) - return false; // can't open mcmeta file + return mcmeta_invalid(); // can't open mcmeta file auto data = mcmeta_file.readAll(); @@ -58,26 +63,31 @@ bool processFolder(ResourcePack& pack, ProcessingLevel level) mcmeta_file.close(); if (!mcmeta_result) { - return false; // mcmeta invalid + return mcmeta_invalid(); // mcmeta invalid } } else { - return false; // mcmeta file isn't a valid file + return mcmeta_invalid(); // mcmeta file isn't a valid file } QFileInfo assets_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "assets")); if (!assets_dir_info.exists() || !assets_dir_info.isDir()) { - return false; // assets dir does not exists or isn't valid + return false; // assets dir does not exists or isn't valid } if (level == ProcessingLevel::BasicInfoOnly) { - return true; // only need basic info already checked + return true; // only need basic info already checked } - + + auto png_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png"; + return true; // the png is optional + }; + QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.exists() && image_file_info.isFile()) { QFile pack_png_file(image_file_info.filePath()); if (!pack_png_file.open(QIODevice::ReadOnly)) - return false; // can't open pack.png file + return png_invalid(); // can't open pack.png file auto data = pack_png_file.readAll(); @@ -85,13 +95,13 @@ bool processFolder(ResourcePack& pack, ProcessingLevel level) pack_png_file.close(); if (!pack_png_result) { - return false; // pack.png invalid + return png_invalid(); // pack.png invalid } } else { - return false; // pack.png does not exists or is not a valid file. + return png_invalid(); // pack.png does not exists or is not a valid file. } - return true; // all tests passed + return true; // all tests passed } bool processZIP(ResourcePack& pack, ProcessingLevel level) @@ -100,15 +110,20 @@ bool processZIP(ResourcePack& pack, ProcessingLevel level) QuaZip zip(pack.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return false; // can't open zip file + return false; // can't open zip file QuaZipFile file(&zip); + auto mcmeta_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + return false; // the mcmeta is not optional + }; + if (zip.setCurrentFile("pack.mcmeta")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return false; + return mcmeta_invalid(); } auto data = file.readAll(); @@ -117,27 +132,32 @@ bool processZIP(ResourcePack& pack, ProcessingLevel level) file.close(); if (!mcmeta_result) { - return false; // mcmeta invalid + return mcmeta_invalid(); // mcmeta invalid } } else { - return false; // could not set pack.mcmeta as current file. + return mcmeta_invalid(); // could not set pack.mcmeta as current file. } QuaZipDir zipDir(&zip); if (!zipDir.exists("/assets")) { - return false; // assets dir does not exists at zip root + return false; // assets dir does not exists at zip root } if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return true; // only need basic info already checked + return true; // only need basic info already checked } + auto png_invalid = [&pack]() { + qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png"; + return true; // the png is optional + }; + if (zip.setCurrentFile("pack.png")) { if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open file in zip."; zip.close(); - return false; + return png_invalid(); } auto data = file.readAll(); @@ -146,10 +166,10 @@ bool processZIP(ResourcePack& pack, ProcessingLevel level) file.close(); if (!pack_png_result) { - return false; // pack.png invalid + return png_invalid(); // pack.png invalid } } else { - return false; // could not set pack.mcmeta as current file. + return png_invalid(); // could not set pack.mcmeta as current file. } zip.close(); diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp index 088853b9..a9949735 100644 --- a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp @@ -24,8 +24,8 @@ #include "FileSystem.h" #include -#include #include +#include namespace ShaderPackUtils { @@ -45,18 +45,18 @@ bool process(ShaderPack& pack, ProcessingLevel level) bool processFolder(ShaderPack& pack, ProcessingLevel level) { Q_ASSERT(pack.type() == ResourceType::FOLDER); - + QFileInfo shaders_dir_info(FS::PathCombine(pack.fileinfo().filePath(), "shaders")); if (!shaders_dir_info.exists() || !shaders_dir_info.isDir()) { - return false; // assets dir does not exists or isn't valid + return false; // assets dir does not exists or isn't valid } pack.setPackFormat(ShaderPackFormat::VALID); if (level == ProcessingLevel::BasicInfoOnly) { - return true; // only need basic info already checked + return true; // only need basic info already checked } - - return true; // all tests passed + + return true; // all tests passed } bool processZIP(ShaderPack& pack, ProcessingLevel level) @@ -65,19 +65,19 @@ bool processZIP(ShaderPack& pack, ProcessingLevel level) QuaZip zip(pack.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return false; // can't open zip file + return false; // can't open zip file QuaZipFile file(&zip); QuaZipDir zipDir(&zip); if (!zipDir.exists("/shaders")) { - return false; // assets dir does not exists at zip root + return false; // assets dir does not exists at zip root } pack.setPackFormat(ShaderPackFormat::VALID); if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return true; // only need basic info already checked + return true; // only need basic info already checked } zip.close(); @@ -85,7 +85,6 @@ bool processZIP(ShaderPack& pack, ProcessingLevel level) return true; } - bool validate(QFileInfo file) { ShaderPack sp{ file }; @@ -94,9 +93,7 @@ bool validate(QFileInfo file) } // namespace ShaderPackUtils -LocalShaderPackParseTask::LocalShaderPackParseTask(int token, ShaderPack& sp) - : Task(nullptr, false), m_token(token), m_shader_pack(sp) -{} +LocalShaderPackParseTask::LocalShaderPackParseTask(int token, ShaderPack& sp) : Task(nullptr, false), m_token(token), m_shader_pack(sp) {} bool LocalShaderPackParseTask::abort() { diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h index 5d113508..6be2183c 100644 --- a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h @@ -19,7 +19,6 @@ * along with this program. If not, see . */ - #pragma once #include @@ -38,7 +37,7 @@ bool process(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); bool processZIP(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); bool processFolder(ShaderPack& pack, ProcessingLevel level = ProcessingLevel::Full); -/** Checks whether a file is valid as a resource pack or not. */ +/** Checks whether a file is valid as a shader pack or not. */ bool validate(QFileInfo file); } // namespace ShaderPackUtils diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp index b7f2420a..cbc8f8ce 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp @@ -24,12 +24,12 @@ #include "FileSystem.h" -#include -#include #include -#include #include -#include +#include + +#include +#include namespace WorldSaveUtils { @@ -41,15 +41,22 @@ bool process(WorldSave& pack, ProcessingLevel level) case ResourceType::ZIPFILE: return WorldSaveUtils::processZIP(pack, level); default: - qWarning() << "Invalid type for shader pack parse task!"; + qWarning() << "Invalid type for world save parse task!"; return false; } } - +/// @brief checks a folder structure to see if it contains a level.dat +/// @param dir the path to check +/// @param saves used in recursive call if a "saves" dir was found +/// @return std::tuple of ( +/// bool , +/// QString , +/// bool +/// ) static std::tuple contains_level_dat(QDir dir, bool saves = false) { - for(auto const& entry : dir.entryInfoList()) { + for (auto const& entry : dir.entryInfoList()) { if (!entry.isDir()) { continue; } @@ -64,12 +71,11 @@ static std::tuple contains_level_dat(QDir dir, bool saves = return std::make_tuple(false, "", saves); } - bool processFolder(WorldSave& save, ProcessingLevel level) { Q_ASSERT(save.type() == ResourceType::FOLDER); - auto [ found, save_dir_name, found_saves_dir ] = contains_level_dat(QDir(save.fileinfo().filePath())); + auto [found, save_dir_name, found_saves_dir] = contains_level_dat(QDir(save.fileinfo().filePath())); if (!found) { return false; @@ -84,14 +90,21 @@ bool processFolder(WorldSave& save, ProcessingLevel level) } if (level == ProcessingLevel::BasicInfoOnly) { - return true; // only need basic info already checked + return true; // only need basic info already checked } - // resurved for more intensive processing - - return true; // all tests passed + // reserved for more intensive processing + + return true; // all tests passed } +/// @brief checks a folder structure to see if it contains a level.dat +/// @param zip the zip file to check +/// @return std::tuple of ( +/// bool , +/// QString , +/// bool +/// ) static std::tuple contains_level_dat(QuaZip& zip) { bool saves = false; @@ -100,7 +113,7 @@ static std::tuple contains_level_dat(QuaZip& zip) saves = true; zipDir.cd("/saves"); } - + for (auto const& entry : zipDir.entryList()) { zipDir.cd(entry); if (zipDir.exists("level.dat")) { @@ -117,14 +130,14 @@ bool processZIP(WorldSave& save, ProcessingLevel level) QuaZip zip(save.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) - return false; // can't open zip file + return false; // can't open zip file - auto [ found, save_dir_name, found_saves_dir ] = contains_level_dat(zip); + auto [found, save_dir_name, found_saves_dir] = contains_level_dat(zip); if (save_dir_name.endsWith("/")) { save_dir_name.chop(1); } - + if (!found) { return false; } @@ -139,17 +152,16 @@ bool processZIP(WorldSave& save, ProcessingLevel level) if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); - return true; // only need basic info already checked + return true; // only need basic info already checked } - // resurved for more intensive processing + // reserved for more intensive processing zip.close(); return true; } - bool validate(QFileInfo file) { WorldSave sp{ file }; @@ -158,9 +170,7 @@ bool validate(QFileInfo file) } // namespace WorldSaveUtils -LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) - : Task(nullptr, false), m_token(token), m_save(save) -{} +LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) : Task(nullptr, false), m_token(token), m_save(save) {} bool LocalWorldSaveParseTask::abort() { diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h index aa5db0c2..9dcdca2b 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h @@ -59,4 +59,4 @@ class LocalWorldSaveParseTask : public Task { WorldSave& m_save; bool m_aborted = false; -}; \ No newline at end of file +}; diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index b62d05ab..79104e17 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -53,15 +53,16 @@ #include "ui/dialogs/BlockedModsDialog.h" #include "ui/dialogs/CustomMessageBox.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include "minecraft/World.h" +#include "minecraft/mod/tasks/LocalDataPackParseTask.h" +#include "minecraft/mod/tasks/LocalModParseTask.h" +#include "minecraft/mod/tasks/LocalResourcePackParseTask.h" +#include "minecraft/mod/tasks/LocalShaderPackParseTask.h" +#include "minecraft/mod/tasks/LocalTexturePackParseTask.h" +#include "minecraft/mod/tasks/LocalWorldSaveParseTask.h" const static QMap forgemap = { { "1.2.5", "3.4.9.171" }, { "1.4.2", "6.0.1.355" }, @@ -411,8 +412,7 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop) QList blocked_mods; auto anyBlocked = false; for (const auto& result : results.files.values()) { - - if(result.fileName.endsWith(".zip")) { + if (result.fileName.endsWith(".zip")) { m_ZIP_resources.append(std::make_pair(result.fileName, result.targetFolder)); } @@ -454,7 +454,6 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop) } } - void FlameCreationTask::setupDownloadJob(QEventLoop& loop) { m_files_job = new NetJob(tr("Mod download"), APPLICATION->network()); @@ -493,8 +492,8 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop) } m_mod_id_resolver.reset(); - connect(m_files_job.get(), &NetJob::succeeded, this, [&]() { - m_files_job.reset(); + connect(m_files_job.get(), &NetJob::succeeded, this, [&]() { + m_files_job.reset(); validateZIPResouces(); }); connect(m_files_job.get(), &NetJob::failed, [&](QString reason) { @@ -543,26 +542,26 @@ void FlameCreationTask::copyBlockedMods(QList const& blocked_mods) bool moveFile(QString src, QString dst) { if (!FS::copy(src, dst)()) { // copy - qDebug() << "Copy of" << src << "to" << dst << "Failed!"; + qDebug() << "Copy of" << src << "to" << dst << "failed!"; return false; } else { if (!FS::deletePath(src)) { // remove original - qDebug() << "Deleation of" << src << "Failed!"; + qDebug() << "Deletion of" << src << "failed!"; return false; }; } return true; } - void FlameCreationTask::validateZIPResouces() { - qDebug() << "Validating resoucres stored as .zip are in the right place"; + qDebug() << "Validating whether resources stored as .zip are in the right place"; for (auto [fileName, targetFolder] : m_ZIP_resources) { - qDebug() << "Checking" << fileName << "..."; auto localPath = FS::PathCombine(m_stagingPath, "minecraft", targetFolder, fileName); + /// @brief check the target and move the the file + /// @return path where file can now be found auto validatePath = [&localPath, this](QString fileName, QString targetFolder, QString realTarget) { if (targetFolder != realTarget) { qDebug() << "Target folder of" << fileName << "is incorrect, it belongs in" << realTarget; @@ -589,7 +588,7 @@ void FlameCreationTask::validateZIPResouces() } else if (ModUtils::validate(localFileInfo)) { qDebug() << fileName << "is a mod"; validatePath(fileName, targetFolder, "mods"); - } else if (WorldSaveUtils::validate(localFileInfo)) { + } else if (WorldSaveUtils::validate(localFileInfo)) { qDebug() << fileName << "is a world save"; QString worldPath = validatePath(fileName, targetFolder, "saves"); @@ -600,7 +599,7 @@ void FlameCreationTask::validateZIPResouces() qDebug() << "World at" << worldPath << "is not valid, skipping install."; } else { w.install(FS::PathCombine(m_stagingPath, "minecraft", "saves")); - } + } } else if (ShaderPackUtils::validate(localFileInfo)) { // in theroy flame API can't do this but who knows, that *may* change ? // better to handle it if it *does* occure in the future @@ -610,7 +609,7 @@ void FlameCreationTask::validateZIPResouces() qDebug() << "Can't Identify" << fileName << "at" << localPath << ", leaving it where it is."; } } else { - qDebug() << "Can't find" << localPath << "to validate it, ignoreing"; + qDebug() << "Can't find" << localPath << "to validate it, ignoring"; } } } diff --git a/tests/ResourcePackParse_test.cpp b/tests/ResourcePackParse_test.cpp index 4192da31..7f2f86bf 100644 --- a/tests/ResourcePackParse_test.cpp +++ b/tests/ResourcePackParse_test.cpp @@ -67,7 +67,7 @@ class ResourcePackParseTest : public QObject { QVERIFY(pack.packFormat() == 6); QVERIFY(pack.description() == "o quartel pegou fogo, policia deu sinal, acode acode acode a bandeira nacional"); - QVERIFY(valid == false); + QVERIFY(valid == false); // no assets dir } }; -- cgit From 7f438425aa84db51211123b47622a828be0aeb96 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 29 Dec 2022 19:47:19 -0700 Subject: refactor: add an `identify` function to make easy to reuse Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/CMakeLists.txt | 2 + .../minecraft/mod/tasks/LocalResourceParse.cpp | 60 +++++++++++++++++++ launcher/minecraft/mod/tasks/LocalResourceParse.h | 31 ++++++++++ .../flame/FlameInstanceCreationTask.cpp | 68 +++++++++++----------- 4 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 launcher/minecraft/mod/tasks/LocalResourceParse.cpp create mode 100644 launcher/minecraft/mod/tasks/LocalResourceParse.h (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 853e1c03..9826d543 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -363,6 +363,8 @@ set(MINECRAFT_SOURCES minecraft/mod/tasks/LocalShaderPackParseTask.cpp minecraft/mod/tasks/LocalWorldSaveParseTask.h minecraft/mod/tasks/LocalWorldSaveParseTask.cpp + minecraft/mod/tasks/LocalResourceParse.h + minecraft/mod/tasks/LocalResourceParse.cpp # Assets minecraft/AssetsUtils.h diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp new file mode 100644 index 00000000..244b2f54 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "LocalResourceParse.h" + +#include "LocalDataPackParseTask.h" +#include "LocalModParseTask.h" +#include "LocalResourcePackParseTask.h" +#include "LocalShaderPackParseTask.h" +#include "LocalTexturePackParseTask.h" +#include "LocalWorldSaveParseTask.h" + +namespace ResourceUtils { +PackedResourceType identify(QFileInfo file){ + if (file.exists() && file.isFile()) { + if (ResourcePackUtils::validate(file)) { + qDebug() << file.fileName() << "is a resource pack"; + return PackedResourceType::ResourcePack; + } else if (TexturePackUtils::validate(file)) { + qDebug() << file.fileName() << "is a pre 1.6 texture pack"; + return PackedResourceType::TexturePack; + } else if (DataPackUtils::validate(file)) { + qDebug() << file.fileName() << "is a data pack"; + return PackedResourceType::DataPack; + } else if (ModUtils::validate(file)) { + qDebug() << file.fileName() << "is a mod"; + return PackedResourceType::Mod; + } else if (WorldSaveUtils::validate(file)) { + qDebug() << file.fileName() << "is a world save"; + return PackedResourceType::WorldSave; + } else if (ShaderPackUtils::validate(file)) { + qDebug() << file.fileName() << "is a shader pack"; + return PackedResourceType::ShaderPack; + } else { + qDebug() << "Can't Identify" << file.fileName() ; + } + } else { + qDebug() << "Can't find" << file.absolutePath(); + } + return PackedResourceType::UNKNOWN; +} +} \ No newline at end of file diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.h b/launcher/minecraft/mod/tasks/LocalResourceParse.h new file mode 100644 index 00000000..b3e2829d --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +enum class PackedResourceType { DataPack, ResourcePack, TexturePack, ShaderPack, WorldSave, Mod, UNKNOWN }; +namespace ResourceUtils { +PackedResourceType identify(QFileInfo file); +} // namespace ResourceUtils \ No newline at end of file diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 0a91879d..dc69769a 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -57,12 +57,8 @@ #include #include "minecraft/World.h" -#include "minecraft/mod/tasks/LocalDataPackParseTask.h" -#include "minecraft/mod/tasks/LocalModParseTask.h" -#include "minecraft/mod/tasks/LocalResourcePackParseTask.h" -#include "minecraft/mod/tasks/LocalShaderPackParseTask.h" -#include "minecraft/mod/tasks/LocalTexturePackParseTask.h" -#include "minecraft/mod/tasks/LocalWorldSaveParseTask.h" +#include "minecraft/mod/tasks/LocalResourceParse.h" + const static QMap forgemap = { { "1.2.5", "3.4.9.171" }, { "1.4.2", "6.0.1.355" }, @@ -561,42 +557,48 @@ void FlameCreationTask::validateZIPResouces() return localPath; }; + auto installWorld = [this](QString worldPath){ + qDebug() << "Installing World from" << worldPath; + QFileInfo worldFileInfo(worldPath); + World w(worldFileInfo); + if (!w.isValid()) { + qDebug() << "World at" << worldPath << "is not valid, skipping install."; + } else { + w.install(FS::PathCombine(m_stagingPath, "minecraft", "saves")); + } + }; + QFileInfo localFileInfo(localPath); - if (localFileInfo.exists() && localFileInfo.isFile()) { - if (ResourcePackUtils::validate(localFileInfo)) { - qDebug() << fileName << "is a resource pack"; + auto type = ResourceUtils::identify(localFileInfo); + + QString worldPath; + + switch (type) { + case PackedResourceType::ResourcePack : validatePath(fileName, targetFolder, "resourcepacks"); - } else if (TexturePackUtils::validate(localFileInfo)) { - qDebug() << fileName << "is a pre 1.6 texture pack"; + break; + case PackedResourceType::TexturePack : validatePath(fileName, targetFolder, "texturepacks"); - } else if (DataPackUtils::validate(localFileInfo)) { - qDebug() << fileName << "is a data pack"; + break; + case PackedResourceType::DataPack : validatePath(fileName, targetFolder, "datapacks"); - } else if (ModUtils::validate(localFileInfo)) { - qDebug() << fileName << "is a mod"; + break; + case PackedResourceType::Mod : validatePath(fileName, targetFolder, "mods"); - } else if (WorldSaveUtils::validate(localFileInfo)) { - qDebug() << fileName << "is a world save"; - QString worldPath = validatePath(fileName, targetFolder, "saves"); - - qDebug() << "Installing World from" << worldPath; - QFileInfo worldFileInfo(worldPath); - World w(worldFileInfo); - if (!w.isValid()) { - qDebug() << "World at" << worldPath << "is not valid, skipping install."; - } else { - w.install(FS::PathCombine(m_stagingPath, "minecraft", "saves")); - } - } else if (ShaderPackUtils::validate(localFileInfo)) { + break; + case PackedResourceType::ShaderPack : // in theroy flame API can't do this but who knows, that *may* change ? // better to handle it if it *does* occure in the future - qDebug() << fileName << "is a shader pack"; validatePath(fileName, targetFolder, "shaderpacks"); - } else { + break; + case PackedResourceType::WorldSave : + worldPath = validatePath(fileName, targetFolder, "saves"); + installWorld(worldPath); + break; + case PackedResourceType::UNKNOWN : + default : qDebug() << "Can't Identify" << fileName << "at" << localPath << ", leaving it where it is."; - } - } else { - qDebug() << "Can't find" << localPath << "to validate it, ignoring"; + break; } } } -- cgit From 0ebf04a021c633cd6a3cdd76514aa728dc253714 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 30 Dec 2022 10:21:49 -0700 Subject: fix newlines Co-authored-by: flow Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/tasks/LocalResourceParse.cpp | 2 +- launcher/minecraft/mod/tasks/LocalResourceParse.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp index 244b2f54..19ddc899 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp @@ -57,4 +57,4 @@ PackedResourceType identify(QFileInfo file){ } return PackedResourceType::UNKNOWN; } -} \ No newline at end of file +} diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.h b/launcher/minecraft/mod/tasks/LocalResourceParse.h index b3e2829d..b07a874c 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.h +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.h @@ -28,4 +28,4 @@ enum class PackedResourceType { DataPack, ResourcePack, TexturePack, ShaderPack, WorldSave, Mod, UNKNOWN }; namespace ResourceUtils { PackedResourceType identify(QFileInfo file); -} // namespace ResourceUtils \ No newline at end of file +} // namespace ResourceUtils -- cgit From 03b75bf2a98edd4114be4799f974bb10fe9b82c4 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 30 Dec 2022 18:06:17 -0700 Subject: feat: Import all the things! Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/Application.cpp | 35 ++++++---- launcher/Application.h | 2 +- launcher/CMakeLists.txt | 6 +- .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 4 +- .../minecraft/mod/tasks/LocalResourceParse.cpp | 21 ++++++ launcher/minecraft/mod/tasks/LocalResourceParse.h | 6 ++ launcher/ui/MainWindow.cpp | 56 ++++++++++----- launcher/ui/MainWindow.h | 2 +- launcher/ui/dialogs/ImportResourceDialog.cpp | 70 +++++++++++++++++++ launcher/ui/dialogs/ImportResourceDialog.h | 30 ++++++++ launcher/ui/dialogs/ImportResourceDialog.ui | 81 ++++++++++++++++++++++ launcher/ui/dialogs/ImportResourcePackDialog.cpp | 65 ----------------- launcher/ui/dialogs/ImportResourcePackDialog.h | 27 -------- launcher/ui/dialogs/ImportResourcePackDialog.ui | 74 -------------------- 14 files changed, 277 insertions(+), 202 deletions(-) create mode 100644 launcher/ui/dialogs/ImportResourceDialog.cpp create mode 100644 launcher/ui/dialogs/ImportResourceDialog.h create mode 100644 launcher/ui/dialogs/ImportResourceDialog.ui delete mode 100644 launcher/ui/dialogs/ImportResourcePackDialog.cpp delete mode 100644 launcher/ui/dialogs/ImportResourcePackDialog.h delete mode 100644 launcher/ui/dialogs/ImportResourcePackDialog.ui (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/Application.cpp b/launcher/Application.cpp index ff34a168..581e51ae 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -259,9 +259,18 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_serverToJoin = parser.value("server"); m_profileToUse = parser.value("profile"); m_liveCheck = parser.isSet("alive"); - m_zipToImport = parser.value("import"); + m_instanceIdToShowWindowOf = parser.value("show"); + for (auto zip_path : parser.values("import")){ + m_zipsToImport.append(QUrl(zip_path)); + } + + for (auto zip_path : parser.positionalArguments()){ // treat unspesified positional arguments as import urls + m_zipsToImport.append(QUrl(zip_path)); + } + + // error if --launch is missing with --server or --profile if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty()) { @@ -345,7 +354,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) } /* - * Establish the mechanism for communication with an already running PolyMC that uses the same data path. + * Establish the mechanism for communication with an already running PrismLauncher that uses the same data path. * If there is one, tell it what the user actually wanted to do and exit. * We want to initialize this before logging to avoid messing with the log of a potential already running copy. */ @@ -363,12 +372,14 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) activate.command = "activate"; m_peerInstance->sendMessage(activate.serialize(), timeout); - if(!m_zipToImport.isEmpty()) + if(!m_zipsToImport.isEmpty()) { - ApplicationMessage import; - import.command = "import"; - import.args.insert("path", m_zipToImport.toString()); - m_peerInstance->sendMessage(import.serialize(), timeout); + for (auto zip_url : m_zipsToImport) { + ApplicationMessage import; + import.command = "import"; + import.args.insert("path", zip_url.toString()); + m_peerInstance->sendMessage(import.serialize(), timeout); + } } } else @@ -938,7 +949,7 @@ bool Application::event(QEvent* event) if (event->type() == QEvent::FileOpen) { auto ev = static_cast(event); - m_mainWindow->droppedURLs({ ev->url() }); + m_mainWindow->processURLs({ ev->url() }); } return QApplication::event(event); @@ -998,10 +1009,10 @@ void Application::performMainStartupAction() showMainWindow(false); qDebug() << "<> Main window shown."; } - if(!m_zipToImport.isEmpty()) + if(!m_zipsToImport.isEmpty()) { - qDebug() << "<> Importing instance from zip:" << m_zipToImport; - m_mainWindow->droppedURLs({ m_zipToImport }); + qDebug() << "<> Importing from zip:" << m_zipsToImport; + m_mainWindow->processURLs( m_zipsToImport ); } } @@ -1054,7 +1065,7 @@ void Application::messageReceived(const QByteArray& message) qWarning() << "Received" << command << "message without a zip path/URL."; return; } - m_mainWindow->droppedURLs({ QUrl(path) }); + m_mainWindow->processURLs({ QUrl(path) }); } else if(command == "launch") { diff --git a/launcher/Application.h b/launcher/Application.h index 7884227a..cd90088e 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -303,7 +303,7 @@ public: QString m_serverToJoin; QString m_profileToUse; bool m_liveCheck = false; - QUrl m_zipToImport; + QList m_zipsToImport; QString m_instanceIdToShowWindowOf; std::unique_ptr logFile; }; diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 8b5c63ff..a3520e72 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -841,8 +841,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ExportInstanceDialog.h ui/dialogs/IconPickerDialog.cpp ui/dialogs/IconPickerDialog.h - ui/dialogs/ImportResourcePackDialog.cpp - ui/dialogs/ImportResourcePackDialog.h + ui/dialogs/ImportResourceDialog.cpp + ui/dialogs/ImportResourceDialog.h ui/dialogs/LoginDialog.cpp ui/dialogs/LoginDialog.h ui/dialogs/MSALoginDialog.cpp @@ -992,7 +992,7 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/SkinUploadDialog.ui ui/dialogs/ExportInstanceDialog.ui ui/dialogs/IconPickerDialog.ui - ui/dialogs/ImportResourcePackDialog.ui + ui/dialogs/ImportResourceDialog.ui ui/dialogs/MSALoginDialog.ui ui/dialogs/OfflineLoginDialog.ui ui/dialogs/AboutDialog.ui diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 3fcb2110..5bb44877 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -50,7 +50,7 @@ bool processFolder(DataPack& pack, ProcessingLevel level) Q_ASSERT(pack.type() == ResourceType::FOLDER); auto mcmeta_invalid = [&pack]() { - qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + qWarning() << "Data pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; return false; // the mcmeta is not optional }; @@ -95,7 +95,7 @@ bool processZIP(DataPack& pack, ProcessingLevel level) QuaZipFile file(&zip); auto mcmeta_invalid = [&pack]() { - qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; + qWarning() << "Data pack at" << pack.fileinfo().filePath() << "does not have a valid pack.mcmeta"; return false; // the mcmeta is not optional }; diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp index 19ddc899..63833832 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp @@ -19,6 +19,8 @@ * along with this program. If not, see . */ +#include + #include "LocalResourceParse.h" #include "LocalDataPackParseTask.h" @@ -28,6 +30,17 @@ #include "LocalTexturePackParseTask.h" #include "LocalWorldSaveParseTask.h" + +static const QMap s_packed_type_names = { + {PackedResourceType::ResourcePack, QObject::tr("resource pack")}, + {PackedResourceType::TexturePack, QObject::tr("texture pack")}, + {PackedResourceType::DataPack, QObject::tr("data pack")}, + {PackedResourceType::ShaderPack, QObject::tr("shader pack")}, + {PackedResourceType::WorldSave, QObject::tr("world save")}, + {PackedResourceType::Mod , QObject::tr("mod")}, + {PackedResourceType::UNKNOWN, QObject::tr("unknown")} +}; + namespace ResourceUtils { PackedResourceType identify(QFileInfo file){ if (file.exists() && file.isFile()) { @@ -57,4 +70,12 @@ PackedResourceType identify(QFileInfo file){ } return PackedResourceType::UNKNOWN; } + +QString getPackedTypeName(PackedResourceType type) { + return s_packed_type_names.constFind(type).value(); } + +} + + + diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.h b/launcher/minecraft/mod/tasks/LocalResourceParse.h index b07a874c..7385d24b 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.h +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.h @@ -21,11 +21,17 @@ #pragma once +#include + #include #include #include enum class PackedResourceType { DataPack, ResourcePack, TexturePack, ShaderPack, WorldSave, Mod, UNKNOWN }; namespace ResourceUtils { +static const std::set ValidResourceTypes = { PackedResourceType::DataPack, PackedResourceType::ResourcePack, + PackedResourceType::TexturePack, PackedResourceType::ShaderPack, + PackedResourceType::WorldSave, PackedResourceType::Mod }; PackedResourceType identify(QFileInfo file); +QString getPackedTypeName(PackedResourceType type); } // namespace ResourceUtils diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e913849d..1d2e44e5 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -109,13 +109,12 @@ #include "ui/dialogs/UpdateDialog.h" #include "ui/dialogs/EditAccountDialog.h" #include "ui/dialogs/ExportInstanceDialog.h" -#include "ui/dialogs/ImportResourcePackDialog.h" +#include "ui/dialogs/ImportResourceDialog.h" #include "ui/themes/ITheme.h" -#include -#include -#include -#include +#include "minecraft/mod/tasks/LocalResourceParse.h" +#include "minecraft/mod/ModFolderModel.h" +#include "minecraft/WorldList.h" #include "UpdateController.h" #include "KonamiCode.h" @@ -954,7 +953,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow view->installEventFilter(this); view->setContextMenuPolicy(Qt::CustomContextMenu); connect(view, &QWidget::customContextMenuRequested, this, &MainWindow::showInstanceContextMenu); - connect(view, &InstanceView::droppedURLs, this, &MainWindow::droppedURLs, Qt::QueuedConnection); + connect(view, &InstanceView::droppedURLs, this, &MainWindow::processURLs, Qt::QueuedConnection); proxymodel = new InstanceProxyModel(this); proxymodel->setSourceModel(APPLICATION->instances().get()); @@ -1813,10 +1812,12 @@ void MainWindow::on_actionAddInstance_triggered() addInstance(); } -void MainWindow::droppedURLs(QList urls) +void MainWindow::processURLs(QList urls) { // NOTE: This loop only processes one dropped file! for (auto& url : urls) { + qDebug() << "Processing :" << url; + // The isLocalFile() check below doesn't work as intended without an explicit scheme. if (url.scheme().isEmpty()) url.setScheme("file"); @@ -1829,28 +1830,49 @@ void MainWindow::droppedURLs(QList urls) auto localFileName = url.toLocalFile(); QFileInfo localFileInfo(localFileName); - bool isResourcePack = ResourcePackUtils::validate(localFileInfo); - bool isTexturePack = TexturePackUtils::validate(localFileInfo); + auto type = ResourceUtils::identify(localFileInfo); + + // bool is_resource = type; - if (!isResourcePack && !isTexturePack) { // probably instance/modpack + if (!(ResourceUtils::ValidResourceTypes.count(type) > 0)) { // probably instance/modpack addInstance(localFileName); - break; + continue; } - ImportResourcePackDialog dlg(this); + ImportResourceDialog dlg(localFileName, type, this); if (dlg.exec() != QDialog::Accepted) - break; + continue; - qDebug() << "Adding resource/texture pack" << localFileName << "to" << dlg.selectedInstanceKey; + qDebug() << "Adding resource" << localFileName << "to" << dlg.selectedInstanceKey; auto inst = APPLICATION->instances()->getInstanceById(dlg.selectedInstanceKey); auto minecraftInst = std::dynamic_pointer_cast(inst); - if (isResourcePack) + + switch (type) { + case PackedResourceType::ResourcePack: minecraftInst->resourcePackList()->installResource(localFileName); - else if (isTexturePack) + break; + case PackedResourceType::TexturePack: minecraftInst->texturePackList()->installResource(localFileName); - break; + break; + case PackedResourceType::DataPack: + qWarning() << "Importing of Data Packs not supported at this time. Ignoring" << localFileName; + break; + case PackedResourceType::Mod: + minecraftInst->loaderModList()->installMod(localFileName); + break; + case PackedResourceType::ShaderPack: + minecraftInst->shaderPackList()->installResource(localFileName); + break; + case PackedResourceType::WorldSave: + minecraftInst->worldList()->installWorld(localFileName); + break; + case PackedResourceType::UNKNOWN: + default: + qDebug() << "Can't Identify" << localFileName << "Ignoring it."; + break; + } } } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index f96f641d..6bf5f428 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -80,7 +80,7 @@ public: void updatesAllowedChanged(bool allowed); - void droppedURLs(QList urls); + void processURLs(QList urls); signals: void isClosing(); diff --git a/launcher/ui/dialogs/ImportResourceDialog.cpp b/launcher/ui/dialogs/ImportResourceDialog.cpp new file mode 100644 index 00000000..84b69273 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourceDialog.cpp @@ -0,0 +1,70 @@ +#include "ImportResourceDialog.h" +#include "ui_ImportResourceDialog.h" + +#include +#include + +#include "Application.h" +#include "InstanceList.h" + +#include +#include "ui/instanceview/InstanceDelegate.h" +#include "ui/instanceview/InstanceProxyModel.h" + +ImportResourceDialog::ImportResourceDialog(QString file_path, PackedResourceType type, QWidget* parent) + : QDialog(parent), ui(new Ui::ImportResourceDialog), m_resource_type(type), m_file_path(file_path) +{ + ui->setupUi(this); + setWindowModality(Qt::WindowModal); + + auto contentsWidget = ui->instanceView; + contentsWidget->setViewMode(QListView::ListMode); + contentsWidget->setFlow(QListView::LeftToRight); + contentsWidget->setIconSize(QSize(48, 48)); + contentsWidget->setMovement(QListView::Static); + contentsWidget->setResizeMode(QListView::Adjust); + contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection); + contentsWidget->setSpacing(5); + contentsWidget->setWordWrap(true); + contentsWidget->setWrapping(true); + // NOTE: We can't have uniform sizes because the text may wrap if it's too long. If we set this, it will cut off the wrapped text. + contentsWidget->setUniformItemSizes(false); + contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + contentsWidget->setItemDelegate(new ListViewDelegate()); + + proxyModel = new InstanceProxyModel(this); + proxyModel->setSourceModel(APPLICATION->instances().get()); + proxyModel->sort(0); + contentsWidget->setModel(proxyModel); + + connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex))); + connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + SLOT(selectionChanged(QItemSelection, QItemSelection))); + + ui->label->setText( + tr("Choose the instance you would like to import this %1 to.").arg(ResourceUtils::getPackedTypeName(m_resource_type))); + ui->label_file_path->setText(tr("File: %1").arg(m_file_path)); +} + +void ImportResourceDialog::activated(QModelIndex index) +{ + selectedInstanceKey = index.data(InstanceList::InstanceIDRole).toString(); + accept(); +} + +void ImportResourceDialog::selectionChanged(QItemSelection selected, QItemSelection deselected) +{ + if (selected.empty()) + return; + + QString key = selected.first().indexes().first().data(InstanceList::InstanceIDRole).toString(); + if (!key.isEmpty()) { + selectedInstanceKey = key; + } +} + +ImportResourceDialog::~ImportResourceDialog() +{ + delete ui; +} diff --git a/launcher/ui/dialogs/ImportResourceDialog.h b/launcher/ui/dialogs/ImportResourceDialog.h new file mode 100644 index 00000000..c9e3f956 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourceDialog.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "ui/instanceview/InstanceProxyModel.h" +#include "minecraft/mod/tasks/LocalResourceParse.h" + +namespace Ui { +class ImportResourceDialog; +} + +class ImportResourceDialog : public QDialog { + Q_OBJECT + + public: + explicit ImportResourceDialog(QString file_path, PackedResourceType type, QWidget* parent = 0); + ~ImportResourceDialog(); + InstanceProxyModel* proxyModel; + QString selectedInstanceKey; + + private: + Ui::ImportResourceDialog* ui; + PackedResourceType m_resource_type; + QString m_file_path; + + private slots: + void selectionChanged(QItemSelection, QItemSelection); + void activated(QModelIndex); +}; diff --git a/launcher/ui/dialogs/ImportResourceDialog.ui b/launcher/ui/dialogs/ImportResourceDialog.ui new file mode 100644 index 00000000..cc3f4ec1 --- /dev/null +++ b/launcher/ui/dialogs/ImportResourceDialog.ui @@ -0,0 +1,81 @@ + + + ImportResourceDialog + + + + 0 + 0 + 676 + 555 + + + + Choose instance to import to + + + + + + Choose the instance you would like to import this resource pack to. + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ImportResourceDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ImportResourceDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.cpp b/launcher/ui/dialogs/ImportResourcePackDialog.cpp deleted file mode 100644 index e8902656..00000000 --- a/launcher/ui/dialogs/ImportResourcePackDialog.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "ImportResourcePackDialog.h" -#include "ui_ImportResourcePackDialog.h" - -#include -#include - -#include "Application.h" -#include "InstanceList.h" - -#include -#include "ui/instanceview/InstanceProxyModel.h" -#include "ui/instanceview/InstanceDelegate.h" - -ImportResourcePackDialog::ImportResourcePackDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ImportResourcePackDialog) -{ - ui->setupUi(this); - setWindowModality(Qt::WindowModal); - - auto contentsWidget = ui->instanceView; - contentsWidget->setViewMode(QListView::ListMode); - contentsWidget->setFlow(QListView::LeftToRight); - contentsWidget->setIconSize(QSize(48, 48)); - contentsWidget->setMovement(QListView::Static); - contentsWidget->setResizeMode(QListView::Adjust); - contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection); - contentsWidget->setSpacing(5); - contentsWidget->setWordWrap(true); - contentsWidget->setWrapping(true); - // NOTE: We can't have uniform sizes because the text may wrap if it's too long. If we set this, it will cut off the wrapped text. - contentsWidget->setUniformItemSizes(false); - contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - contentsWidget->setItemDelegate(new ListViewDelegate()); - - proxyModel = new InstanceProxyModel(this); - proxyModel->setSourceModel(APPLICATION->instances().get()); - proxyModel->sort(0); - contentsWidget->setModel(proxyModel); - - connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex))); - connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - SLOT(selectionChanged(QItemSelection, QItemSelection))); -} - -void ImportResourcePackDialog::activated(QModelIndex index) -{ - selectedInstanceKey = index.data(InstanceList::InstanceIDRole).toString(); - accept(); -} - -void ImportResourcePackDialog::selectionChanged(QItemSelection selected, QItemSelection deselected) -{ - if (selected.empty()) - return; - - QString key = selected.first().indexes().first().data(InstanceList::InstanceIDRole).toString(); - if (!key.isEmpty()) { - selectedInstanceKey = key; - } -} - -ImportResourcePackDialog::~ImportResourcePackDialog() -{ - delete ui; -} diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.h b/launcher/ui/dialogs/ImportResourcePackDialog.h deleted file mode 100644 index 8356f204..00000000 --- a/launcher/ui/dialogs/ImportResourcePackDialog.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -#include "ui/instanceview/InstanceProxyModel.h" - -namespace Ui { -class ImportResourcePackDialog; -} - -class ImportResourcePackDialog : public QDialog { - Q_OBJECT - - public: - explicit ImportResourcePackDialog(QWidget* parent = 0); - ~ImportResourcePackDialog(); - InstanceProxyModel* proxyModel; - QString selectedInstanceKey; - - private: - Ui::ImportResourcePackDialog* ui; - - private slots: - void selectionChanged(QItemSelection, QItemSelection); - void activated(QModelIndex); -}; diff --git a/launcher/ui/dialogs/ImportResourcePackDialog.ui b/launcher/ui/dialogs/ImportResourcePackDialog.ui deleted file mode 100644 index 20cb9177..00000000 --- a/launcher/ui/dialogs/ImportResourcePackDialog.ui +++ /dev/null @@ -1,74 +0,0 @@ - - - ImportResourcePackDialog - - - - 0 - 0 - 676 - 555 - - - - Choose instance to import - - - - - - Choose the instance you would like to import this resource pack to. - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - ImportResourcePackDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ImportResourcePackDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - -- cgit From 574af2c795a19246c18e5f07a49d6d41f5670a6e Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 9 Jan 2023 17:12:28 -0700 Subject: chore: cleanup review suggestions Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/mod/tasks/LocalResourceParse.cpp | 3 --- launcher/ui/dialogs/ImportResourceDialog.h | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp index 63833832..4d760df2 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp @@ -76,6 +76,3 @@ QString getPackedTypeName(PackedResourceType type) { } } - - - diff --git a/launcher/ui/dialogs/ImportResourceDialog.h b/launcher/ui/dialogs/ImportResourceDialog.h index c9e3f956..5f2f7a92 100644 --- a/launcher/ui/dialogs/ImportResourceDialog.h +++ b/launcher/ui/dialogs/ImportResourceDialog.h @@ -3,8 +3,8 @@ #include #include -#include "ui/instanceview/InstanceProxyModel.h" #include "minecraft/mod/tasks/LocalResourceParse.h" +#include "ui/instanceview/InstanceProxyModel.h" namespace Ui { class ImportResourceDialog; @@ -14,15 +14,15 @@ class ImportResourceDialog : public QDialog { Q_OBJECT public: - explicit ImportResourceDialog(QString file_path, PackedResourceType type, QWidget* parent = 0); - ~ImportResourceDialog(); - InstanceProxyModel* proxyModel; + explicit ImportResourceDialog(QString file_path, PackedResourceType type, QWidget* parent = nullptr); + ~ImportResourceDialog() override; QString selectedInstanceKey; - + private: Ui::ImportResourceDialog* ui; PackedResourceType m_resource_type; QString m_file_path; + InstanceProxyModel* proxyModel; private slots: void selectionChanged(QItemSelection, QItemSelection); -- cgit From ebb0596c1a09a7c14f3c8e9e2cb311e652bd34e0 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 13 Jan 2023 21:15:10 -0300 Subject: fix: don't fail mod parsing when encountering invalid modListVersion The spec (admitely a very old one) states that this entry should always have the value "2". However, some mods do not follow this convention, causing issues. One notable example is the 1.6 version of Aether II for 1.7.10, that has this value set at "5" for whatever reason. Signed-off-by: flow --- launcher/minecraft/mod/tasks/LocalModParseTask.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'launcher/minecraft/mod/tasks') diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 8bfe2c84..91cb747f 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -17,7 +17,7 @@ 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 @@ -74,10 +74,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"); -- cgit