aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/CMakeLists.txt2
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp2
-rw-r--r--launcher/minecraft/mod/ModFolderModel.h2
-rw-r--r--launcher/minecraft/mod/ResourceFolderModel.h2
-rw-r--r--launcher/minecraft/mod/ResourcePackFolderModel.cpp174
-rw-r--r--launcher/minecraft/mod/ResourcePackFolderModel.h17
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp95
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h34
8 files changed, 292 insertions, 36 deletions
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 7c3c2f28..ef8ec681 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -336,6 +336,8 @@ set(MINECRAFT_SOURCES
minecraft/mod/tasks/LocalModParseTask.cpp
minecraft/mod/tasks/LocalModUpdateTask.h
minecraft/mod/tasks/LocalModUpdateTask.cpp
+ minecraft/mod/tasks/LocalResourcePackParseTask.h
+ minecraft/mod/tasks/LocalResourcePackParseTask.cpp
# Assets
minecraft/AssetsUtils.h
diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp
index 4e264a74..c014742c 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -156,7 +156,7 @@ Task* ModFolderModel::createUpdateTask()
return task;
}
-Task* ModFolderModel::createParseTask(Resource const& resource)
+Task* ModFolderModel::createParseTask(Resource& resource)
{
return new LocalModParseTask(m_next_resolution_ticket, resource.type(), resource.fileinfo());
}
diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h
index c33195ed..93980319 100644
--- a/launcher/minecraft/mod/ModFolderModel.h
+++ b/launcher/minecraft/mod/ModFolderModel.h
@@ -82,7 +82,7 @@ public:
int columnCount(const QModelIndex &parent) const override;
[[nodiscard]] Task* createUpdateTask() override;
- [[nodiscard]] Task* createParseTask(Resource const&) override;
+ [[nodiscard]] Task* createParseTask(Resource&) override;
bool installMod(QString file_path) { return ResourceFolderModel::installResource(file_path); }
bool uninstallMod(const QString& filename, bool preserve_metadata = false);
diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h
index e27b5db6..a45d1cbd 100644
--- a/launcher/minecraft/mod/ResourceFolderModel.h
+++ b/launcher/minecraft/mod/ResourceFolderModel.h
@@ -145,7 +145,7 @@ class ResourceFolderModel : public QAbstractListModel {
* This task should load and parse all heavy info needed by a resource, such as parsing a manifest. It gets executed
* in the background, so it slowly updates the UI as tasks get done.
*/
- [[nodiscard]] virtual Task* createParseTask(Resource const&) { return nullptr; };
+ [[nodiscard]] virtual Task* createParseTask(Resource&) { return nullptr; };
/** Standard implementation of the model update logic.
*
diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
index e92be894..b634130f 100644
--- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp
+++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
@@ -1,38 +1,146 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
-* PolyMC - Minecraft Launcher
-* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
-*
-* 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/>.
-*
-* This file incorporates work covered by the following copyright and
-* permission notice:
-*
-* Copyright 2013-2021 MultiMC Contributors
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * 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/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include "ResourcePackFolderModel.h"
-ResourcePackFolderModel::ResourcePackFolderModel(const QString &dir) : ResourceFolderModel(QDir(dir)) {}
+#include "Version.h"
+
+#include "minecraft/mod/tasks/BasicFolderLoadTask.h"
+#include "minecraft/mod/tasks/LocalResourcePackParseTask.h"
+
+ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir) : ResourceFolderModel(QDir(dir))
+{
+ m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::VERSION, SortType::DATE };
+}
+
+QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const
+{
+ if (!validateIndex(index))
+ return {};
+
+ int row = index.row();
+ int column = index.column();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (column) {
+ case NameColumn:
+ return m_resources[row]->name();
+ case PackFormatColumn: {
+ auto version_bounds = at(row)->compatibleVersions();
+ if (version_bounds.first.toString().isEmpty())
+ return QString::number(at(row)->packFormat());
+
+ return QString("%1 (%2 - %3)")
+ .arg(QString::number(at(row)->packFormat()), version_bounds.first.toString(), version_bounds.second.toString());
+ }
+ case DateColumn:
+ return m_resources[row]->dateTimeChanged();
+
+ default:
+ return {};
+ }
+
+ case Qt::ToolTipRole: {
+ if (column == PackFormatColumn) {
+ //: The string being explained by this is in the format: ID (Lower version - Upper version)
+ return tr("The resource pack format ID, as well as the Minecraft versions it was designed for.");
+ }
+ return m_resources[row]->internal_id();
+ }
+ case Qt::CheckStateRole:
+ switch (column) {
+ case ActiveColumn:
+ return at(row)->enabled() ? Qt::Checked : Qt::Unchecked;
+ default:
+ return {};
+ }
+ default:
+ return {};
+ }
+}
+
+QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (section) {
+ case ActiveColumn:
+ return QString();
+ case NameColumn:
+ return tr("Name");
+ case PackFormatColumn:
+ return tr("Pack Format");
+ case DateColumn:
+ return tr("Last changed");
+ default:
+ return {};
+ }
+
+ case Qt::ToolTipRole:
+ switch (section) {
+ case ActiveColumn:
+ return tr("Is the resource pack enabled? (Only valid for ZIPs)");
+ case NameColumn:
+ return tr("The name of the resource pack.");
+ case PackFormatColumn:
+ //: The string being explained by this is in the format: ID (Lower version - Upper version)
+ return tr("The resource pack format ID, as well as the Minecraft versions it was designed for.");
+ case DateColumn:
+ return tr("The date and time this resource pack was last changed (or added).");
+ default:
+ return {};
+ }
+ default:
+ return {};
+ }
+ return {};
+}
+
+int ResourcePackFolderModel::columnCount(const QModelIndex& parent) const
+{
+ return NUM_COLUMNS;
+}
+
+Task* ResourcePackFolderModel::createUpdateTask()
+{
+ return new BasicFolderLoadTask(m_dir, [](QFileInfo const& entry) { return new ResourcePack(entry); });
+}
+
+Task* ResourcePackFolderModel::createParseTask(Resource& resource)
+{
+ return new LocalResourcePackParseTask(m_next_resolution_ticket, static_cast<ResourcePack&>(resource));
+}
diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.h b/launcher/minecraft/mod/ResourcePackFolderModel.h
index 1fe82867..cb620ce2 100644
--- a/launcher/minecraft/mod/ResourcePackFolderModel.h
+++ b/launcher/minecraft/mod/ResourcePackFolderModel.h
@@ -8,7 +8,24 @@ class ResourcePackFolderModel : public ResourceFolderModel
{
Q_OBJECT
public:
+ enum Columns
+ {
+ ActiveColumn = 0,
+ NameColumn,
+ PackFormatColumn,
+ DateColumn,
+ NUM_COLUMNS
+ };
+
explicit ResourcePackFolderModel(const QString &dir);
+ [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ [[nodiscard]] int columnCount(const QModelIndex &parent) const override;
+
+ [[nodiscard]] Task* createUpdateTask() override;
+ [[nodiscard]] Task* createParseTask(Resource&) override;
+
RESOURCE_HELPERS(ResourcePack)
};
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
new file mode 100644
index 00000000..0fc7a87e
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
@@ -0,0 +1,95 @@
+#include "LocalResourcePackParseTask.h"
+
+#include "FileSystem.h"
+#include "Json.h"
+
+#include <quazip/quazip.h>
+#include <quazip/quazipfile.h>
+
+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()
+{
+ switch (m_resource_pack.type()) {
+ case ResourceType::FOLDER:
+ processAsFolder();
+ break;
+ case ResourceType::ZIPFILE:
+ processAsZip();
+ break;
+ default:
+ qWarning() << "Invalid type for resource pack parse task!";
+ emitFailed(tr("Invalid type."));
+ }
+
+ if (isFinished())
+ return;
+
+ if (m_aborted)
+ emitAborted();
+ else
+ emitSucceeded();
+}
+
+// https://minecraft.fandom.com/wiki/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta
+void LocalResourcePackParseTask::processMCMeta(QByteArray&& raw_data)
+{
+ try {
+ auto json_doc = QJsonDocument::fromJson(raw_data);
+ auto pack_obj = Json::requireObject(json_doc.object(), "pack", {});
+
+ m_resource_pack.setPackFormat(Json::ensureInteger(pack_obj, "pack_format", 0));
+ m_resource_pack.setDescription(Json::ensureString(pack_obj, "description", ""));
+ } catch (Json::JsonException& e) {
+ qWarning() << "JsonException: " << e.what() << e.cause();
+ emitFailed(tr("Failed to process .mcmeta file."));
+ }
+}
+
+void LocalResourcePackParseTask::processAsFolder()
+{
+ QFileInfo mcmeta_file_info(FS::PathCombine(m_resource_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();
+ if (data.isEmpty() || data.isNull())
+ return;
+
+ processMCMeta(std::move(data));
+ }
+}
+
+void LocalResourcePackParseTask::processAsZip()
+{
+ QuaZip zip(m_resource_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();
+
+ processMCMeta(std::move(data));
+
+ file.close();
+ zip.close();
+ }
+}
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
new file mode 100644
index 00000000..7660d233
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <QDebug>
+#include <QObject>
+
+#include "minecraft/mod/ResourcePack.h"
+
+#include "tasks/Task.h"
+
+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:
+ void processMCMeta(QByteArray&& raw_data);
+
+ void processAsFolder();
+ void processAsZip();
+
+ private:
+ int m_token;
+
+ ResourcePack& m_resource_pack;
+
+ bool m_aborted = false;
+};