summaryrefslogtreecommitdiff
path: root/archived/projt-launcher/launcher/minecraft/Component.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
commitd3261e64152397db2dca4d691a990c6bc2a6f4dd (patch)
treefac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/launcher/minecraft/Component.cpp
parent31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff)
downloadProject-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.tar.gz
Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.zip
NOISSUE add archived projects
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'archived/projt-launcher/launcher/minecraft/Component.cpp')
-rw-r--r--archived/projt-launcher/launcher/minecraft/Component.cpp576
1 files changed, 576 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/minecraft/Component.cpp b/archived/projt-launcher/launcher/minecraft/Component.cpp
new file mode 100644
index 0000000000..2cb5054e3f
--- /dev/null
+++ b/archived/projt-launcher/launcher/minecraft/Component.cpp
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-FileCopyrightText: 2026 Project Tick
+// SPDX-FileContributor: Project Tick Team
+/*
+ * ProjT Launcher - Minecraft Launcher
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * === Upstream License Block (Do Not Modify) ==============================
+ *
+ *
+ *
+ * Prism Launcher - 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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 "Component.h"
+#include <meta/Index.hpp>
+#include <meta/VersionList.hpp>
+
+#include <QSaveFile>
+
+#include "Application.h"
+#include "FileSystem.h"
+#include "OneSixVersionFormat.h"
+#include "VersionFile.h"
+#include "meta/Version.hpp"
+#include "minecraft/Component.h"
+#include "minecraft/PackProfile.h"
+
+#include <assert.h>
+
+const QMap<QString, ModloaderMapEntry> Component::KNOWN_MODLOADERS = {
+ { "net.neoforged",
+ { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "org.quiltmc.quilt-loader" } } },
+ { "net.minecraftforge",
+ { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "org.quiltmc.quilt-loader" } } },
+ { "net.fabricmc.fabric-loader",
+ { ModPlatform::Fabric, { "net.minecraftforge", "net.neoforged", "org.quiltmc.quilt-loader" } } },
+ { "org.quiltmc.quilt-loader",
+ { ModPlatform::Quilt, { "net.minecraftforge", "net.neoforged", "net.fabricmc.fabric-loader" } } },
+ { "com.mumfrey.liteloader", { ModPlatform::LiteLoader, {} } }
+};
+
+Component::Component(PackProfile* parent, const QString& uid)
+{
+ assert(parent);
+ m_parent = parent;
+
+ m_uid = uid;
+}
+
+Component::Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file)
+{
+ assert(parent);
+ m_parent = parent;
+
+ m_file = file;
+ m_uid = uid;
+ m_cachedVersion = m_file->version;
+ m_cachedName = m_file->name;
+ m_loaded = true;
+}
+
+std::shared_ptr<projt::meta::MetaVersion> Component::getMeta()
+{
+ return m_metaVersion;
+}
+
+void Component::applyTo(LaunchProfile* profile)
+{
+ // do not apply disabled components
+ if (!isEnabled())
+ {
+ return;
+ }
+ auto vfile = getVersionFile();
+ if (vfile)
+ {
+ vfile->applyTo(profile, m_parent->runtimeContext());
+ }
+ else
+ {
+ profile->applyProblemSeverity(getProblemSeverity());
+ }
+}
+
+std::shared_ptr<class VersionFile> Component::getVersionFile() const
+{
+ if (m_metaVersion)
+ {
+ return m_metaVersion->detailedData();
+ }
+ else
+ {
+ return m_file;
+ }
+}
+
+std::shared_ptr<projt::meta::MetaVersionList> Component::getVersionList() const
+{
+ // Return nullptr if metadata index isn't loaded yet - caller should handle this case
+ auto index = APPLICATION->metadataIndex();
+ if (!index || !index->hasComponent(m_uid))
+ {
+ return nullptr;
+ }
+ return index->component(m_uid);
+}
+
+int Component::getOrder()
+{
+ if (m_orderOverride)
+ return m_order;
+
+ auto vfile = getVersionFile();
+ if (vfile)
+ {
+ return vfile->order;
+ }
+ return 0;
+}
+
+void Component::setOrder(int order)
+{
+ m_orderOverride = true;
+ m_order = order;
+}
+
+QString Component::getID()
+{
+ return m_uid;
+}
+
+QString Component::getName()
+{
+ if (!m_cachedName.isEmpty())
+ return m_cachedName;
+ return m_uid;
+}
+
+QString Component::getVersion()
+{
+ return m_cachedVersion;
+}
+
+QString Component::getFilename()
+{
+ return m_parent->patchFilePathForUid(m_uid);
+}
+
+QDateTime Component::getReleaseDateTime()
+{
+ if (m_metaVersion)
+ {
+ return m_metaVersion->releaseTime();
+ }
+ auto vfile = getVersionFile();
+ if (vfile)
+ {
+ return vfile->releaseTime;
+ }
+ // Fallback: return current time when no release time is available (e.g., custom components)
+ return QDateTime::currentDateTime();
+}
+
+bool Component::isEnabled()
+{
+ return !canBeDisabled() || !m_disabled;
+}
+
+bool Component::canBeDisabled()
+{
+ return isRemovable() && !m_dependencyOnly;
+}
+
+bool Component::setEnabled(bool state)
+{
+ bool intendedDisabled = !state;
+ if (!canBeDisabled())
+ {
+ intendedDisabled = false;
+ }
+ if (intendedDisabled != m_disabled)
+ {
+ m_disabled = intendedDisabled;
+ emit dataChanged();
+ return true;
+ }
+ return false;
+}
+
+bool Component::isCustom()
+{
+ return m_file != nullptr;
+}
+
+bool Component::isCustomizable()
+{
+ return m_metaVersion && getVersionFile();
+}
+
+bool Component::isRemovable()
+{
+ return !m_important;
+}
+
+bool Component::isRevertible()
+{
+ if (isCustom())
+ {
+ if (APPLICATION->metadataIndex()->hasComponent(m_uid))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Component::isMoveable()
+{
+ // Important components (like Minecraft) should stay at their fixed position
+ // Non-important components can be reordered by the user
+ return !m_important;
+}
+
+bool Component::isVersionChangeable(bool wait)
+{
+ auto list = getVersionList();
+ if (list)
+ {
+ if (wait)
+ list->waitUntilReady();
+ return list->count() != 0;
+ }
+ return false;
+}
+
+bool Component::isKnownModloader()
+{
+ auto iter = KNOWN_MODLOADERS.find(m_uid);
+ return iter != KNOWN_MODLOADERS.cend();
+}
+
+QStringList Component::knownConflictingComponents()
+{
+ auto iter = KNOWN_MODLOADERS.find(m_uid);
+ if (iter != KNOWN_MODLOADERS.cend())
+ {
+ return (*iter).knownConflictingComponents;
+ }
+ else
+ {
+ return {};
+ }
+}
+
+void Component::setImportant(bool state)
+{
+ if (m_important != state)
+ {
+ m_important = state;
+ emit dataChanged();
+ }
+}
+
+ProblemSeverity Component::getProblemSeverity() const
+{
+ auto file = getVersionFile();
+ if (file)
+ {
+ auto severity = file->getProblemSeverity();
+ return m_componentProblemSeverity > severity ? m_componentProblemSeverity : severity;
+ }
+ return ProblemSeverity::Error;
+}
+
+const QList<PatchProblem> Component::getProblems() const
+{
+ auto file = getVersionFile();
+ if (file)
+ {
+ auto problems = file->getProblems();
+ problems.append(m_componentProblems);
+ return problems;
+ }
+ return { { ProblemSeverity::Error, QObject::tr("Patch is not loaded yet.") } };
+}
+
+void Component::addComponentProblem(ProblemSeverity severity, const QString& description)
+{
+ if (severity > m_componentProblemSeverity)
+ {
+ m_componentProblemSeverity = severity;
+ }
+ m_componentProblems.append({ severity, description });
+
+ emit dataChanged();
+}
+
+void Component::resetComponentProblems()
+{
+ m_componentProblems.clear();
+ m_componentProblemSeverity = ProblemSeverity::None;
+
+ emit dataChanged();
+}
+
+void Component::setVersion(const QString& version)
+{
+ if (version == m_version)
+ {
+ return;
+ }
+ m_version = version;
+ if (m_loaded)
+ {
+ // we are loaded and potentially have state to invalidate
+ if (m_file)
+ {
+ // we have a file... explicit version has been changed and there is nothing else to do.
+ }
+ else
+ {
+ // we don't have a file, therefore we are loaded with metadata
+ m_cachedVersion = version;
+ // see if the meta version is loaded
+ auto metaVersion = APPLICATION->metadataIndex()->version(m_uid, version);
+ if (metaVersion->isFullyLoaded())
+ {
+ // if yes, we can continue with that.
+ m_metaVersion = metaVersion;
+ }
+ else
+ {
+ // if not, we need loading
+ m_metaVersion.reset();
+ m_loaded = false;
+ }
+ updateCachedData();
+ }
+ }
+ else
+ {
+ // not loaded... assume it will be sorted out later by the update task
+ }
+ emit dataChanged();
+}
+
+bool Component::customize()
+{
+ if (isCustom())
+ {
+ return false;
+ }
+
+ auto filename = getFilename();
+ if (!FS::ensureFilePathExists(filename))
+ {
+ return false;
+ }
+ // Using try-catch to handle potential JSON serialization errors gracefully
+ try
+ {
+ QSaveFile jsonFile(filename);
+ if (!jsonFile.open(QIODevice::WriteOnly))
+ {
+ return false;
+ }
+ auto vfile = getVersionFile();
+ if (!vfile)
+ {
+ return false;
+ }
+ auto document = OneSixVersionFormat::versionFileToJson(vfile);
+ jsonFile.write(document.toJson());
+ if (!jsonFile.commit())
+ {
+ return false;
+ }
+ m_file = vfile;
+ m_metaVersion.reset();
+ emit dataChanged();
+ }
+ catch (const Exception& error)
+ {
+ qWarning() << "Version could not be loaded:" << error.cause();
+ }
+ return true;
+}
+
+bool Component::revert()
+{
+ if (!isCustom())
+ {
+ // already not custom
+ return true;
+ }
+ auto filename = getFilename();
+ bool result = true;
+ // just kill the file and reload
+ if (QFile::exists(filename))
+ {
+ result = FS::deletePath(filename);
+ }
+ if (result)
+ {
+ // file gone...
+ m_file.reset();
+
+ // check local cache for metadata...
+ auto version = APPLICATION->metadataIndex()->version(m_uid, m_version);
+ if (version->isFullyLoaded())
+ {
+ m_metaVersion = version;
+ }
+ else
+ {
+ m_metaVersion.reset();
+ m_loaded = false;
+ }
+ emit dataChanged();
+ }
+ return result;
+}
+
+/**
+ * deep inspecting compare for requirement sets
+ * By default, only uids are compared for set operations.
+ * This compares all fields of the Require structs in the sets.
+ */
+static bool deepCompare(const projt::meta::DependencySet& a, const projt::meta::DependencySet& b)
+{
+ // NOTE: this needs to be rewritten if the type of DependencySet changes
+ if (a.size() != b.size())
+ {
+ return false;
+ }
+ for (const auto& reqA : a)
+ {
+ const auto& iter2 = b.find(reqA);
+ if (iter2 == b.cend())
+ {
+ return false;
+ }
+ const auto& reqB = *iter2;
+ if (!reqA.deepEquals(reqB))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Component::updateCachedData()
+{
+ auto file = getVersionFile();
+ if (file)
+ {
+ bool changed = false;
+ if (m_cachedName != file->name)
+ {
+ m_cachedName = file->name;
+ changed = true;
+ }
+ if (m_cachedVersion != file->version)
+ {
+ m_cachedVersion = file->version;
+ changed = true;
+ }
+ if (m_cachedVolatile != file->m_volatile)
+ {
+ m_cachedVolatile = file->m_volatile;
+ changed = true;
+ }
+ if (!deepCompare(m_cachedRequires, file->m_requires))
+ {
+ m_cachedRequires = file->m_requires;
+ changed = true;
+ }
+ if (!deepCompare(m_cachedConflicts, file->conflicts))
+ {
+ m_cachedConflicts = file->conflicts;
+ changed = true;
+ }
+ if (changed)
+ {
+ emit dataChanged();
+ }
+ }
+ else
+ {
+ // in case we removed all the metadata
+ m_cachedRequires.clear();
+ m_cachedConflicts.clear();
+ emit dataChanged();
+ }
+}
+
+void Component::waitLoadMeta()
+{
+ if (!m_loaded)
+ {
+ if (!m_metaVersion || !m_metaVersion->isFullyLoaded())
+ {
+ // wait for the loaded version from meta
+ m_metaVersion = APPLICATION->metadataIndex()->loadVersionBlocking(m_uid, m_version);
+ }
+ m_loaded = true;
+ updateCachedData();
+ }
+}
+
+void Component::setUpdateAction(const UpdateAction& action)
+{
+ m_updateAction = action;
+}
+
+UpdateAction Component::getUpdateAction()
+{
+ return m_updateAction;
+}
+
+void Component::clearUpdateAction()
+{
+ m_updateAction = UpdateAction{ UpdateActionNone{} };
+}
+
+QDebug operator<<(QDebug d, const Component& comp)
+{
+ d << "Component(" << comp.m_uid << " : " << comp.m_cachedVersion << ")";
+ return d;
+}