diff options
Diffstat (limited to 'meshmc/launcher/minecraft/Library.cpp')
| -rw-r--r-- | meshmc/launcher/minecraft/Library.cpp | 282 |
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); +} |
