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/GetModDependenciesTask.cpp252
-rw-r--r--launcher/minecraft/mod/tasks/GetModDependenciesTask.h84
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp211
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.h3
-rw-r--r--launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp33
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp67
-rw-r--r--launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h5
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp67
-rw-r--r--launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h5
9 files changed, 705 insertions, 22 deletions
diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
new file mode 100644
index 00000000..f8ecdb33
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@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 "GetModDependenciesTask.h"
+
+#include <QDebug>
+#include <algorithm>
+#include <memory>
+#include "Json.h"
+#include "QObjectPtr.h"
+#include "minecraft/mod/MetadataHandler.h"
+#include "modplatform/ModIndex.h"
+#include "modplatform/ResourceAPI.h"
+#include "modplatform/flame/FlameAPI.h"
+#include "modplatform/modrinth/ModrinthAPI.h"
+#include "tasks/ConcurrentTask.h"
+#include "tasks/SequentialTask.h"
+#include "ui/pages/modplatform/ModModel.h"
+#include "ui/pages/modplatform/flame/FlameResourceModels.h"
+#include "ui/pages/modplatform/modrinth/ModrinthResourceModels.h"
+
+static Version mcVersion(BaseInstance* inst)
+{
+ return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion();
+}
+
+static ResourceAPI::ModLoaderTypes mcLoaders(BaseInstance* inst)
+{
+ return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders().value();
+}
+
+GetModDependenciesTask::GetModDependenciesTask(QObject* parent,
+ BaseInstance* instance,
+ ModFolderModel* folder,
+ QList<std::shared_ptr<PackDependency>> selected)
+ : SequentialTask(parent, tr("Get dependencies"))
+ , m_selected(selected)
+ , m_flame_provider{ ModPlatform::ResourceProvider::FLAME, std::make_shared<ResourceDownload::FlameModModel>(*instance),
+ std::make_shared<FlameAPI>() }
+ , m_modrinth_provider{ ModPlatform::ResourceProvider::MODRINTH, std::make_shared<ResourceDownload::ModrinthModModel>(*instance),
+ std::make_shared<ModrinthAPI>() }
+ , m_version(mcVersion(instance))
+ , m_loaderType(mcLoaders(instance))
+{
+ for (auto mod : folder->allMods())
+ if (auto meta = mod->metadata(); meta)
+ m_mods.append(meta);
+ prepare();
+};
+
+void GetModDependenciesTask::prepare()
+{
+ for (auto sel : m_selected) {
+ for (auto dep : getDependenciesForVersion(sel->version, sel->pack->provider)) {
+ addTask(prepareDependencyTask(dep, sel->pack->provider, 20));
+ }
+ }
+}
+
+ModPlatform::Dependency GetModDependenciesTask::getOverride(const ModPlatform::Dependency& dep,
+ const ModPlatform::ResourceProvider providerName)
+{
+ if (auto isQuilt = m_loaderType & ResourceAPI::Quilt; isQuilt || m_loaderType & ResourceAPI::Fabric) {
+ auto overide = ModPlatform::getOverrideDeps();
+ auto over = std::find_if(overide.cbegin(), overide.cend(), [dep, providerName, isQuilt](auto o) {
+ return o.provider == providerName && dep.addonId == (isQuilt ? o.fabric : o.quilt);
+ });
+ if (over != overide.cend()) {
+ return { isQuilt ? over->quilt : over->fabric, dep.type };
+ }
+ }
+ return dep;
+}
+
+QList<ModPlatform::Dependency> GetModDependenciesTask::getDependenciesForVersion(const ModPlatform::IndexedVersion& version,
+ const ModPlatform::ResourceProvider providerName)
+{
+ QList<ModPlatform::Dependency> c_dependencies;
+ for (auto ver_dep : version.dependencies) {
+ if (ver_dep.type != ModPlatform::DependencyType::REQUIRED)
+ continue;
+
+ auto isOnlyVersion = providerName == ModPlatform::ResourceProvider::MODRINTH && ver_dep.addonId.toString().isEmpty();
+ if (auto dep = std::find_if(c_dependencies.begin(), c_dependencies.end(),
+ [&ver_dep, isOnlyVersion](const ModPlatform::Dependency& i) {
+ return isOnlyVersion ? i.version == ver_dep.version : i.addonId == ver_dep.addonId;
+ });
+ dep != c_dependencies.end())
+ continue; // check the current dependency list
+
+ if (auto dep = std::find_if(m_selected.begin(), m_selected.end(),
+ [&ver_dep, providerName, isOnlyVersion](std::shared_ptr<PackDependency> i) {
+ return i->pack->provider == providerName && (isOnlyVersion ? i->version.version == ver_dep.version
+ : i->pack->addonId == ver_dep.addonId);
+ });
+ dep != m_selected.end())
+ continue; // check the selected versions
+
+ if (auto dep = std::find_if(m_mods.begin(), m_mods.end(),
+ [&ver_dep, providerName, isOnlyVersion](std::shared_ptr<Metadata::ModStruct> i) {
+ return i->provider == providerName &&
+ (isOnlyVersion ? i->file_id == ver_dep.version : i->project_id == ver_dep.addonId);
+ });
+ dep != m_mods.end())
+ continue; // check the existing mods
+
+ if (auto dep = std::find_if(m_pack_dependencies.begin(), m_pack_dependencies.end(),
+ [&ver_dep, providerName, isOnlyVersion](std::shared_ptr<PackDependency> i) {
+ return i->pack->provider == providerName && (isOnlyVersion ? i->version.version == ver_dep.addonId
+ : i->pack->addonId == ver_dep.addonId);
+ });
+ dep != m_pack_dependencies.end()) // check loaded dependencies
+ continue;
+
+ c_dependencies.append(getOverride(ver_dep, providerName));
+ }
+ return c_dependencies;
+};
+
+Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptr<PackDependency> pDep)
+{
+ auto provider = pDep->pack->provider == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
+ auto responseInfo = std::make_shared<QByteArray>();
+ auto info = provider.api->getProject(pDep->pack->addonId.toString(), responseInfo);
+ QObject::connect(info.get(), &NetJob::succeeded, [responseInfo, provider, pDep] {
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*responseInfo, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qDebug() << *responseInfo;
+ return;
+ }
+ try {
+ auto obj = provider.name == ModPlatform::ResourceProvider::FLAME ? Json::requireObject(Json::requireObject(doc), "data")
+ : Json::requireObject(doc);
+ provider.mod->loadIndexedPack(*pDep->pack, obj);
+ } catch (const JSONValidationError& e) {
+ qDebug() << doc;
+ qWarning() << "Error while reading mod info: " << e.cause();
+ }
+ });
+ return info;
+}
+
+Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Dependency& dep,
+ const ModPlatform::ResourceProvider providerName,
+ int level)
+{
+ auto pDep = std::make_shared<PackDependency>();
+ pDep->dependency = dep;
+ pDep->pack = std::make_shared<ModPlatform::IndexedPack>();
+ pDep->pack->addonId = dep.addonId;
+ pDep->pack->provider = providerName;
+
+ m_pack_dependencies.append(pDep);
+ auto provider = providerName == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
+
+ auto tasks = makeShared<SequentialTask>(
+ this, QString("DependencyInfo: %1").arg(dep.addonId.toString().isEmpty() ? dep.version : dep.addonId.toString()));
+
+ if (!dep.addonId.toString().isEmpty()) {
+ tasks->addTask(getProjectInfoTask(pDep));
+ }
+
+ ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType };
+ ResourceAPI::DependencySearchCallbacks callbacks;
+
+ callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, auto& pack) {
+ try {
+ QJsonArray arr;
+ if (dep.version.length() != 0 && doc.isObject()) {
+ arr.append(doc.object());
+ } else {
+ arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array();
+ }
+ pDep->version = provider.mod->loadDependencyVersions(dep, arr);
+ if (!pDep->version.addonId.isValid()) {
+ if (m_loaderType & ResourceAPI::Quilt) { // falback for quilt
+ auto overide = ModPlatform::getOverrideDeps();
+ auto over = std::find_if(overide.cbegin(), overide.cend(),
+ [dep, provider](auto o) { return o.provider == provider.name && dep.addonId == o.quilt; });
+ if (over != overide.cend()) {
+ removePack(dep.addonId);
+ addTask(prepareDependencyTask({ over->fabric, dep.type }, provider.name, level));
+ return;
+ }
+ }
+ qWarning() << "Error while reading mod version empty ";
+ qDebug() << doc;
+ return;
+ }
+ pDep->version.is_currently_selected = true;
+ pDep->pack->versions = { pDep->version };
+ pDep->pack->versionsLoaded = true;
+
+ } catch (const JSONValidationError& e) {
+ qDebug() << doc;
+ qWarning() << "Error while reading mod version: " << e.cause();
+ return;
+ }
+ if (level == 0) {
+ qWarning() << "Dependency cycle exeeded";
+ return;
+ }
+ if (dep.addonId.toString().isEmpty() && !pDep->version.addonId.toString().isEmpty()) {
+ pDep->pack->addonId = pDep->version.addonId;
+ auto dep = getOverride({ pDep->version.addonId, pDep->dependency.type }, provider.name);
+ if (dep.addonId != pDep->version.addonId) {
+ removePack(pDep->version.addonId);
+ addTask(prepareDependencyTask(dep, provider.name, level));
+ } else
+ addTask(getProjectInfoTask(pDep));
+ }
+ for (auto dep : getDependenciesForVersion(pDep->version, provider.name)) {
+ addTask(prepareDependencyTask(dep, provider.name, level - 1));
+ }
+ };
+
+ auto version = provider.api->getDependencyVersion(std::move(args), std::move(callbacks));
+ tasks->addTask(version);
+ return tasks;
+};
+
+void GetModDependenciesTask::removePack(const QVariant addonId)
+{
+ auto pred = [addonId](const std::shared_ptr<PackDependency>& v) { return v->pack->addonId == addonId; };
+#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
+ m_pack_dependencies.removeIf(pred);
+#else
+ for (auto it = m_pack_dependencies.begin(); it != m_pack_dependencies.end();)
+ if (pred(*it))
+ it = m_pack_dependencies.erase(it);
+ else
+ ++it;
+#endif
+}
diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h
new file mode 100644
index 00000000..50eba6af
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (c) 2023 Trial97 <alexandru.tripon97@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 <QDir>
+#include <QEventLoop>
+#include <QList>
+#include <QVariant>
+#include <functional>
+#include <memory>
+
+#include "minecraft/mod/MetadataHandler.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "modplatform/ModIndex.h"
+#include "modplatform/ResourceAPI.h"
+#include "tasks/SequentialTask.h"
+#include "tasks/Task.h"
+#include "ui/pages/modplatform/ModModel.h"
+
+class GetModDependenciesTask : public SequentialTask {
+ Q_OBJECT
+ public:
+ using Ptr = shared_qobject_ptr<GetModDependenciesTask>;
+
+ struct PackDependency {
+ ModPlatform::Dependency dependency;
+ ModPlatform::IndexedPack::Ptr pack;
+ ModPlatform::IndexedVersion version;
+ PackDependency() = default;
+ PackDependency(const ModPlatform::IndexedPack::Ptr p, const ModPlatform::IndexedVersion& v)
+ {
+ pack = p;
+ version = v;
+ }
+ };
+
+ struct Provider {
+ ModPlatform::ResourceProvider name;
+ std::shared_ptr<ResourceDownload::ModModel> mod;
+ std::shared_ptr<ResourceAPI> api;
+ };
+
+ explicit GetModDependenciesTask(QObject* parent,
+ BaseInstance* instance,
+ ModFolderModel* folder,
+ QList<std::shared_ptr<PackDependency>> selected);
+
+ auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_pack_dependencies; }
+
+ protected slots:
+ Task::Ptr prepareDependencyTask(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider, int);
+ QList<ModPlatform::Dependency> getDependenciesForVersion(const ModPlatform::IndexedVersion&,
+ const ModPlatform::ResourceProvider providerName);
+ void prepare();
+ Task::Ptr getProjectInfoTask(std::shared_ptr<PackDependency> pDep);
+ ModPlatform::Dependency getOverride(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider providerName);
+ void removePack(const QVariant addonId);
+
+ private:
+ QList<std::shared_ptr<PackDependency>> m_pack_dependencies;
+ QList<std::shared_ptr<Metadata::ModStruct>> m_mods;
+ QList<std::shared_ptr<PackDependency>> m_selected;
+ Provider m_flame_provider;
+ Provider m_modrinth_provider;
+
+ Version m_version;
+ ResourceAPI::ModLoaderTypes m_loaderType;
+};
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index 5342d693..264019f8 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
@@ -52,6 +52,10 @@ ModDetails ReadMCModInfo(QByteArray contents)
authors = firstObj.value("authors").toArray();
}
+ if (firstObj.contains("logoFile")) {
+ details.icon_file = firstObj.value("logoFile").toString();
+ }
+
for (auto author : authors) {
details.authors.append(author.toString());
}
@@ -166,6 +170,31 @@ ModDetails ReadMCModTOML(QByteArray contents)
}
details.homeurl = homeurl;
+ QString issueTrackerURL = "";
+ if (auto issueTrackerURLDatum = tomlData["issueTrackerURL"].as_string()) {
+ issueTrackerURL = QString::fromStdString(issueTrackerURLDatum->get());
+ } else if (auto issueTrackerURLDatum = (*modsTable)["issueTrackerURL"].as_string()) {
+ issueTrackerURL = QString::fromStdString(issueTrackerURLDatum->get());
+ }
+ details.issue_tracker = issueTrackerURL;
+
+ QString license = "";
+ if (auto licenseDatum = tomlData["license"].as_string()) {
+ license = QString::fromStdString(licenseDatum->get());
+ } else if (auto licenseDatum =(*modsTable)["license"].as_string()) {
+ license = QString::fromStdString(licenseDatum->get());
+ }
+ if (!license.isEmpty())
+ details.licenses.append(ModLicense(license));
+
+ QString logoFile = "";
+ if (auto logoFileDatum = tomlData["logoFile"].as_string()) {
+ logoFile = QString::fromStdString(logoFileDatum->get());
+ } else if (auto logoFileDatum =(*modsTable)["logoFile"].as_string()) {
+ logoFile = QString::fromStdString(logoFileDatum->get());
+ }
+ details.icon_file = logoFile;
+
return details;
}
@@ -201,6 +230,57 @@ ModDetails ReadFabricModInfo(QByteArray contents)
if (contact.contains("homepage")) {
details.homeurl = contact.value("homepage").toString();
}
+ if (contact.contains("issues")) {
+ details.issue_tracker = contact.value("issues").toString();
+ }
+ }
+
+ if (object.contains("license")) {
+ auto license = object.value("license");
+ if (license.isArray()) {
+ for (auto l : license.toArray()) {
+ if (l.isString()) {
+ details.licenses.append(ModLicense(l.toString()));
+ } else if (l.isObject()) {
+ auto obj = l.toObject();
+ details.licenses.append(ModLicense(obj.value("name").toString(), obj.value("id").toString(),
+ obj.value("url").toString(), obj.value("description").toString()));
+ }
+ }
+ } else if (license.isString()) {
+ details.licenses.append(ModLicense(license.toString()));
+ } else if (license.isObject()) {
+ auto obj = license.toObject();
+ details.licenses.append(ModLicense(obj.value("name").toString(), obj.value("id").toString(), obj.value("url").toString(),
+ obj.value("description").toString()));
+ }
+ }
+
+ if (object.contains("icon")) {
+ auto icon = object.value("icon");
+ if (icon.isObject()) {
+ auto obj = icon.toObject();
+ // take the largest icon
+ int largest = 0;
+ for (auto key : obj.keys()) {
+ auto size = key.split('x').first().toInt();
+ if (size > largest) {
+ largest = size;
+ }
+ }
+ if (largest > 0) {
+ auto key = QString::number(largest) + "x" + QString::number(largest);
+ details.icon_file = obj.value(key).toString();
+ } else { // parsing the sizes failed
+ // take the first
+ for (auto i : obj) {
+ details.icon_file = i.toString();
+ break;
+ }
+ }
+ } else if (icon.isString()) {
+ details.icon_file = icon.toString();
+ }
}
}
return details;
@@ -238,6 +318,58 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
if (modContact.contains("homepage")) {
details.homeurl = Json::requireString(modContact.value("homepage"));
}
+ if (modContact.contains("issues")) {
+ details.issue_tracker = Json::requireString(modContact.value("issues"));
+ }
+
+ if (modMetadata.contains("license")) {
+ auto license = modMetadata.value("license");
+ if (license.isArray()) {
+ for (auto l : license.toArray()) {
+ if (l.isString()) {
+ details.licenses.append(ModLicense(l.toString()));
+ } else if (l.isObject()) {
+ auto obj = l.toObject();
+ details.licenses.append(ModLicense(obj.value("name").toString(), obj.value("id").toString(),
+ obj.value("url").toString(), obj.value("description").toString()));
+ }
+ }
+ } else if (license.isString()) {
+ details.licenses.append(ModLicense(license.toString()));
+ } else if (license.isObject()) {
+ auto obj = license.toObject();
+ details.licenses.append(ModLicense(obj.value("name").toString(), obj.value("id").toString(), obj.value("url").toString(),
+ obj.value("description").toString()));
+ }
+ }
+
+ if (modMetadata.contains("icon")) {
+ auto icon = modMetadata.value("icon");
+ if (icon.isObject()) {
+ auto obj = icon.toObject();
+ // take the largest icon
+ int largest = 0;
+ for (auto key : obj.keys()) {
+ auto size = key.split('x').first().toInt();
+ if (size > largest) {
+ largest = size;
+ }
+ }
+ if (largest > 0) {
+ auto key = QString::number(largest) + "x" + QString::number(largest);
+ details.icon_file = obj.value(key).toString();
+ } else { // parsing the sizes failed
+ // take the first
+ for (auto i : obj) {
+ details.icon_file = i.toString();
+ break;
+ }
+ }
+ } else if (icon.isString()) {
+ details.icon_file = icon.toString();
+ }
+ }
+
}
return details;
}
@@ -515,6 +647,85 @@ bool validate(QFileInfo file)
return ModUtils::process(mod, ProcessingLevel::BasicInfoOnly) && mod.valid();
}
+bool processIconPNG(const Mod& mod, QByteArray&& raw_data)
+{
+ auto img = QImage::fromData(raw_data);
+ if (!img.isNull()) {
+ mod.setIcon(img);
+ } else {
+ qWarning() << "Failed to parse mod logo:" << mod.iconPath() << "from" << mod.name();
+ return false;
+ }
+ return true;
+}
+
+bool loadIconFile(const Mod& mod) {
+ if (mod.iconPath().isEmpty()) {
+ qWarning() << "No Iconfile set, be sure to parse the mod first";
+ return false;
+ }
+
+ auto png_invalid = [&mod]() {
+ qWarning() << "Mod at" << mod.fileinfo().filePath() << "does not have a valid icon";
+ return false;
+ };
+
+ switch (mod.type()) {
+ case ResourceType::FOLDER:
+ {
+ QFileInfo icon_info(FS::PathCombine(mod.fileinfo().filePath(), mod.iconPath()));
+ if (icon_info.exists() && icon_info.isFile()) {
+ QFile icon(icon_info.filePath());
+ if (!icon.open(QIODevice::ReadOnly))
+ return false;
+ auto data = icon.readAll();
+
+ bool icon_result = ModUtils::processIconPNG(mod, std::move(data));
+
+ icon.close();
+
+ if (!icon_result) {
+ return png_invalid(); // icon invalid
+ }
+ }
+ }
+ case ResourceType::ZIPFILE:
+ {
+ QuaZip zip(mod.fileinfo().filePath());
+ if (!zip.open(QuaZip::mdUnzip))
+ return false;
+
+ QuaZipFile file(&zip);
+
+ if (zip.setCurrentFile(mod.iconPath())) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open file in zip.";
+ zip.close();
+ return png_invalid();
+ }
+
+ auto data = file.readAll();
+
+ bool icon_result = ModUtils::processIconPNG(mod, std::move(data));
+
+ file.close();
+ if (!icon_result) {
+ return png_invalid(); // icon png invalid
+ }
+ } else {
+ return png_invalid(); // could not set icon as current file.
+ }
+ }
+ case ResourceType::LITEMOD:
+ {
+ return false; // can lightmods even have icons?
+ }
+ default:
+ qWarning() << "Invalid type for mod, can not load icon.";
+ return false;
+ }
+}
+
} // namespace ModUtils
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.h b/launcher/minecraft/mod/tasks/LocalModParseTask.h
index 38dae135..a0321709 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.h
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.h
@@ -25,6 +25,9 @@ bool processLitemod(Mod& mod, ProcessingLevel level = ProcessingLevel::Full);
/** Checks whether a file is valid as a mod or not. */
bool validate(QFileInfo file);
+
+bool processIconPNG(const Mod& mod, QByteArray&& raw_data);
+bool loadIconFile(const Mod& mod);
} // namespace ModUtils
class LocalModParseTask : public Task {
diff --git a/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp b/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp
index cc4e252c..4352fad9 100644
--- a/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp
@@ -1,25 +1,24 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
-* 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/>.
-*/
+ * Prism Launcher - 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/>.
+ */
#include "LocalModUpdateTask.h"
-#include "Application.h"
#include "FileSystem.h"
#include "minecraft/mod/MetadataHandler.h"
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
index 4bf0b80d..a67c56a8 100644
--- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp
@@ -165,15 +165,16 @@ bool processZIP(ResourcePack& pack, ProcessingLevel level)
bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data));
file.close();
+ zip.close();
if (!pack_png_result) {
return png_invalid(); // pack.png invalid
}
} else {
+ zip.close();
return png_invalid(); // could not set pack.mcmeta as current file.
}
zip.close();
-
return true;
}
@@ -193,7 +194,7 @@ bool processMCMeta(ResourcePack& pack, QByteArray&& raw_data)
return true;
}
-bool processPackPNG(ResourcePack& pack, QByteArray&& raw_data)
+bool processPackPNG(const ResourcePack& pack, QByteArray&& raw_data)
{
auto img = QImage::fromData(raw_data);
if (!img.isNull()) {
@@ -205,6 +206,68 @@ bool processPackPNG(ResourcePack& pack, QByteArray&& raw_data)
return true;
}
+bool processPackPNG(const ResourcePack& pack)
+{
+ auto png_invalid = [&pack]() {
+ qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png";
+ return false;
+ };
+
+ switch (pack.type()) {
+ case ResourceType::FOLDER:
+ {
+ 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 png_invalid(); // can't open pack.png file
+
+ auto data = pack_png_file.readAll();
+
+ bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data));
+
+ pack_png_file.close();
+ if (!pack_png_result) {
+ return png_invalid(); // pack.png invalid
+ }
+ } else {
+ return png_invalid(); // pack.png does not exists or is not a valid file.
+ }
+ }
+ case ResourceType::ZIPFILE:
+ {
+ 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.png")) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open file in zip.";
+ zip.close();
+ return png_invalid();
+ }
+
+ auto data = file.readAll();
+
+ bool pack_png_result = ResourcePackUtils::processPackPNG(pack, std::move(data));
+
+ file.close();
+ if (!pack_png_result) {
+ return png_invalid(); // pack.png invalid
+ }
+ } else {
+ return png_invalid(); // could not set pack.mcmeta as current file.
+ }
+ }
+ default:
+ qWarning() << "Invalid type for resource pack parse task!";
+ return false;
+ }
+}
+
bool validate(QFileInfo file)
{
ResourcePack rp{ file };
diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
index d0c24c2b..58d90b3b 100644
--- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
+++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.h
@@ -35,7 +35,10 @@ bool processZIP(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Ful
bool processFolder(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full);
bool processMCMeta(ResourcePack& pack, QByteArray&& raw_data);
-bool processPackPNG(ResourcePack& pack, QByteArray&& raw_data);
+bool processPackPNG(const ResourcePack& pack, QByteArray&& raw_data);
+
+/// processes ONLY the pack.png (rest of the pack may be invalid)
+bool processPackPNG(const ResourcePack& pack);
/** 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 38f1d7c1..a72e8115 100644
--- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp
@@ -131,6 +131,7 @@ bool processZIP(TexturePack& pack, ProcessingLevel level)
bool packPNG_result = TexturePackUtils::processPackPNG(pack, std::move(data));
file.close();
+ zip.close();
if (!packPNG_result) {
return false;
}
@@ -147,7 +148,7 @@ bool processPackTXT(TexturePack& pack, QByteArray&& raw_data)
return true;
}
-bool processPackPNG(TexturePack& pack, QByteArray&& raw_data)
+bool processPackPNG(const TexturePack& pack, QByteArray&& raw_data)
{
auto img = QImage::fromData(raw_data);
if (!img.isNull()) {
@@ -159,6 +160,70 @@ bool processPackPNG(TexturePack& pack, QByteArray&& raw_data)
return true;
}
+bool processPackPNG(const TexturePack& pack)
+{
+ auto png_invalid = [&pack]() {
+ qWarning() << "Texture pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png";
+ return false;
+ };
+
+ switch (pack.type()) {
+ case ResourceType::FOLDER:
+ {
+ 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 png_invalid(); // can't open pack.png file
+
+ auto data = pack_png_file.readAll();
+
+ bool pack_png_result = TexturePackUtils::processPackPNG(pack, std::move(data));
+
+ pack_png_file.close();
+ if (!pack_png_result) {
+ return png_invalid(); // pack.png invalid
+ }
+ } else {
+ return png_invalid(); // pack.png does not exists or is not a valid file.
+ }
+ }
+ case ResourceType::ZIPFILE:
+ {
+ 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.png")) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open file in zip.";
+ zip.close();
+ return png_invalid();
+ }
+
+ auto data = file.readAll();
+
+ bool pack_png_result = TexturePackUtils::processPackPNG(pack, std::move(data));
+
+ file.close();
+ if (!pack_png_result) {
+ zip.close();
+ return png_invalid(); // pack.png invalid
+ }
+ } else {
+ zip.close();
+ return png_invalid(); // could not set pack.mcmeta as current file.
+ }
+ }
+ default:
+ qWarning() << "Invalid type for resource pack parse task!";
+ return false;
+ }
+}
+
bool validate(QFileInfo file)
{
TexturePack rp{ file };
diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h
index 1589f8cb..6b91565a 100644
--- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h
+++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.h
@@ -36,7 +36,10 @@ bool processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full
bool processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full);
bool processPackTXT(TexturePack& pack, QByteArray&& raw_data);
-bool processPackPNG(TexturePack& pack, QByteArray&& raw_data);
+bool processPackPNG(const TexturePack& pack, QByteArray&& raw_data);
+
+/// processes ONLY the pack.png (rest of the pack may be invalid)
+bool processPackPNG(const TexturePack& pack);
/** Checks whether a file is valid as a texture pack or not. */
bool validate(QFileInfo file);