summaryrefslogtreecommitdiff
path: root/meshmc/launcher/minecraft/Library.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'meshmc/launcher/minecraft/Library.cpp')
-rw-r--r--meshmc/launcher/minecraft/Library.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/meshmc/launcher/minecraft/Library.cpp b/meshmc/launcher/minecraft/Library.cpp
new file mode 100644
index 0000000000..8ecc32d200
--- /dev/null
+++ b/meshmc/launcher/minecraft/Library.cpp
@@ -0,0 +1,282 @@
+/* SPDX-FileCopyrightText: 2026 Project Tick
+ * SPDX-FileContributor: Project Tick
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * MeshMC - A Custom Launcher for Minecraft
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "Library.h"
+#include "MinecraftInstance.h"
+
+#include <net/Download.h>
+#include <net/ChecksumValidator.h>
+#include <FileSystem.h>
+#include <BuildConfig.h>
+
+void Library::getApplicableFiles(OpSys system, QStringList& jar,
+ QStringList& native, QStringList& native32,
+ QStringList& native64,
+ const QString& overridePath) const
+{
+ bool local = isLocal();
+ auto actualPath = [&](QString relPath) {
+ QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
+ if (local && !overridePath.isEmpty()) {
+ QString fileName = out.fileName();
+ return QFileInfo(FS::PathCombine(overridePath, fileName))
+ .absoluteFilePath();
+ }
+ return out.absoluteFilePath();
+ };
+ QString raw_storage = storageSuffix(system);
+ if (isNative()) {
+ if (raw_storage.contains("${arch}")) {
+ auto nat32Storage = raw_storage;
+ nat32Storage.replace("${arch}", "32");
+ auto nat64Storage = raw_storage;
+ nat64Storage.replace("${arch}", "64");
+ native32 += actualPath(nat32Storage);
+ native64 += actualPath(nat64Storage);
+ } else {
+ native += actualPath(raw_storage);
+ }
+ } else {
+ jar += actualPath(raw_storage);
+ }
+}
+
+QList<NetAction::Ptr> Library::getDownloads(OpSys system,
+ class HttpMetaCache* cache,
+ QStringList& failedLocalFiles,
+ const QString& overridePath) const
+{
+ QList<NetAction::Ptr> out;
+ bool stale = isAlwaysStale();
+ bool local = isLocal();
+
+ auto check_local_file = [&](QString storage) {
+ QFileInfo fileinfo(storage);
+ QString fileName = fileinfo.fileName();
+ auto fullPath = FS::PathCombine(overridePath, fileName);
+ QFileInfo localFileInfo(fullPath);
+ if (!localFileInfo.exists()) {
+ failedLocalFiles.append(localFileInfo.filePath());
+ return false;
+ }
+ return true;
+ };
+
+ auto add_download = [&](QString storage, QString url, QString sha1) {
+ if (local) {
+ return check_local_file(storage);
+ }
+ auto entry = cache->resolveEntry("libraries", storage);
+ if (stale) {
+ entry->setStale(true);
+ }
+ if (!entry->isStale())
+ return true;
+ Net::Download::Options options;
+ if (stale) {
+ options |= Net::Download::Option::AcceptLocalFiles;
+ }
+
+ if (sha1.size()) {
+ auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
+ auto dl = Net::Download::makeCached(url, entry, options);
+ dl->addValidator(
+ new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
+ qDebug() << "Checksummed Download for:" << rawName().serialize()
+ << "storage:" << storage << "url:" << url;
+ out.append(dl);
+ } else {
+ out.append(Net::Download::makeCached(url, entry, options));
+ qDebug() << "Download for:" << rawName().serialize()
+ << "storage:" << storage << "url:" << url;
+ }
+ return true;
+ };
+
+ QString raw_storage = storageSuffix(system);
+ if (m_mojangDownloads) {
+ if (isNative()) {
+ if (m_nativeClassifiers.contains(system)) {
+ auto nativeClassifier = m_nativeClassifiers[system];
+ if (nativeClassifier.contains("${arch}")) {
+ auto nat32Classifier = nativeClassifier;
+ nat32Classifier.replace("${arch}", "32");
+ auto nat64Classifier = nativeClassifier;
+ nat64Classifier.replace("${arch}", "64");
+ auto nat32info =
+ m_mojangDownloads->getDownloadInfo(nat32Classifier);
+ if (nat32info) {
+ auto cooked_storage = raw_storage;
+ cooked_storage.replace("${arch}", "32");
+ add_download(cooked_storage, nat32info->url,
+ nat32info->sha1);
+ }
+ auto nat64info =
+ m_mojangDownloads->getDownloadInfo(nat64Classifier);
+ if (nat64info) {
+ auto cooked_storage = raw_storage;
+ cooked_storage.replace("${arch}", "64");
+ add_download(cooked_storage, nat64info->url,
+ nat64info->sha1);
+ }
+ } else {
+ auto info =
+ m_mojangDownloads->getDownloadInfo(nativeClassifier);
+ if (info) {
+ add_download(raw_storage, info->url, info->sha1);
+ }
+ }
+ } else {
+ qDebug() << "Ignoring native library" << m_name.serialize()
+ << "because it has no classifier for current OS";
+ }
+ } else {
+ if (m_mojangDownloads->artifact) {
+ auto artifact = m_mojangDownloads->artifact;
+ add_download(raw_storage, artifact->url, artifact->sha1);
+ } else {
+ qDebug() << "Ignoring java library" << m_name.serialize()
+ << "because it has no artifact";
+ }
+ }
+ } else {
+ auto raw_dl = [&]() {
+ if (!m_absoluteURL.isEmpty()) {
+ return m_absoluteURL;
+ }
+
+ if (m_repositoryURL.isEmpty()) {
+ return BuildConfig.LIBRARY_BASE + raw_storage;
+ }
+
+ if (m_repositoryURL.endsWith('/')) {
+ return m_repositoryURL + raw_storage;
+ } else {
+ return m_repositoryURL + QChar('/') + raw_storage;
+ }
+ }();
+ if (raw_storage.contains("${arch}")) {
+ QString cooked_storage = raw_storage;
+ QString cooked_dl = raw_dl;
+ add_download(cooked_storage.replace("${arch}", "32"),
+ cooked_dl.replace("${arch}", "32"), QString());
+ cooked_storage = raw_storage;
+ cooked_dl = raw_dl;
+ add_download(cooked_storage.replace("${arch}", "64"),
+ cooked_dl.replace("${arch}", "64"), QString());
+ } else {
+ add_download(raw_storage, raw_dl, QString());
+ }
+ }
+ return out;
+}
+
+bool Library::isActive() const
+{
+ bool result = true;
+ if (m_rules.empty()) {
+ result = true;
+ } else {
+ RuleAction ruleResult = Disallow;
+ for (auto rule : m_rules) {
+ RuleAction temp = rule->apply(this);
+ if (temp != Defer)
+ ruleResult = temp;
+ }
+ result = result && (ruleResult == Allow);
+ }
+ if (isNative()) {
+ result = result && m_nativeClassifiers.contains(currentSystem);
+ }
+ return result;
+}
+
+bool Library::isLocal() const
+{
+ return m_hint == "local";
+}
+
+bool Library::isAlwaysStale() const
+{
+ return m_hint == "always-stale";
+}
+
+void Library::setStoragePrefix(QString prefix)
+{
+ m_storagePrefix = prefix;
+}
+
+QString Library::defaultStoragePrefix()
+{
+ return "libraries/";
+}
+
+QString Library::storagePrefix() const
+{
+ if (m_storagePrefix.isEmpty()) {
+ return defaultStoragePrefix();
+ }
+ return m_storagePrefix;
+}
+
+QString Library::filename(OpSys system) const
+{
+ if (!m_filename.isEmpty()) {
+ return m_filename;
+ }
+ // non-native? use only the gradle specifier
+ if (!isNative()) {
+ return m_name.getFileName();
+ }
+
+ // otherwise native, override classifiers. Mojang HACK!
+ GradleSpecifier nativeSpec = m_name;
+ if (m_nativeClassifiers.contains(system)) {
+ nativeSpec.setClassifier(m_nativeClassifiers[system]);
+ } else {
+ nativeSpec.setClassifier("INVALID");
+ }
+ return nativeSpec.getFileName();
+}
+
+QString Library::displayName(OpSys system) const
+{
+ if (!m_displayname.isEmpty())
+ return m_displayname;
+ return filename(system);
+}
+
+QString Library::storageSuffix(OpSys system) const
+{
+ // non-native? use only the gradle specifier
+ if (!isNative()) {
+ return m_name.toPath(m_filename);
+ }
+
+ // otherwise native, override classifiers. Mojang HACK!
+ GradleSpecifier nativeSpec = m_name;
+ if (m_nativeClassifiers.contains(system)) {
+ nativeSpec.setClassifier(m_nativeClassifiers[system]);
+ } else {
+ nativeSpec.setClassifier("INVALID");
+ }
+ return nativeSpec.toPath(m_filename);
+}