fix conflicts with develop
This commit is contained in:
		| @@ -1,6 +1,7 @@ | ||||
| // SPDX-License-Identifier: GPL-3.0-only | ||||
| /* | ||||
|  *  PolyMC - Minecraft Launcher | ||||
|  *  Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> | ||||
|  *  Copyright (c) 2022 flowln <flowlnlnln@gmail.com> | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
| @@ -51,11 +52,22 @@ | ||||
| #include "minecraft/PackProfile.h" | ||||
| #include "modplatform/flame/FileResolvingTask.h" | ||||
| #include "modplatform/flame/PackManifest.h" | ||||
| #include "modplatform/modrinth/ModrinthPackManifest.h" | ||||
| #include "modplatform/technic/TechnicPackProcessor.h" | ||||
|  | ||||
| InstanceImportTask::InstanceImportTask(const QUrl sourceUrl) | ||||
| #include "Application.h" | ||||
| #include "icons/IconList.h" | ||||
| #include "net/ChecksumValidator.h" | ||||
|  | ||||
| #include "ui/dialogs/CustomMessageBox.h" | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <iterator> | ||||
|  | ||||
| InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent) | ||||
| { | ||||
|     m_sourceUrl = sourceUrl; | ||||
|     m_parent = parent; | ||||
| } | ||||
|  | ||||
| bool InstanceImportTask::abort() | ||||
| @@ -127,6 +139,7 @@ void InstanceImportTask::processZipPack() | ||||
|     QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg"); | ||||
|     bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json"); | ||||
|     QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json"); | ||||
|     QString modrinthFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "modrinth.index.json"); | ||||
|     QString root; | ||||
|     if(!mmcFound.isNull()) | ||||
|     { | ||||
| @@ -150,6 +163,13 @@ void InstanceImportTask::processZipPack() | ||||
|         root = flameFound; | ||||
|         m_modpackType = ModpackType::Flame; | ||||
|     } | ||||
|     else if(!modrinthFound.isNull()) | ||||
|     { | ||||
|         // process as Modrinth pack | ||||
|         qDebug() << "Modrinth:" << modrinthFound; | ||||
|         root = modrinthFound; | ||||
|         m_modpackType = ModpackType::Modrinth; | ||||
|     } | ||||
|     if(m_modpackType == ModpackType::Unknown) | ||||
|     { | ||||
|         emitFailed(tr("Archive does not contain a recognized modpack type.")); | ||||
| @@ -206,15 +226,18 @@ void InstanceImportTask::extractFinished() | ||||
|  | ||||
|     switch(m_modpackType) | ||||
|     { | ||||
|         case ModpackType::Flame: | ||||
|             processFlame(); | ||||
|             return; | ||||
|         case ModpackType::MultiMC: | ||||
|             processMultiMC(); | ||||
|             return; | ||||
|         case ModpackType::Technic: | ||||
|             processTechnic(); | ||||
|             return; | ||||
|         case ModpackType::Flame: | ||||
|             processFlame(); | ||||
|             return; | ||||
|         case ModpackType::Modrinth: | ||||
|             processModrinth(); | ||||
|             return; | ||||
|         case ModpackType::Unknown: | ||||
|             emitFailed(tr("Archive does not contain a recognized modpack type.")); | ||||
|             return; | ||||
| @@ -457,25 +480,174 @@ void InstanceImportTask::processMultiMC() | ||||
|     instance.setName(m_instName); | ||||
|  | ||||
|     // if the icon was specified by user, use that. otherwise pull icon from the pack | ||||
|     if (m_instIcon != "default") { | ||||
|         instance.setIconKey(m_instIcon); | ||||
|     } else { | ||||
|         m_instIcon = instance.iconKey(); | ||||
|  | ||||
|         auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon); | ||||
|         if (!importIconPath.isNull() && QFile::exists(importIconPath)) { | ||||
|             // import icon | ||||
|             auto iconList = APPLICATION->icons(); | ||||
|             if (iconList->iconFileExists(m_instIcon)) { | ||||
|                 iconList->deleteIcon(m_instIcon); | ||||
|             } | ||||
|             iconList->installIcons({ importIconPath }); | ||||
|         } | ||||
|     } | ||||
|     emitSucceeded(); | ||||
| } | ||||
|  | ||||
| void InstanceImportTask::processModrinth() | ||||
| { | ||||
|     std::vector<Modrinth::File> files; | ||||
|     QString minecraftVersion, fabricVersion, quiltVersion, forgeVersion; | ||||
|     try { | ||||
|         QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json"); | ||||
|         auto doc = Json::requireDocument(indexPath); | ||||
|         auto obj = Json::requireObject(doc, "modrinth.index.json"); | ||||
|         int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json"); | ||||
|         if (formatVersion == 1) { | ||||
|             auto game = Json::requireString(obj, "game", "modrinth.index.json"); | ||||
|             if (game != "minecraft") { | ||||
|                 throw JSONValidationError("Unknown game: " + game); | ||||
|             } | ||||
|  | ||||
|             auto jsonFiles = Json::requireIsArrayOf<QJsonObject>(obj, "files", "modrinth.index.json"); | ||||
|             bool had_optional = false; | ||||
|             for (auto& obj : jsonFiles) { | ||||
|                 Modrinth::File file; | ||||
|                 file.path = Json::requireString(obj, "path"); | ||||
|  | ||||
|                 auto env = Json::ensureObject(obj, "env"); | ||||
|                 QString support = Json::ensureString(env, "client", "unsupported"); | ||||
|                 if (support == "unsupported") { | ||||
|                     continue; | ||||
|                 } else if (support == "optional") { | ||||
|                     // TODO: Make a review dialog for choosing which ones the user wants! | ||||
|                     if (!had_optional) { | ||||
|                         had_optional = true; | ||||
|                         auto info = CustomMessageBox::selectable( | ||||
|                             m_parent, tr("Optional mod detected!"), | ||||
|                             tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"), QMessageBox::Information); | ||||
|                         info->exec(); | ||||
|                     } | ||||
|  | ||||
|                     if (file.path.endsWith(".jar")) | ||||
|                         file.path += ".disabled"; | ||||
|                 } | ||||
|  | ||||
|                 QJsonObject hashes = Json::requireObject(obj, "hashes"); | ||||
|                 QString hash; | ||||
|                 QCryptographicHash::Algorithm hashAlgorithm; | ||||
|                 hash = Json::ensureString(hashes, "sha1"); | ||||
|                 hashAlgorithm = QCryptographicHash::Sha1; | ||||
|                 if (hash.isEmpty()) { | ||||
|                     hash = Json::ensureString(hashes, "sha512"); | ||||
|                     hashAlgorithm = QCryptographicHash::Sha512; | ||||
|                     if (hash.isEmpty()) { | ||||
|                         hash = Json::ensureString(hashes, "sha256"); | ||||
|                         hashAlgorithm = QCryptographicHash::Sha256; | ||||
|                         if (hash.isEmpty()) { | ||||
|                             throw JSONValidationError("No hash found for: " + file.path); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 file.hash = QByteArray::fromHex(hash.toLatin1()); | ||||
|                 file.hashAlgorithm = hashAlgorithm; | ||||
|                 // Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode | ||||
|                 // (as Modrinth seems to incorrectly handle spaces) | ||||
|                 file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path); | ||||
|                 if (!file.download.isValid() || !Modrinth::validateDownloadUrl(file.download)) { | ||||
|                     throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL"); | ||||
|                 } | ||||
|                 files.push_back(file); | ||||
|             } | ||||
|  | ||||
|             auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json"); | ||||
|             for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) { | ||||
|                 QString name = it.key(); | ||||
|                 if (name == "minecraft") { | ||||
|                     minecraftVersion = Json::requireString(*it, "Minecraft version"); | ||||
|                 } | ||||
|                 else if (name == "fabric-loader") { | ||||
|                     fabricVersion = Json::requireString(*it, "Fabric Loader version"); | ||||
|                 } | ||||
|                 else if (name == "quilt-loader") { | ||||
|                     quiltVersion = Json::requireString(*it, "Quilt Loader version"); | ||||
|                 } | ||||
|                 else if (name == "forge") { | ||||
|                     forgeVersion = Json::requireString(*it, "Forge version"); | ||||
|                 } | ||||
|                 else { | ||||
|                     throw JSONValidationError("Unknown dependency type: " + name); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             throw JSONValidationError(QStringLiteral("Unknown format version: %s").arg(formatVersion)); | ||||
|         } | ||||
|         QFile::remove(indexPath); | ||||
|     } catch (const JSONValidationError& e) { | ||||
|         emitFailed(tr("Could not understand pack index:\n") + e.cause()); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QString overridePath = FS::PathCombine(m_stagingPath, "overrides"); | ||||
|     if (QFile::exists(overridePath)) { | ||||
|         QString mcPath = FS::PathCombine(m_stagingPath, ".minecraft"); | ||||
|         if (!QFile::rename(overridePath, mcPath)) { | ||||
|             emitFailed(tr("Could not rename the overrides folder:\n") + "overrides"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); | ||||
|     auto instanceSettings = std::make_shared<INISettingsObject>(configPath); | ||||
|     MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); | ||||
|     auto components = instance.getPackProfile(); | ||||
|     components->buildingFromScratch(); | ||||
|     components->setComponentVersion("net.minecraft", minecraftVersion, true); | ||||
|     if (!fabricVersion.isEmpty()) | ||||
|         components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true); | ||||
|     if (!quiltVersion.isEmpty()) | ||||
|         components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true); | ||||
|     if (!forgeVersion.isEmpty()) | ||||
|         components->setComponentVersion("net.minecraftforge", forgeVersion, true); | ||||
|     if (m_instIcon != "default") | ||||
|     { | ||||
|         instance.setIconKey(m_instIcon); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         m_instIcon = instance.iconKey(); | ||||
|  | ||||
|         auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon); | ||||
|         if (!importIconPath.isNull() && QFile::exists(importIconPath)) | ||||
|         { | ||||
|             // import icon | ||||
|             auto iconList = APPLICATION->icons(); | ||||
|             if (iconList->iconFileExists(m_instIcon)) | ||||
|             { | ||||
|                 iconList->deleteIcon(m_instIcon); | ||||
|             } | ||||
|             iconList->installIcons({importIconPath}); | ||||
|         } | ||||
|         instance.setIconKey("modrinth"); | ||||
|     } | ||||
|     emitSucceeded(); | ||||
|     instance.setName(m_instName); | ||||
|     instance.saveNow(); | ||||
|  | ||||
|     m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network()); | ||||
|     for (auto &file : files) | ||||
|     { | ||||
|         auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path); | ||||
|         qDebug() << "Will download" << file.download << "to" << path; | ||||
|         auto dl = Net::Download::makeFile(file.download, path); | ||||
|         dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); | ||||
|         m_filesNetJob->addNetAction(dl); | ||||
|     } | ||||
|     connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() | ||||
|             { | ||||
|                 m_filesNetJob.reset(); | ||||
|                 emitSucceeded(); | ||||
|             } | ||||
|     ); | ||||
|     connect(m_filesNetJob.get(), &NetJob::failed, [&](const QString &reason) | ||||
|     { | ||||
|         m_filesNetJob.reset(); | ||||
|         emitFailed(reason); | ||||
|     }); | ||||
|     connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) | ||||
|     { | ||||
|         setProgress(current, total); | ||||
|     }); | ||||
|     setStatus(tr("Downloading mods...")); | ||||
|     m_filesNetJob->start(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 flow
					flow