aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/mod/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/minecraft/mod/tasks')
-rw-r--r--launcher/minecraft/mod/tasks/BasicFolderLoadTask.h37
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp4
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.h2
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp164
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h56
-rw-r--r--launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp9
-rw-r--r--launcher/minecraft/mod/tasks/ModFolderLoadTask.h12
7 files changed, 264 insertions, 20 deletions
diff --git a/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h b/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h
index cc02a9b9..be0e752d 100644
--- a/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h
+++ b/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h
@@ -10,37 +10,46 @@
#include "tasks/Task.h"
-/** Very simple task that just loads a folder's contents directly.
+/** Very simple task that just loads a folder's contents directly.
*/
-class BasicFolderLoadTask : public Task
-{
+class BasicFolderLoadTask : public Task {
Q_OBJECT
-public:
+ public:
struct Result {
QMap<QString, Resource::Ptr> resources;
};
using ResultPtr = std::shared_ptr<Result>;
- [[nodiscard]] ResultPtr result() const {
- return m_result;
- }
+ [[nodiscard]] ResultPtr result() const { return m_result; }
-public:
- BasicFolderLoadTask(QDir dir) : Task(nullptr, false), m_dir(dir), m_result(new Result) {}
+ public:
+ BasicFolderLoadTask(QDir dir) : Task(nullptr, false), m_dir(dir), m_result(new Result)
+ {
+ m_create_func = [](QFileInfo const& entry) -> Resource* {
+ return new Resource(entry);
+ };
+ }
+ BasicFolderLoadTask(QDir dir, std::function<Resource*(QFileInfo const&)> create_function)
+ : Task(nullptr, false), m_dir(dir), m_result(new Result), m_create_func(std::move(create_function))
+ {}
[[nodiscard]] bool canAbort() const override { return true; }
- bool abort() override { m_aborted = true; return true; }
+ bool abort() override
+ {
+ m_aborted.store(true);
+ return true;
+ }
void executeTask() override
{
m_dir.refresh();
for (auto entry : m_dir.entryInfoList()) {
- auto resource = new Resource(entry);
+ auto resource = m_create_func(entry);
m_result->resources.insert(resource->internal_id(), resource);
}
if (m_aborted)
- emitAborted();
+ emit finished();
else
emitSucceeded();
}
@@ -49,5 +58,7 @@ private:
QDir m_dir;
ResultPtr m_result;
- bool m_aborted = false;
+ std::atomic<bool> m_aborted = false;
+
+ std::function<Resource*(QFileInfo const&)> m_create_func;
};
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index c486bd46..8a6e54d8 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
@@ -499,7 +499,7 @@ void LocalModParseTask::processAsLitemod()
bool LocalModParseTask::abort()
{
- m_aborted = true;
+ m_aborted.store(true);
return true;
}
@@ -521,7 +521,7 @@ void LocalModParseTask::executeTask()
}
if (m_aborted)
- emitAborted();
+ emit finished();
else
emitSucceeded();
}
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.h b/launcher/minecraft/mod/tasks/LocalModParseTask.h
index 4bbf3c85..413eb2d1 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.h
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.h
@@ -39,5 +39,5 @@ private:
QFileInfo m_modFile;
ResultPtr m_result;
- bool m_aborted = false;
+ std::atomic<bool> m_aborted = false;
};
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
new file mode 100644
index 00000000..4f87bc13
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.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 "LocalResourcePackParseTask.h"
+
+#include "FileSystem.h"
+#include "Json.h"
+
+#include <quazip/quazip.h>
+#include <quazip/quazipfile.h>
+
+#include <QCryptographicHash>
+
+namespace ResourcePackUtils {
+
+bool process(ResourcePack& pack)
+{
+ switch (pack.type()) {
+ case ResourceType::FOLDER:
+ ResourcePackUtils::processFolder(pack);
+ return true;
+ case ResourceType::ZIPFILE:
+ ResourcePackUtils::processZIP(pack);
+ return true;
+ default:
+ qWarning() << "Invalid type for resource pack parse task!";
+ return false;
+ }
+}
+
+void processFolder(ResourcePack& pack)
+{
+ Q_ASSERT(pack.type() == ResourceType::FOLDER);
+
+ QFileInfo mcmeta_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.mcmeta"));
+ if (mcmeta_file_info.isFile()) {
+ QFile mcmeta_file(mcmeta_file_info.filePath());
+ if (!mcmeta_file.open(QIODevice::ReadOnly))
+ return;
+
+ auto data = mcmeta_file.readAll();
+
+ ResourcePackUtils::processMCMeta(pack, std::move(data));
+
+ mcmeta_file.close();
+ }
+
+ 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;
+
+ auto data = mcmeta_file.readAll();
+
+ ResourcePackUtils::processPackPNG(pack, std::move(data));
+
+ mcmeta_file.close();
+ }
+}
+
+void processZIP(ResourcePack& pack)
+{
+ Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
+
+ QuaZip zip(pack.fileinfo().filePath());
+ if (!zip.open(QuaZip::mdUnzip))
+ return;
+
+ QuaZipFile file(&zip);
+
+ if (zip.setCurrentFile("pack.mcmeta")) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open file in zip.";
+ zip.close();
+ return;
+ }
+
+ auto data = file.readAll();
+
+ ResourcePackUtils::processMCMeta(pack, std::move(data));
+
+ file.close();
+ }
+
+ if (zip.setCurrentFile("pack.png")) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open file in zip.";
+ zip.close();
+ return;
+ }
+
+ auto data = file.readAll();
+
+ ResourcePackUtils::processPackPNG(pack, std::move(data));
+
+ file.close();
+ }
+
+ zip.close();
+}
+
+// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta
+void processMCMeta(ResourcePack& 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();
+ }
+}
+
+void 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.";
+ }
+}
+} // namespace ResourcePackUtils
+
+LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp)
+ : Task(nullptr, false), m_token(token), m_resource_pack(rp)
+{}
+
+bool LocalResourcePackParseTask::abort()
+{
+ m_aborted = true;
+ return true;
+}
+
+void LocalResourcePackParseTask::executeTask()
+{
+ Q_ASSERT(m_resource_pack.valid());
+
+ if (!ResourcePackUtils::process(m_resource_pack))
+ return;
+
+ if (m_aborted)
+ emitAborted();
+ else
+ emitSucceeded();
+}
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
new file mode 100644
index 00000000..d3c25464
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.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/ResourcePack.h"
+
+#include "tasks/Task.h"
+
+namespace ResourcePackUtils {
+bool process(ResourcePack& pack);
+
+void processZIP(ResourcePack& pack);
+void processFolder(ResourcePack& pack);
+
+void processMCMeta(ResourcePack& pack, QByteArray&& raw_data);
+void processPackPNG(ResourcePack& pack, QByteArray&& raw_data);
+} // namespace ResourcePackUtils
+
+class LocalResourcePackParseTask : public Task {
+ Q_OBJECT
+ public:
+ LocalResourcePackParseTask(int token, ResourcePack& 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;
+
+ ResourcePack& m_resource_pack;
+
+ bool m_aborted = false;
+};
diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp
index a56ba8ab..3a857740 100644
--- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp
+++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp
@@ -38,8 +38,8 @@
#include "minecraft/mod/MetadataHandler.h"
-ModFolderLoadTask::ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan, QObject* parent)
- : Task(parent, false), m_mods_dir(mods_dir), m_index_dir(index_dir), m_is_indexed(is_indexed), m_clean_orphan(clean_orphan), m_result(new Result())
+ModFolderLoadTask::ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan)
+ : Task(nullptr, false), m_mods_dir(mods_dir), m_index_dir(index_dir), m_is_indexed(is_indexed), m_clean_orphan(clean_orphan), m_result(new Result())
{}
void ModFolderLoadTask::executeTask()
@@ -96,7 +96,10 @@ void ModFolderLoadTask::executeTask()
}
}
- emitSucceeded();
+ if (m_aborted)
+ emit finished();
+ else
+ emitSucceeded();
}
void ModFolderLoadTask::getFromMetadata()
diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h
index 840e95e1..0f18b8b9 100644
--- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h
+++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h
@@ -57,7 +57,15 @@ public:
}
public:
- ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan = false, QObject* parent = nullptr);
+ ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan = false);
+
+ [[nodiscard]] bool canAbort() const override { return true; }
+ bool abort() override
+ {
+ m_aborted.store(true);
+ return true;
+ }
+
void executeTask() override;
@@ -69,4 +77,6 @@ private:
bool m_is_indexed;
bool m_clean_orphan;
ResultPtr m_result;
+
+ std::atomic<bool> m_aborted = false;
};