aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/mod
diff options
context:
space:
mode:
authorSefa Eyeoglu <contact@scrumplex.net>2023-01-07 17:33:34 +0100
committerGitHub <noreply@github.com>2023-01-07 17:33:34 +0100
commitf3f628410d3d4c9589b8ec2d06d492e7861c35a3 (patch)
tree415bb4e7bb92dd48bec8097ea73a8e63d5c0c10e /launcher/minecraft/mod
parent9901ecda4938827986e4754f770a2b35b64bb774 (diff)
parent0ebf04a021c633cd6a3cdd76514aa728dc253714 (diff)
downloadPrismLauncher-f3f628410d3d4c9589b8ec2d06d492e7861c35a3.tar.gz
PrismLauncher-f3f628410d3d4c9589b8ec2d06d492e7861c35a3.tar.bz2
PrismLauncher-f3f628410d3d4c9589b8ec2d06d492e7861c35a3.zip
Merge pull request #576 from Ryex/identify-zip-packs
fix https://github.com/PrismLauncher/PrismLauncher/issues/349
Diffstat (limited to 'launcher/minecraft/mod')
-rw-r--r--launcher/minecraft/mod/DataPack.cpp108
-rw-r--r--launcher/minecraft/mod/DataPack.h73
-rw-r--r--launcher/minecraft/mod/Mod.cpp10
-rw-r--r--launcher/minecraft/mod/Mod.h3
-rw-r--r--launcher/minecraft/mod/ModDetails.h6
-rw-r--r--launcher/minecraft/mod/ResourcePack.cpp13
-rw-r--r--launcher/minecraft/mod/ShaderPack.cpp37
-rw-r--r--launcher/minecraft/mod/ShaderPack.h62
-rw-r--r--launcher/minecraft/mod/WorldSave.cpp43
-rw-r--r--launcher/minecraft/mod/WorldSave.h61
-rw-r--r--launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp177
-rw-r--r--launcher/minecraft/mod/tasks/LocalDataPackParseTask.h65
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp143
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.h34
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp110
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h8
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourceParse.cpp60
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourceParse.h31
-rw-r--r--launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp113
-rw-r--r--launcher/minecraft/mod/tasks/LocalShaderPackParseTask.h62
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp59
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h8
-rw-r--r--launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp190
-rw-r--r--launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h62
24 files changed, 1416 insertions, 122 deletions
diff --git a/launcher/minecraft/mod/DataPack.cpp b/launcher/minecraft/mod/DataPack.cpp
new file mode 100644
index 00000000..5c58f6b2
--- /dev/null
+++ b/launcher/minecraft/mod/DataPack.cpp
@@ -0,0 +1,108 @@
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "DataPack.h"
+
+#include <QDebug>
+#include <QMap>
+#include <QRegularExpression>
+
+#include "Version.h"
+
+// Values taken from:
+// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22
+static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = {
+ { 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") } },
+};
+
+void DataPack::setPackFormat(int new_format_id)
+{
+ QMutexLocker locker(&m_data_lock);
+
+ if (!s_pack_format_versions.contains(new_format_id)) {
+ qWarning() << "Pack format '" << new_format_id << "' is not a recognized data pack id!";
+ }
+
+ m_pack_format = new_format_id;
+}
+
+void DataPack::setDescription(QString new_description)
+{
+ QMutexLocker locker(&m_data_lock);
+
+ m_description = new_description;
+}
+
+std::pair<Version, Version> DataPack::compatibleVersions() const
+{
+ if (!s_pack_format_versions.contains(m_pack_format)) {
+ return { {}, {} };
+ }
+
+ return s_pack_format_versions.constFind(m_pack_format).value();
+}
+
+std::pair<int, bool> DataPack::compare(const Resource& other, SortType type) const
+{
+ auto const& cast_other = static_cast<DataPack const&>(other);
+
+ switch (type) {
+ default: {
+ auto res = Resource::compare(other, type);
+ if (res.first != 0)
+ return res;
+ }
+ case SortType::PACK_FORMAT: {
+ auto this_ver = packFormat();
+ auto other_ver = cast_other.packFormat();
+
+ if (this_ver > other_ver)
+ return { 1, type == SortType::PACK_FORMAT };
+ if (this_ver < other_ver)
+ return { -1, type == SortType::PACK_FORMAT };
+ }
+ }
+ return { 0, false };
+}
+
+bool DataPack::applyFilter(QRegularExpression filter) const
+{
+ if (filter.match(description()).hasMatch())
+ return true;
+
+ if (filter.match(QString::number(packFormat())).hasMatch())
+ return true;
+
+ if (filter.match(compatibleVersions().first.toString()).hasMatch())
+ return true;
+ if (filter.match(compatibleVersions().second.toString()).hasMatch())
+ return true;
+
+ return Resource::applyFilter(filter);
+}
+
+bool DataPack::valid() const
+{
+ return m_pack_format != 0;
+}
diff --git a/launcher/minecraft/mod/DataPack.h b/launcher/minecraft/mod/DataPack.h
new file mode 100644
index 00000000..fc2703c7
--- /dev/null
+++ b/launcher/minecraft/mod/DataPack.h
@@ -0,0 +1,73 @@
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "Resource.h"
+
+#include <QMutex>
+
+class Version;
+
+/* TODO:
+ *
+ * Store localized descriptions
+ * */
+
+class DataPack : public Resource {
+ Q_OBJECT
+ public:
+ using Ptr = shared_qobject_ptr<Resource>;
+
+ DataPack(QObject* parent = nullptr) : Resource(parent) {}
+ DataPack(QFileInfo file_info) : Resource(file_info) {}
+
+ /** Gets the numerical ID of the pack format. */
+ [[nodiscard]] int packFormat() const { return m_pack_format; }
+ /** Gets, respectively, the lower and upper versions supported by the set pack format. */
+ [[nodiscard]] std::pair<Version, Version> compatibleVersions() const;
+
+ /** Gets the description of the data pack. */
+ [[nodiscard]] QString description() const { return m_description; }
+
+ /** Thread-safe. */
+ void setPackFormat(int new_format_id);
+
+ /** Thread-safe. */
+ void setDescription(QString new_description);
+
+ bool valid() const override;
+
+ [[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
+ [[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
+
+ protected:
+ mutable QMutex m_data_lock;
+
+ /* 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 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 9cd0056c..c495cd47 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"
static ModPlatform::ProviderCapabilities ProviderCaps;
@@ -70,6 +71,10 @@ void Mod::setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata)
m_local_details.metadata = metadata;
}
+void Mod::setDetails(const ModDetails& details) {
+ m_local_details = details;
+}
+
std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const
{
auto cast_other = dynamic_cast<Mod const*>(&other);
@@ -204,3 +209,8 @@ auto Mod::provider() const -> std::optional<QString>
return ProviderCaps.readableName(metadata()->provider);
return {};
}
+
+bool Mod::valid() const
+{
+ return !m_local_details.mod_id.isEmpty();
+}
diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h
index 8185c8fc..c4032538 100644
--- a/launcher/minecraft/mod/Mod.h
+++ b/launcher/minecraft/mod/Mod.h
@@ -71,6 +71,9 @@ public:
void setStatus(ModStatus status);
void setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata);
void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared<Metadata::ModStruct>(metadata)); }
+ void setDetails(const ModDetails& details);
+
+ bool valid() const override;
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
[[nodiscard]] 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/ResourcePack.cpp b/launcher/minecraft/mod/ResourcePack.cpp
index 3a2fd771..876d5c3e 100644
--- a/launcher/minecraft/mod/ResourcePack.cpp
+++ b/launcher/minecraft/mod/ResourcePack.cpp
@@ -13,11 +13,12 @@
// Values taken from:
// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta
static const QMap<int, std::pair<Version, Version>> 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("1.19.3"), Version("1.19.3") } },
+ { 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") } },
};
void ResourcePack::setPackFormat(int new_format_id)
@@ -25,7 +26,7 @@ void ResourcePack::setPackFormat(int new_format_id)
QMutexLocker locker(&m_data_lock);
if (!s_pack_format_versions.contains(new_format_id)) {
- qWarning() << "Pack format '%1' is not a recognized resource pack id!";
+ qWarning() << "Pack format '" << new_format_id << "' is not a recognized resource pack id!";
}
m_pack_format = new_format_id;
diff --git a/launcher/minecraft/mod/ShaderPack.cpp b/launcher/minecraft/mod/ShaderPack.cpp
new file mode 100644
index 00000000..6a9641de
--- /dev/null
+++ b/launcher/minecraft/mod/ShaderPack.cpp
@@ -0,0 +1,37 @@
+
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#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..ec0f9404
--- /dev/null
+++ b/launcher/minecraft/mod/ShaderPack.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 <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "Resource.h"
+
+/* Info:
+ * 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 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 available profiles but this is not all that useful without more knowledge of the
+ * shader mod used to be able to change settings.
+ */
+
+#include <QMutex>
+
+enum class ShaderPackFormat { VALID, INVALID };
+
+class ShaderPack : public Resource {
+ Q_OBJECT
+ public:
+ using Ptr = shared_qobject_ptr<Resource>;
+
+ [[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/WorldSave.cpp b/launcher/minecraft/mod/WorldSave.cpp
new file mode 100644
index 00000000..7123f512
--- /dev/null
+++ b/launcher/minecraft/mod/WorldSave.cpp
@@ -0,0 +1,43 @@
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#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;
+}
diff --git a/launcher/minecraft/mod/WorldSave.h b/launcher/minecraft/mod/WorldSave.h
new file mode 100644
index 00000000..5985fc8a
--- /dev/null
+++ b/launcher/minecraft/mod/WorldSave.h
@@ -0,0 +1,61 @@
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "Resource.h"
+
+#include <QMutex>
+
+class Version;
+
+enum class WorldSaveFormat { SINGLE, MULTI, INVALID };
+
+class WorldSave : public Resource {
+ Q_OBJECT
+ public:
+ using Ptr = shared_qobject_ptr<Resource>;
+
+ 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 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;
+};
diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp
new file mode 100644
index 00000000..3fcb2110
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "LocalDataPackParseTask.h"
+
+#include "FileSystem.h"
+#include "Json.h"
+
+#include <quazip/quazip.h>
+#include <quazip/quazipdir.h>
+#include <quazip/quazipfile.h>
+
+#include <QCryptographicHash>
+
+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 data pack parse task!";
+ return false;
+ }
+}
+
+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 mcmeta_invalid(); // 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 mcmeta_invalid(); // mcmeta invalid
+ }
+ } else {
+ 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
+ }
+
+ 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);
+
+ 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 mcmeta_invalid();
+ }
+
+ auto data = file.readAll();
+
+ bool mcmeta_result = DataPackUtils::processMCMeta(pack, std::move(data));
+
+ file.close();
+ if (!mcmeta_result) {
+ return mcmeta_invalid(); // mcmeta invalid
+ }
+ } else {
+ 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
+ }
+
+ if (level == ProcessingLevel::BasicInfoOnly) {
+ zip.close();
+ return true; // only need basic info already checked
+ }
+
+ zip.close();
+
+ return true;
+}
+
+// https://minecraft.fandom.com/wiki/Data_pack#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_data_pack(dp) {}
+
+bool LocalDataPackParseTask::abort()
+{
+ m_aborted = true;
+ return true;
+}
+
+void LocalDataPackParseTask::executeTask()
+{
+ if (!DataPackUtils::process(m_data_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..12fd8c82
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.h
@@ -0,0 +1,65 @@
+// 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 <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <QDebug>
+#include <QObject>
+
+#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 data pack or not. */
+bool validate(QFileInfo file);
+
+} // namespace DataPackUtils
+
+class LocalDataPackParseTask : public Task {
+ Q_OBJECT
+ public:
+ LocalDataPackParseTask(int token, DataPack& dp);
+
+ [[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_data_pack;
+
+ bool m_aborted = false;
+};
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index 774f6114..8bfe2c84 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,46 @@ ModDetails ReadLiteModInfo(QByteArray contents)
return details;
}
-} // n