From 20b9f2b42a3b58b6081af271774fbcc34025dccb Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 25 Jul 2021 19:11:59 +0200 Subject: NOISSUE Flatten gui and logic libraries into MultiMC --- api/logic/minecraft/AssetsUtils.cpp | 333 ------ api/logic/minecraft/AssetsUtils.h | 53 - api/logic/minecraft/Component.cpp | 439 ------- api/logic/minecraft/Component.h | 111 -- api/logic/minecraft/ComponentUpdateTask.cpp | 704 ----------- api/logic/minecraft/ComponentUpdateTask.h | 37 - api/logic/minecraft/ComponentUpdateTask_p.h | 32 - api/logic/minecraft/GradleSpecifier.h | 151 --- api/logic/minecraft/GradleSpecifier_test.cpp | 78 -- api/logic/minecraft/LaunchProfile.cpp | 319 ----- api/logic/minecraft/LaunchProfile.h | 104 -- api/logic/minecraft/Library.cpp | 309 ----- api/logic/minecraft/Library.h | 219 ---- api/logic/minecraft/Library_test.cpp | 272 ----- api/logic/minecraft/MinecraftInstance.cpp | 1054 ----------------- api/logic/minecraft/MinecraftInstance.h | 133 --- api/logic/minecraft/MinecraftLoadAndCheck.cpp | 45 - api/logic/minecraft/MinecraftLoadAndCheck.h | 48 - api/logic/minecraft/MinecraftUpdate.cpp | 182 --- api/logic/minecraft/MinecraftUpdate.h | 57 - api/logic/minecraft/MojangDownloadInfo.h | 82 -- api/logic/minecraft/MojangVersionFormat.cpp | 383 ------ api/logic/minecraft/MojangVersionFormat.h | 26 - api/logic/minecraft/MojangVersionFormat_test.cpp | 55 - api/logic/minecraft/OneSixVersionFormat.cpp | 391 ------- api/logic/minecraft/OneSixVersionFormat.h | 30 - api/logic/minecraft/OpSys.cpp | 42 - api/logic/minecraft/OpSys.h | 37 - api/logic/minecraft/PackProfile.cpp | 1225 -------------------- api/logic/minecraft/PackProfile.h | 152 --- api/logic/minecraft/PackProfile_p.h | 42 - api/logic/minecraft/ParseUtils.cpp | 34 - api/logic/minecraft/ParseUtils.h | 11 - api/logic/minecraft/ParseUtils_test.cpp | 45 - api/logic/minecraft/ProfileUtils.cpp | 178 --- api/logic/minecraft/ProfileUtils.h | 28 - api/logic/minecraft/Rule.cpp | 93 -- api/logic/minecraft/Rule.h | 101 -- api/logic/minecraft/VersionFile.cpp | 60 - api/logic/minecraft/VersionFile.h | 114 -- api/logic/minecraft/VersionFilterData.cpp | 71 -- api/logic/minecraft/VersionFilterData.h | 31 - api/logic/minecraft/World.cpp | 520 --------- api/logic/minecraft/World.h | 113 -- api/logic/minecraft/WorldList.cpp | 387 ------- api/logic/minecraft/WorldList.h | 131 --- api/logic/minecraft/auth-msa/BuildConfig.cpp.in | 9 - api/logic/minecraft/auth-msa/BuildConfig.h | 11 - api/logic/minecraft/auth-msa/CMakeLists.txt | 28 - api/logic/minecraft/auth-msa/context.cpp | 938 --------------- api/logic/minecraft/auth-msa/context.h | 128 -- api/logic/minecraft/auth-msa/main.cpp | 100 -- api/logic/minecraft/auth-msa/mainwindow.cpp | 97 -- api/logic/minecraft/auth-msa/mainwindow.h | 34 - api/logic/minecraft/auth-msa/mainwindow.ui | 72 -- api/logic/minecraft/auth/AuthSession.cpp | 30 - api/logic/minecraft/auth/AuthSession.h | 54 - api/logic/minecraft/auth/MojangAccount.cpp | 315 ----- api/logic/minecraft/auth/MojangAccount.h | 182 --- api/logic/minecraft/auth/MojangAccountList.cpp | 468 -------- api/logic/minecraft/auth/MojangAccountList.h | 201 ---- api/logic/minecraft/auth/YggdrasilTask.cpp | 255 ---- api/logic/minecraft/auth/YggdrasilTask.h | 151 --- .../minecraft/auth/flows/AuthenticateTask.cpp | 202 ---- api/logic/minecraft/auth/flows/AuthenticateTask.h | 46 - api/logic/minecraft/auth/flows/RefreshTask.cpp | 144 --- api/logic/minecraft/auth/flows/RefreshTask.h | 44 - api/logic/minecraft/auth/flows/ValidateTask.cpp | 61 - api/logic/minecraft/auth/flows/ValidateTask.h | 47 - api/logic/minecraft/gameoptions/GameOptions.cpp | 144 --- api/logic/minecraft/gameoptions/GameOptions.h | 34 - api/logic/minecraft/launch/ClaimAccount.cpp | 24 - api/logic/minecraft/launch/ClaimAccount.h | 37 - api/logic/minecraft/launch/CreateGameFolders.cpp | 28 - api/logic/minecraft/launch/CreateGameFolders.h | 37 - api/logic/minecraft/launch/DirectJavaLaunch.cpp | 148 --- api/logic/minecraft/launch/DirectJavaLaunch.h | 58 - api/logic/minecraft/launch/ExtractNatives.cpp | 111 -- api/logic/minecraft/launch/ExtractNatives.h | 38 - api/logic/minecraft/launch/LauncherPartLaunch.cpp | 218 ---- api/logic/minecraft/launch/LauncherPartLaunch.h | 60 - .../minecraft/launch/MinecraftServerTarget.cpp | 66 -- api/logic/minecraft/launch/MinecraftServerTarget.h | 30 - api/logic/minecraft/launch/ModMinecraftJar.cpp | 82 -- api/logic/minecraft/launch/ModMinecraftJar.h | 36 - api/logic/minecraft/launch/PrintInstanceInfo.cpp | 106 -- api/logic/minecraft/launch/PrintInstanceInfo.h | 41 - api/logic/minecraft/launch/ReconstructAssets.cpp | 36 - api/logic/minecraft/launch/ReconstructAssets.h | 33 - api/logic/minecraft/launch/ScanModFolders.cpp | 59 - api/logic/minecraft/launch/ScanModFolders.h | 42 - api/logic/minecraft/launch/VerifyJavaInstall.cpp | 34 - api/logic/minecraft/launch/VerifyJavaInstall.h | 17 - api/logic/minecraft/legacy/LegacyInstance.cpp | 256 ---- api/logic/minecraft/legacy/LegacyInstance.h | 142 --- api/logic/minecraft/legacy/LegacyModList.cpp | 136 --- api/logic/minecraft/legacy/LegacyModList.h | 49 - api/logic/minecraft/legacy/LegacyUpgradeTask.cpp | 138 --- api/logic/minecraft/legacy/LegacyUpgradeTask.h | 30 - api/logic/minecraft/mod/LocalModParseTask.cpp | 467 -------- api/logic/minecraft/mod/LocalModParseTask.h | 37 - api/logic/minecraft/mod/Mod.cpp | 151 --- api/logic/minecraft/mod/Mod.h | 117 -- api/logic/minecraft/mod/ModDetails.h | 17 - api/logic/minecraft/mod/ModFolderLoadTask.cpp | 18 - api/logic/minecraft/mod/ModFolderLoadTask.h | 29 - api/logic/minecraft/mod/ModFolderModel.cpp | 554 --------- api/logic/minecraft/mod/ModFolderModel.h | 149 --- api/logic/minecraft/mod/ModFolderModel_test.cpp | 53 - .../minecraft/mod/ResourcePackFolderModel.cpp | 23 - api/logic/minecraft/mod/ResourcePackFolderModel.h | 13 - api/logic/minecraft/mod/TexturePackFolderModel.cpp | 23 - api/logic/minecraft/mod/TexturePackFolderModel.h | 13 - api/logic/minecraft/services/SkinDelete.cpp | 42 - api/logic/minecraft/services/SkinDelete.h | 30 - api/logic/minecraft/services/SkinUpload.cpp | 66 -- api/logic/minecraft/services/SkinUpload.h | 39 - api/logic/minecraft/testdata/1.9-simple.json | 198 ---- api/logic/minecraft/testdata/1.9.json | 529 --------- api/logic/minecraft/testdata/codecwav-20101023.jar | 1 - api/logic/minecraft/testdata/lib-native-arch.json | 46 - api/logic/minecraft/testdata/lib-native.json | 52 - api/logic/minecraft/testdata/lib-simple.json | 11 - .../testdata/testname-testversion-linux-32.jar | 1 - api/logic/minecraft/update/AssetUpdateTask.cpp | 107 -- api/logic/minecraft/update/AssetUpdateTask.h | 28 - api/logic/minecraft/update/FMLLibrariesTask.cpp | 131 --- api/logic/minecraft/update/FMLLibrariesTask.h | 31 - api/logic/minecraft/update/FoldersTask.cpp | 21 - api/logic/minecraft/update/FoldersTask.h | 17 - api/logic/minecraft/update/LibrariesTask.cpp | 90 -- api/logic/minecraft/update/LibrariesTask.h | 26 - 132 files changed, 18079 deletions(-) delete mode 100644 api/logic/minecraft/AssetsUtils.cpp delete mode 100644 api/logic/minecraft/AssetsUtils.h delete mode 100644 api/logic/minecraft/Component.cpp delete mode 100644 api/logic/minecraft/Component.h delete mode 100644 api/logic/minecraft/ComponentUpdateTask.cpp delete mode 100644 api/logic/minecraft/ComponentUpdateTask.h delete mode 100644 api/logic/minecraft/ComponentUpdateTask_p.h delete mode 100644 api/logic/minecraft/GradleSpecifier.h delete mode 100644 api/logic/minecraft/GradleSpecifier_test.cpp delete mode 100644 api/logic/minecraft/LaunchProfile.cpp delete mode 100644 api/logic/minecraft/LaunchProfile.h delete mode 100644 api/logic/minecraft/Library.cpp delete mode 100644 api/logic/minecraft/Library.h delete mode 100644 api/logic/minecraft/Library_test.cpp delete mode 100644 api/logic/minecraft/MinecraftInstance.cpp delete mode 100644 api/logic/minecraft/MinecraftInstance.h delete mode 100644 api/logic/minecraft/MinecraftLoadAndCheck.cpp delete mode 100644 api/logic/minecraft/MinecraftLoadAndCheck.h delete mode 100644 api/logic/minecraft/MinecraftUpdate.cpp delete mode 100644 api/logic/minecraft/MinecraftUpdate.h delete mode 100644 api/logic/minecraft/MojangDownloadInfo.h delete mode 100644 api/logic/minecraft/MojangVersionFormat.cpp delete mode 100644 api/logic/minecraft/MojangVersionFormat.h delete mode 100644 api/logic/minecraft/MojangVersionFormat_test.cpp delete mode 100644 api/logic/minecraft/OneSixVersionFormat.cpp delete mode 100644 api/logic/minecraft/OneSixVersionFormat.h delete mode 100644 api/logic/minecraft/OpSys.cpp delete mode 100644 api/logic/minecraft/OpSys.h delete mode 100644 api/logic/minecraft/PackProfile.cpp delete mode 100644 api/logic/minecraft/PackProfile.h delete mode 100644 api/logic/minecraft/PackProfile_p.h delete mode 100644 api/logic/minecraft/ParseUtils.cpp delete mode 100644 api/logic/minecraft/ParseUtils.h delete mode 100644 api/logic/minecraft/ParseUtils_test.cpp delete mode 100644 api/logic/minecraft/ProfileUtils.cpp delete mode 100644 api/logic/minecraft/ProfileUtils.h delete mode 100644 api/logic/minecraft/Rule.cpp delete mode 100644 api/logic/minecraft/Rule.h delete mode 100644 api/logic/minecraft/VersionFile.cpp delete mode 100644 api/logic/minecraft/VersionFile.h delete mode 100644 api/logic/minecraft/VersionFilterData.cpp delete mode 100644 api/logic/minecraft/VersionFilterData.h delete mode 100644 api/logic/minecraft/World.cpp delete mode 100644 api/logic/minecraft/World.h delete mode 100644 api/logic/minecraft/WorldList.cpp delete mode 100644 api/logic/minecraft/WorldList.h delete mode 100644 api/logic/minecraft/auth-msa/BuildConfig.cpp.in delete mode 100644 api/logic/minecraft/auth-msa/BuildConfig.h delete mode 100644 api/logic/minecraft/auth-msa/CMakeLists.txt delete mode 100644 api/logic/minecraft/auth-msa/context.cpp delete mode 100644 api/logic/minecraft/auth-msa/context.h delete mode 100644 api/logic/minecraft/auth-msa/main.cpp delete mode 100644 api/logic/minecraft/auth-msa/mainwindow.cpp delete mode 100644 api/logic/minecraft/auth-msa/mainwindow.h delete mode 100644 api/logic/minecraft/auth-msa/mainwindow.ui delete mode 100644 api/logic/minecraft/auth/AuthSession.cpp delete mode 100644 api/logic/minecraft/auth/AuthSession.h delete mode 100644 api/logic/minecraft/auth/MojangAccount.cpp delete mode 100644 api/logic/minecraft/auth/MojangAccount.h delete mode 100644 api/logic/minecraft/auth/MojangAccountList.cpp delete mode 100644 api/logic/minecraft/auth/MojangAccountList.h delete mode 100644 api/logic/minecraft/auth/YggdrasilTask.cpp delete mode 100644 api/logic/minecraft/auth/YggdrasilTask.h delete mode 100644 api/logic/minecraft/auth/flows/AuthenticateTask.cpp delete mode 100644 api/logic/minecraft/auth/flows/AuthenticateTask.h delete mode 100644 api/logic/minecraft/auth/flows/RefreshTask.cpp delete mode 100644 api/logic/minecraft/auth/flows/RefreshTask.h delete mode 100644 api/logic/minecraft/auth/flows/ValidateTask.cpp delete mode 100644 api/logic/minecraft/auth/flows/ValidateTask.h delete mode 100644 api/logic/minecraft/gameoptions/GameOptions.cpp delete mode 100644 api/logic/minecraft/gameoptions/GameOptions.h delete mode 100644 api/logic/minecraft/launch/ClaimAccount.cpp delete mode 100644 api/logic/minecraft/launch/ClaimAccount.h delete mode 100644 api/logic/minecraft/launch/CreateGameFolders.cpp delete mode 100644 api/logic/minecraft/launch/CreateGameFolders.h delete mode 100644 api/logic/minecraft/launch/DirectJavaLaunch.cpp delete mode 100644 api/logic/minecraft/launch/DirectJavaLaunch.h delete mode 100644 api/logic/minecraft/launch/ExtractNatives.cpp delete mode 100644 api/logic/minecraft/launch/ExtractNatives.h delete mode 100644 api/logic/minecraft/launch/LauncherPartLaunch.cpp delete mode 100644 api/logic/minecraft/launch/LauncherPartLaunch.h delete mode 100644 api/logic/minecraft/launch/MinecraftServerTarget.cpp delete mode 100644 api/logic/minecraft/launch/MinecraftServerTarget.h delete mode 100644 api/logic/minecraft/launch/ModMinecraftJar.cpp delete mode 100644 api/logic/minecraft/launch/ModMinecraftJar.h delete mode 100644 api/logic/minecraft/launch/PrintInstanceInfo.cpp delete mode 100644 api/logic/minecraft/launch/PrintInstanceInfo.h delete mode 100644 api/logic/minecraft/launch/ReconstructAssets.cpp delete mode 100644 api/logic/minecraft/launch/ReconstructAssets.h delete mode 100644 api/logic/minecraft/launch/ScanModFolders.cpp delete mode 100644 api/logic/minecraft/launch/ScanModFolders.h delete mode 100644 api/logic/minecraft/launch/VerifyJavaInstall.cpp delete mode 100644 api/logic/minecraft/launch/VerifyJavaInstall.h delete mode 100644 api/logic/minecraft/legacy/LegacyInstance.cpp delete mode 100644 api/logic/minecraft/legacy/LegacyInstance.h delete mode 100644 api/logic/minecraft/legacy/LegacyModList.cpp delete mode 100644 api/logic/minecraft/legacy/LegacyModList.h delete mode 100644 api/logic/minecraft/legacy/LegacyUpgradeTask.cpp delete mode 100644 api/logic/minecraft/legacy/LegacyUpgradeTask.h delete mode 100644 api/logic/minecraft/mod/LocalModParseTask.cpp delete mode 100644 api/logic/minecraft/mod/LocalModParseTask.h delete mode 100644 api/logic/minecraft/mod/Mod.cpp delete mode 100644 api/logic/minecraft/mod/Mod.h delete mode 100644 api/logic/minecraft/mod/ModDetails.h delete mode 100644 api/logic/minecraft/mod/ModFolderLoadTask.cpp delete mode 100644 api/logic/minecraft/mod/ModFolderLoadTask.h delete mode 100644 api/logic/minecraft/mod/ModFolderModel.cpp delete mode 100644 api/logic/minecraft/mod/ModFolderModel.h delete mode 100644 api/logic/minecraft/mod/ModFolderModel_test.cpp delete mode 100644 api/logic/minecraft/mod/ResourcePackFolderModel.cpp delete mode 100644 api/logic/minecraft/mod/ResourcePackFolderModel.h delete mode 100644 api/logic/minecraft/mod/TexturePackFolderModel.cpp delete mode 100644 api/logic/minecraft/mod/TexturePackFolderModel.h delete mode 100644 api/logic/minecraft/services/SkinDelete.cpp delete mode 100644 api/logic/minecraft/services/SkinDelete.h delete mode 100644 api/logic/minecraft/services/SkinUpload.cpp delete mode 100644 api/logic/minecraft/services/SkinUpload.h delete mode 100644 api/logic/minecraft/testdata/1.9-simple.json delete mode 100644 api/logic/minecraft/testdata/1.9.json delete mode 100644 api/logic/minecraft/testdata/codecwav-20101023.jar delete mode 100644 api/logic/minecraft/testdata/lib-native-arch.json delete mode 100644 api/logic/minecraft/testdata/lib-native.json delete mode 100644 api/logic/minecraft/testdata/lib-simple.json delete mode 100644 api/logic/minecraft/testdata/testname-testversion-linux-32.jar delete mode 100644 api/logic/minecraft/update/AssetUpdateTask.cpp delete mode 100644 api/logic/minecraft/update/AssetUpdateTask.h delete mode 100644 api/logic/minecraft/update/FMLLibrariesTask.cpp delete mode 100644 api/logic/minecraft/update/FMLLibrariesTask.h delete mode 100644 api/logic/minecraft/update/FoldersTask.cpp delete mode 100644 api/logic/minecraft/update/FoldersTask.h delete mode 100644 api/logic/minecraft/update/LibrariesTask.cpp delete mode 100644 api/logic/minecraft/update/LibrariesTask.h (limited to 'api/logic/minecraft') diff --git a/api/logic/minecraft/AssetsUtils.cpp b/api/logic/minecraft/AssetsUtils.cpp deleted file mode 100644 index c01733b6..00000000 --- a/api/logic/minecraft/AssetsUtils.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AssetsUtils.h" -#include "FileSystem.h" -#include "net/Download.h" -#include "net/ChecksumValidator.h" -#include "BuildConfig.h" - -namespace { -QSet collectPathsFromDir(QString dirPath) -{ - QFileInfo dirInfo(dirPath); - - if (!dirInfo.exists()) - { - return {}; - } - - QSet out; - - QDirIterator iter(dirPath, QDirIterator::Subdirectories); - while (iter.hasNext()) - { - QString value = iter.next(); - QFileInfo info(value); - if(info.isFile()) - { - out.insert(value); - qDebug() << value; - } - } - return out; -} -} - - -namespace AssetsUtils -{ - -/* - * Returns true on success, with index populated - * index is undefined otherwise - */ -bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsIndex& index) -{ - /* - { - "objects": { - "icons/icon_16x16.png": { - "hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a", - "size": 3665 - }, - ... - } - } - } - */ - - QFile file(path); - - // Try to open the file and fail if we can't. - // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::ReadOnly)) - { - qCritical() << "Failed to read assets index file" << path; - return false; - } - index.id = assetsId; - - // Read the file and close it. - QByteArray jsonData = file.readAll(); - file.close(); - - QJsonParseError parseError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); - - // Fail if the JSON is invalid. - if (parseError.error != QJsonParseError::NoError) - { - qCritical() << "Failed to parse assets index file:" << parseError.errorString() - << "at offset " << QString::number(parseError.offset); - return false; - } - - // Make sure the root is an object. - if (!jsonDoc.isObject()) - { - qCritical() << "Invalid assets index JSON: Root should be an array."; - return false; - } - - QJsonObject root = jsonDoc.object(); - - QJsonValue isVirtual = root.value("virtual"); - if (!isVirtual.isUndefined()) - { - index.isVirtual = isVirtual.toBool(false); - } - - QJsonValue mapToResources = root.value("map_to_resources"); - if (!mapToResources.isUndefined()) - { - index.mapToResources = mapToResources.toBool(false); - } - - QJsonValue objects = root.value("objects"); - QVariantMap map = objects.toVariant().toMap(); - - for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) - { - // qDebug() << iter.key(); - - QVariant variant = iter.value(); - QVariantMap nested_objects = variant.toMap(); - - AssetObject object; - - for (QVariantMap::const_iterator nested_iter = nested_objects.begin(); - nested_iter != nested_objects.end(); ++nested_iter) - { - // qDebug() << nested_iter.key() << nested_iter.value().toString(); - QString key = nested_iter.key(); - QVariant value = nested_iter.value(); - - if (key == "hash") - { - object.hash = value.toString(); - } - else if (key == "size") - { - object.size = value.toDouble(); - } - } - - index.objects.insert(iter.key(), object); - } - - return true; -} - -// FIXME: ugly code duplication -QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder) -{ - QDir assetsDir = QDir("assets/"); - QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes")); - QDir objectDir = QDir(FS::PathCombine(assetsDir.path(), "objects")); - QDir virtualDir = QDir(FS::PathCombine(assetsDir.path(), "virtual")); - - QString indexPath = FS::PathCombine(indexDir.path(), assetsId + ".json"); - QFile indexFile(indexPath); - QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId)); - - if (!indexFile.exists()) - { - qCritical() << "No assets index file" << indexPath << "; can't determine assets path!"; - return virtualRoot; - } - - AssetsIndex index; - if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) - { - qCritical() << "Failed to load asset index file" << indexPath << "; can't determine assets path!"; - return virtualRoot; - } - - QString targetPath; - if(index.isVirtual) - { - return virtualRoot; - } - else if(index.mapToResources) - { - return QDir(resourcesFolder); - } - return virtualRoot; -} - -// FIXME: ugly code duplication -bool reconstructAssets(QString assetsId, QString resourcesFolder) -{ - QDir assetsDir = QDir("assets/"); - QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes")); - QDir objectDir = QDir(FS::PathCombine(assetsDir.path(), "objects")); - QDir virtualDir = QDir(FS::PathCombine(assetsDir.path(), "virtual")); - - QString indexPath = FS::PathCombine(indexDir.path(), assetsId + ".json"); - QFile indexFile(indexPath); - QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId)); - - if (!indexFile.exists()) - { - qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets!"; - return false; - } - - qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path() << objectDir.path() << virtualDir.path() << virtualRoot.path(); - - AssetsIndex index; - if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) - { - qCritical() << "Failed to load asset index file" << indexPath << "; can't reconstruct assets!"; - return false; - } - - QString targetPath; - bool removeLeftovers = false; - if(index.isVirtual) - { - targetPath = virtualRoot.path(); - removeLeftovers = true; - qDebug() << "Reconstructing virtual assets folder at" << targetPath; - } - else if(index.mapToResources) - { - targetPath = resourcesFolder; - qDebug() << "Reconstructing resources folder at" << targetPath; - } - - if (!targetPath.isNull()) - { - auto presentFiles = collectPathsFromDir(targetPath); - for (QString map : index.objects.keys()) - { - AssetObject asset_object = index.objects.value(map); - QString target_path = FS::PathCombine(targetPath, map); - QFile target(target_path); - - QString tlk = asset_object.hash.left(2); - - QString original_path = FS::PathCombine(objectDir.path(), tlk, asset_object.hash); - QFile original(original_path); - if (!original.exists()) - continue; - - presentFiles.remove(target_path); - - if (!target.exists()) - { - QFileInfo info(target_path); - QDir target_dir = info.dir(); - - qDebug() << target_dir.path(); - FS::ensureFolderPathExists(target_dir.path()); - - bool couldCopy = original.copy(target_path); - qDebug() << " Copying" << original_path << "to" << target_path << QString::number(couldCopy); - } - } - - // TODO: Write last used time to virtualRoot/.lastused - if(removeLeftovers) - { - for(auto & file: presentFiles) - { - qDebug() << "Would remove" << file; - } - } - } - return true; -} - -} - -NetActionPtr AssetObject::getDownloadAction() -{ - QFileInfo objectFile(getLocalPath()); - if ((!objectFile.isFile()) || (objectFile.size() != size)) - { - auto objectDL = Net::Download::makeFile(getUrl(), objectFile.filePath()); - if(hash.size()) - { - auto rawHash = QByteArray::fromHex(hash.toLatin1()); - objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash)); - } - objectDL->m_total_progress = size; - return objectDL; - } - return nullptr; -} - -QString AssetObject::getLocalPath() -{ - return "assets/objects/" + getRelPath(); -} - -QUrl AssetObject::getUrl() -{ - return BuildConfig.RESOURCE_BASE + getRelPath(); -} - -QString AssetObject::getRelPath() -{ - return hash.left(2) + "/" + hash; -} - -NetJobPtr AssetsIndex::getDownloadJob() -{ - auto job = new NetJob(QObject::tr("Assets for %1").arg(id)); - for (auto &object : objects.values()) - { - auto dl = object.getDownloadAction(); - if(dl) - { - job->addNetAction(dl); - } - } - if(job->size()) - return job; - return nullptr; -} diff --git a/api/logic/minecraft/AssetsUtils.h b/api/logic/minecraft/AssetsUtils.h deleted file mode 100644 index 32e57060..00000000 --- a/api/logic/minecraft/AssetsUtils.h +++ /dev/null @@ -1,53 +0,0 @@ -/* 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. - */ - -#pragma once - -#include -#include -#include "net/NetAction.h" -#include "net/NetJob.h" - -struct AssetObject -{ - QString getRelPath(); - QUrl getUrl(); - QString getLocalPath(); - NetActionPtr getDownloadAction(); - - QString hash; - qint64 size; -}; - -struct AssetsIndex -{ - NetJobPtr getDownloadJob(); - - QString id; - QMap objects; - bool isVirtual = false; - bool mapToResources = false; -}; - -/// FIXME: this is absolutely horrendous. REDO!!!! -namespace AssetsUtils -{ -bool loadAssetsIndexJson(const QString &id, const QString &file, AssetsIndex& index); - -QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder); - -/// Reconstruct a virtual assets folder for the given assets ID and return the folder -bool reconstructAssets(QString assetsId, QString resourcesFolder); -} diff --git a/api/logic/minecraft/Component.cpp b/api/logic/minecraft/Component.cpp deleted file mode 100644 index 92821065..00000000 --- a/api/logic/minecraft/Component.cpp +++ /dev/null @@ -1,439 +0,0 @@ -#include -#include -#include -#include "Component.h" - -#include "meta/Version.h" -#include "VersionFile.h" -#include "minecraft/PackProfile.h" -#include -#include -#include "OneSixVersionFormat.h" -#include - -Component::Component(PackProfile * parent, const QString& uid) -{ - assert(parent); - m_parent = parent; - - m_uid = uid; -} - -Component::Component(PackProfile * parent, std::shared_ptr version) -{ - assert(parent); - m_parent = parent; - - m_metaVersion = version; - m_uid = version->uid(); - m_version = m_cachedVersion = version->version(); - m_cachedName = version->name(); - m_loaded = version->isLoaded(); -} - -Component::Component(PackProfile * parent, const QString& uid, std::shared_ptr 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 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); - } - else - { - profile->applyProblemSeverity(getProblemSeverity()); - } -} - -std::shared_ptr Component::getVersionFile() const -{ - if(m_metaVersion) - { - if(!m_metaVersion->isLoaded()) - { - m_metaVersion->load(Net::Mode::Online); - } - return m_metaVersion->data(); - } - else - { - return m_file; - } -} - -std::shared_ptr Component::getVersionList() const -{ - // FIXME: what if the metadata index isn't loaded yet? - if(ENV.metadataIndex()->hasUid(m_uid)) - { - return ENV.metadataIndex()->get(m_uid); - } - return nullptr; -} - -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->time(); - } - auto vfile = getVersionFile(); - if(vfile) - { - return vfile->releaseTime; - } - // FIXME: fake - 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() -{ - if(m_metaVersion) - { - if(getVersionFile()) - { - return true; - } - } - return false; -} -bool Component::isRemovable() -{ - return !m_important; -} -bool Component::isRevertible() -{ - if (isCustom()) - { - if(ENV.metadataIndex()->hasUid(m_uid)) - { - return true; - } - } - return false; -} -bool Component::isMoveable() -{ - // HACK, FIXME: this was too dumb and wouldn't follow dependency constraints anyway. For now hardcoded to 'true'. - return true; -} -bool Component::isVersionChangeable() -{ - auto list = getVersionList(); - if(list) - { - if(!list->isLoaded()) - { - list->load(Net::Mode::Online); - } - return list->count() != 0; - } - return false; -} - -void Component::setImportant(bool state) -{ - if(m_important != state) - { - m_important = state; - emit dataChanged(); - } -} - -ProblemSeverity Component::getProblemSeverity() const -{ - auto file = getVersionFile(); - if(file) - { - return file->getProblemSeverity(); - } - return ProblemSeverity::Error; -} - -const QList Component::getProblems() const -{ - auto file = getVersionFile(); - if(file) - { - return file->getProblems(); - } - return {{ProblemSeverity::Error, QObject::tr("Patch is not loaded yet.")}}; -} - -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 = ENV.metadataIndex()->get(m_uid, version); - if(metaVersion->isLoaded()) - { - // 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; - } - // FIXME: get rid of this try-catch. - 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 = QFile::remove(filename); - } - if(result) - { - // file gone... - m_file.reset(); - - // check local cache for metadata... - auto version = ENV.metadataIndex()->get(m_uid, m_version); - if(version->isLoaded()) - { - 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 std::set & a, const std::set & b) -{ - // NOTE: this needs to be rewritten if the type of Meta::RequireSet 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->requires)) - { - m_cachedRequires = file->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(); - } -} diff --git a/api/logic/minecraft/Component.h b/api/logic/minecraft/Component.h deleted file mode 100644 index cb202f7f..00000000 --- a/api/logic/minecraft/Component.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "meta/JsonFormat.h" -#include "ProblemProvider.h" -#include "QObjectPtr.h" -#include "multimc_logic_export.h" - -class PackProfile; -class LaunchProfile; -namespace Meta -{ - class Version; - class VersionList; -} -class VersionFile; - -class MULTIMC_LOGIC_EXPORT Component : public QObject, public ProblemProvider -{ -Q_OBJECT -public: - Component(PackProfile * parent, const QString &uid); - - // DEPRECATED: remove these constructors? - Component(PackProfile * parent, std::shared_ptr version); - Component(PackProfile * parent, const QString & uid, std::shared_ptr file); - - virtual ~Component(){}; - void applyTo(LaunchProfile *profile); - - bool isEnabled(); - bool setEnabled (bool state); - bool canBeDisabled(); - - bool isMoveable(); - bool isCustomizable(); - bool isRevertible(); - bool isRemovable(); - bool isCustom(); - bool isVersionChangeable(); - - // DEPRECATED: explicit numeric order values, used for loading old non-component config. TODO: refactor and move to migration code - void setOrder(int order); - int getOrder(); - - QString getID(); - QString getName(); - QString getVersion(); - std::shared_ptr getMeta(); - QDateTime getReleaseDateTime(); - - QString getFilename(); - - std::shared_ptr getVersionFile() const; - std::shared_ptr getVersionList() const; - - void setImportant (bool state); - - - const QList getProblems() const override; - ProblemSeverity getProblemSeverity() const override; - - void setVersion(const QString & version); - bool customize(); - bool revert(); - - void updateCachedData(); - -signals: - void dataChanged(); - -public: /* data */ - PackProfile * m_parent; - - // BEGIN: persistent component list properties - /// ID of the component - QString m_uid; - /// version of the component - when there's a custom json override, this is also the version the component reverts to - QString m_version; - /// if true, this has been added automatically to satisfy dependencies and may be automatically removed - bool m_dependencyOnly = false; - /// if true, the component is either the main component of the instance, or otherwise important and cannot be removed. - bool m_important = false; - /// if true, the component is disabled - bool m_disabled = false; - - /// cached name for display purposes, taken from the version file (meta or local override) - QString m_cachedName; - /// cached version for display AND other purposes, taken from the version file (meta or local override) - QString m_cachedVersion; - /// cached set of requirements, taken from the version file (meta or local override) - Meta::RequireSet m_cachedRequires; - Meta::RequireSet m_cachedConflicts; - /// if true, the component is volatile and may be automatically removed when no longer needed - bool m_cachedVolatile = false; - // END: persistent component list properties - - // DEPRECATED: explicit numeric order values, used for loading old non-component config. TODO: refactor and move to migration code - bool m_orderOverride = false; - int m_order = 0; - - // load state - std::shared_ptr m_metaVersion; - std::shared_ptr m_file; - bool m_loaded = false; -}; - -typedef shared_qobject_ptr ComponentPtr; diff --git a/api/logic/minecraft/ComponentUpdateTask.cpp b/api/logic/minecraft/ComponentUpdateTask.cpp deleted file mode 100644 index 241d9a49..00000000 --- a/api/logic/minecraft/ComponentUpdateTask.cpp +++ /dev/null @@ -1,704 +0,0 @@ -#include "ComponentUpdateTask.h" - -#include "PackProfile_p.h" -#include "PackProfile.h" -#include "Component.h" -#include -#include -#include -#include -#include "ComponentUpdateTask_p.h" -#include -#include -#include "net/Mode.h" -#include "OneSixVersionFormat.h" - -/* - * This is responsible for loading the components of a component list AND resolving dependency issues between them - */ - -/* - * FIXME: the 'one shot async task' nature of this does not fit the intended usage - * Really, it should be a reactor/state machine that receives input from the application - * and dynamically adapts to changing requirements... - * - * The reactor should be the only entry into manipulating the PackProfile. - * See: https://en.wikipedia.org/wiki/Reactor_pattern - */ - -/* - * Or make this operate on a snapshot of the PackProfile state, then merge results in as long as the snapshot and PackProfile didn't change? - * If the component list changes, start over. - */ - -ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent) - : Task(parent) -{ - d.reset(new ComponentUpdateTaskData); - d->m_list = list; - d->mode = mode; - d->netmode = netmode; -} - -ComponentUpdateTask::~ComponentUpdateTask() -{ -} - -void ComponentUpdateTask::executeTask() -{ - qDebug() << "Loading components"; - loadComponents(); -} - -namespace -{ -enum class LoadResult -{ - LoadedLocal, - RequiresRemote, - Failed -}; - -LoadResult composeLoadResult(LoadResult a, LoadResult b) -{ - if (a < b) - { - return b; - } - return a; -} - -static LoadResult loadComponent(ComponentPtr component, shared_qobject_ptr& loadTask, Net::Mode netmode) -{ - if(component->m_loaded) - { - qDebug() << component->getName() << "is already loaded"; - return LoadResult::LoadedLocal; - } - - LoadResult result = LoadResult::Failed; - auto customPatchFilename = component->getFilename(); - if(QFile::exists(customPatchFilename)) - { - // if local file exists... - - // check for uid problems inside... - bool fileChanged = false; - auto file = ProfileUtils::parseJsonFile(QFileInfo(customPatchFilename), false); - if(file->uid != component->m_uid) - { - file->uid = component->m_uid; - fileChanged = true; - } - if(fileChanged) - { - // FIXME: @QUALITY do not ignore return value - ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), customPatchFilename); - } - - component->m_file = file; - component->m_loaded = true; - result = LoadResult::LoadedLocal; - } - else - { - auto metaVersion = ENV.metadataIndex()->get(component->m_uid, component->m_version); - component->m_metaVersion = metaVersion; - if(metaVersion->isLoaded()) - { - component->m_loaded = true; - result = LoadResult::LoadedLocal; - } - else - { - metaVersion->load(netmode); - loadTask = metaVersion->getCurrentTask(); - if(loadTask) - result = LoadResult::RequiresRemote; - else if (metaVersion->isLoaded()) - result = LoadResult::LoadedLocal; - else - result = LoadResult::Failed; - } - } - return result; -} - -// FIXME: dead code. determine if this can still be useful? -/* -static LoadResult loadPackProfile(ComponentPtr component, shared_qobject_ptr& loadTask, Net::Mode netmode) -{ - if(component->m_loaded) - { - qDebug() << component->getName() << "is already loaded"; - return LoadResult::LoadedLocal; - } - - LoadResult result = LoadResult::Failed; - auto metaList = ENV.metadataIndex()->get(component->m_uid); - if(metaList->isLoaded()) - { - component->m_loaded = true; - result = LoadResult::LoadedLocal; - } - else - { - metaList->load(netmode); - loadTask = metaList->getCurrentTask(); - result = LoadResult::RequiresRemote; - } - return result; -} -*/ - -static LoadResult loadIndex(shared_qobject_ptr& loadTask, Net::Mode netmode) -{ - // FIXME: DECIDE. do we want to run the update task anyway? - if(ENV.metadataIndex()->isLoaded()) - { - qDebug() << "Index is already loaded"; - return LoadResult::LoadedLocal; - } - ENV.metadataIndex()->load(netmode); - loadTask = ENV.metadataIndex()->getCurrentTask(); - if(loadTask) - { - return LoadResult::RequiresRemote; - } - // FIXME: this is assuming the load succeeded... did it really? - return LoadResult::LoadedLocal; -} -} - -void ComponentUpdateTask::loadComponents() -{ - LoadResult result = LoadResult::LoadedLocal; - size_t taskIndex = 0; - size_t componentIndex = 0; - d->remoteLoadSuccessful = true; - // load the main index (it is needed to determine if components can revert) - { - // FIXME: tear out as a method? or lambda? - shared_qobject_ptr indexLoadTask; - auto singleResult = loadIndex(indexLoadTask, d->netmode); - result = composeLoadResult(result, singleResult); - if(indexLoadTask) - { - qDebug() << "Remote loading is being run for metadata index"; - RemoteLoadStatus status; - status.type = RemoteLoadStatus::Type::Index; - d->remoteLoadStatusList.append(status); - connect(indexLoadTask.get(), &Task::succeeded, [=]() - { - remoteLoadSucceeded(taskIndex); - }); - connect(indexLoadTask.get(), &Task::failed, [=](const QString & error) - { - remoteLoadFailed(taskIndex, error); - }); - taskIndex++; - } - } - // load all the components OR their lists... - for (auto component: d->m_list->d->components) - { - shared_qobject_ptr loadTask; - LoadResult singleResult; - RemoteLoadStatus::Type loadType; - // FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now, ignore all that... -#if 0 - switch(d->mode) - { - case Mode::Launch: - { - singleResult = loadComponent(component, loadTask, d->netmode); - loadType = RemoteLoadStatus::Type::Version; - break; - } - case Mode::Resolution: - { - singleResult = loadPackProfile(component, loadTask, d->netmode); - loadType = RemoteLoadStatus::Type::List; - break; - } - } -#else - singleResult = loadComponent(component, loadTask, d->netmode); - loadType = RemoteLoadStatus::Type::Version; -#endif - if(singleResult == LoadResult::LoadedLocal) - { - component->updateCachedData(); - } - result = composeLoadResult(result, singleResult); - if (loadTask) - { - qDebug() << "Remote loading is being run for" << component->getName(); - connect(loadTask.get(), &Task::succeeded, [=]() - { - remoteLoadSucceeded(taskIndex); - }); - connect(loadTask.get(), &Task::failed, [=](const QString & error) - { - remoteLoadFailed(taskIndex, error); - }); - RemoteLoadStatus status; - status.type = loadType; - status.PackProfileIndex = componentIndex; - d->remoteLoadStatusList.append(status); - taskIndex++; - } - componentIndex++; - } - d->remoteTasksInProgress = taskIndex; - switch(result) - { - case LoadResult::LoadedLocal: - { - // Everything got loaded. Advance to dependency resolution. - resolveDependencies(d->mode == Mode::Launch || d->netmode == Net::Mode::Offline); - break; - } - case LoadResult::RequiresRemote: - { - // we wait for signals. - break; - } - case LoadResult::Failed: - { - emitFailed(tr("Some component metadata load tasks failed.")); - break; - } - } -} - -namespace -{ - struct RequireEx : public Meta::Require - { - size_t indexOfFirstDependee = 0; - }; - struct RequireCompositionResult - { - bool ok; - RequireEx outcome; - }; - using RequireExSet = std::set; -} - -static RequireCompositionResult composeRequirement(const RequireEx & a, const RequireEx & b) -{ - assert(a.uid == b.uid); - RequireEx out; - out.uid = a.uid; - out.indexOfFirstDependee = std::min(a.indexOfFirstDependee, b.indexOfFirstDependee); - if(a.equalsVersion.isEmpty()) - { - out.equalsVersion = b.equalsVersion; - } - else if (b.equalsVersion.isEmpty()) - { - out.equalsVersion = a.equalsVersion; - } - else if (a.equalsVersion == b.equalsVersion) - { - out.equalsVersion = a.equalsVersion; - } - else - { - // FIXME: mark error as explicit version conflict - return {false, out}; - } - - if(a.suggests.isEmpty()) - { - out.suggests = b.suggests; - } - else if (b.suggests.isEmpty()) - { - out.suggests = a.suggests; - } - else - { - Version aVer(a.suggests); - Version bVer(b.suggests); - out.suggests = (aVer < bVer ? b.suggests : a.suggests); - } - return {true, out}; -} - -// gather the requirements from all components, finding any obvious conflicts -static bool gatherRequirementsFromComponents(const ComponentContainer & input, RequireExSet & output) -{ - bool succeeded = true; - size_t componentNum = 0; - for(auto component: input) - { - auto &componentRequires = component->m_cachedRequires; - for(const auto & componentRequire: componentRequires) - { - auto found = std::find_if(output.cbegin(), output.cend(), [componentRequire](const Meta::Require & req){ - return req.uid == componentRequire.uid; - }); - - RequireEx componenRequireEx; - componenRequireEx.uid = componentRequire.uid; - componenRequireEx.suggests = componentRequire.suggests; - componenRequireEx.equalsVersion = componentRequire.equalsVersion; - componenRequireEx.indexOfFirstDependee = componentNum; - - if(found != output.cend()) - { - // found... process it further - auto result = composeRequirement(componenRequireEx, *found); - if(result.ok) - { - output.erase(componenRequireEx); - output.insert(result.outcome); - } - else - { - qCritical() - << "Conflicting requirements:" - << componentRequire.uid - << "versions:" - << componentRequire.equalsVersion - << ";" - << (*found).equalsVersion; - } - succeeded &= result.ok; - } - else - { - // not found, accumulate - output.insert(componenRequireEx); - } - } - componentNum++; - } - return succeeded; -} - -/// Get list of uids that can be trivially removed because nothing is depending on them anymore (and they are installed as deps) -static void getTrivialRemovals(const ComponentContainer & components, const RequireExSet & reqs, QStringList &toRemove) -{ - for(const auto & component: components) - { - if(!component->m_dependencyOnly) - continue; - if(!component->m_cachedVolatile) - continue; - RequireEx reqNeedle; - reqNeedle.uid = component->m_uid; - const auto iter = reqs.find(reqNeedle); - if(iter == reqs.cend()) - { - toRemove.append(component->m_uid); - } - } -} - -/** - * handles: - * - trivial addition (there is an unmet requirement and it can be trivially met by adding something) - * - trivial version conflict of dependencies == explicit version required and installed is different - * - * toAdd - set of requirements than mean adding a new component - * toChange - set of requirements that mean changing version of an existing component - */ -static bool getTrivialComponentChanges(const ComponentIndex & index, const RequireExSet & input, RequireExSet & toAdd, RequireExSet & toChange) -{ - enum class Decision - { - Undetermined, - Met, - Missing, - VersionNotSame, - LockedVersionNotSame - } decision = Decision::Undetermined; - - QString reqStr; - bool succeeded = true; - // list the composed requirements and say if they are met or unmet - for(auto & req: input) - { - do - { - if(req.equalsVersion.isEmpty()) - { - reqStr = QString("Req: %1").arg(req.uid); - if(index.contains(req.uid)) - { - decision = Decision::Met; - } - else - { - toAdd.insert(req); - decision = Decision::Missing; - } - break; - } - else - { - reqStr = QString("Req: %1 == %2").arg(req.uid, req.equalsVersion); - const auto & compIter = index.find(req.uid); - if(compIter == index.cend()) - { - toAdd.insert(req); - decision = Decision::Missing; - break; - } - auto & comp = (*compIter); - if(comp->getVersion() != req.equalsVersion) - { - if(comp->isCustom()) { - decision = Decision::LockedVersionNotSame; - } else { - if(comp->m_dependencyOnly) - { - decision = Decision::VersionNotSame; - } - else - { - decision = Decision::LockedVersionNotSame; - } - } - break; - } - decision = Decision::Met; - } - } while(false); - switch(decision) - { - case Decision::Undetermined: - qCritical() << "No decision for" << reqStr; - succeeded = false; - break; - case Decision::Met: - qDebug() << reqStr << "Is met."; - break; - case Decision::Missing: - qDebug() << reqStr << "Is missing and should be added at" << req.indexOfFirstDependee; - toAdd.insert(req); - break; - case Decision::VersionNotSame: - qDebug() << reqStr << "already has different version that can be changed."; - toChange.insert(req); - break; - case Decision::LockedVersionNotSame: - qDebug() << reqStr << "already has different version that cannot be changed."; - succeeded = false; - break; - } - } - return succeeded; -} - -// FIXME, TODO: decouple dependency resolution from loading -// FIXME: This works directly with the PackProfile internals. It shouldn't! It needs richer data types than PackProfile uses. -// FIXME: throw all this away and use a graph -void ComponentUpdateTask::resolveDependencies(bool checkOnly) -{ - qDebug() << "Resolving dependencies"; - /* - * this is a naive dependency resolving algorithm. all it does is check for following conditions and react in simple ways: - * 1. There are conflicting dependencies on the same uid with different exact version numbers - * -> hard error - * 2. A dependency has non-matching exact version number - * -> hard error - * 3. A dependency is entirely missing and needs to be injected before the dependee(s) - * -> requirements are injected - * - * NOTE: this is a placeholder and should eventually be replaced with something 'serious' - */ - auto & components = d->m_list->d->components; - auto & componentIndex = d->m_list->d->componentIndex; - - RequireExSet allRequires; - QStringList toRemove; - do - { - allRequires.clear(); - toRemove.clear(); - if(!gatherRequirementsFromComponents(components, allRequires)) - { - emitFailed(tr("Conflicting requirements detected during dependency checking!")); - return; - } - getTrivialRemovals(components, allRequires, toRemove); - if(!toRemove.isEmpty()) - { - qDebug() << "Removing obsolete components..."; - for(auto & remove : toRemove) - { - qDebug() << "Removing" << remove; - d->m_list->remove(remove); - } - } - } while (!toRemove.isEmpty()); - RequireExSet toAdd; - RequireExSet toChange; - bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange); - if(!succeeded) - { - emitFailed(tr("Instance has conflicting dependencies.")); - return; - } - if(checkOnly) - { - if(toAdd.size() || toChange.size()) - { - emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch.")); - } - else - { - emitSucceeded(); - } - return; - } - - bool recursionNeeded = false; - if(toAdd.size()) - { - // add stuff... - for(auto &add: toAdd) - { - ComponentPtr component = new Component(d->m_list, add.uid); - if(!add.equalsVersion.isEmpty()) - { - // exact version - qDebug() << "Adding" << add.uid << "version" << add.equalsVersion << "at position" << add.indexOfFirstDependee; - component->m_version = add.equalsVersion; - } - else - { - // version needs to be decided - qDebug() << "Adding" << add.uid << "at position" << add.indexOfFirstDependee; -// ############################################################################################################ -// HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. - if(!add.suggests.isEmpty()) - { - component->m_version = add.suggests; - } - else - { - if(add.uid == "org.lwjgl") - { - component->m_version = "2.9.1"; - } - else if (add.uid == "org.lwjgl3") - { - component->m_version = "3.1.2"; - } - else if (add.uid == "net.fabricmc.intermediary") - { - auto minecraft = std::find_if(components.begin(), components.end(), [](ComponentPtr & cmp){ - return cmp->getID() == "net.minecraft"; - }); - if(minecraft != components.end()) { - component->m_version = (*minecraft)->getVersion(); - } - } - } -// HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. -// ############################################################################################################ - } - component->m_dependencyOnly = true; - // FIXME: this should not work directly with the component list - d->m_list->insertComponent(add.indexOfFirstDependee, component); - componentIndex[add.uid] = component; - } - recursionNeeded = true; - } - if(toChange.size()) - { - // change a version of something that exists - for(auto &change: toChange) - { - // FIXME: this should not work directly with the component list - qDebug() << "Setting version of " << change.uid << "to" << change.equalsVersion; - auto component = componentIndex[change.uid]; - component->setVersion(change.equalsVersion); - } - recursionNeeded = true; - } - - if(recursionNeeded) - { - loadComponents(); - } - else - { - emitSucceeded(); - } -} - -void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) -{ - auto &taskSlot = d->remoteLoadStatusList[taskIndex]; - if(taskSlot.finished) - { - qWarning() << "Got multiple results from remote load task" << taskIndex; - return; - } - qDebug() << "Remote task" << taskIndex << "succeeded"; - taskSlot.succeeded = false; - taskSlot.finished = true; - d->remoteTasksInProgress --; - // update the cached data of the component from the downloaded version file. - if (taskSlot.type == RemoteLoadStatus::Type::Version) - { - auto component = d->m_list->getComponent(taskSlot.PackProfileIndex); - component->m_loaded = true; - component->updateCachedData(); - } - checkIfAllFinished(); -} - - -void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg) -{ - auto &taskSlot = d->remoteLoadStatusList[taskIndex]; - if(taskSlot.finished) - { - qWarning() << "Got multiple results from remote load task" << taskIndex; - return; - } - qDebug() << "Remote task" << taskIndex << "failed: " << msg; - d->remoteLoadSuccessful = false; - taskSlot.succeeded = false; - taskSlot.finished = true; - taskSlot.error = msg; - d->remoteTasksInProgress --; - checkIfAllFinished(); -} - -void ComponentUpdateTask::checkIfAllFinished() -{ - if(d->remoteTasksInProgress) - { - // not yet... - return; - } - if(d->remoteLoadSuccessful) - { - // nothing bad happened... clear the temp load status and proceed with looking at dependencies - d->remoteLoadStatusList.clear(); - resolveDependencies(d->mode == Mode::Launch); - } - else - { -