From 87dbe82474cf12467f3b0557143b4a27714c6ea6 Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Tue, 13 Apr 2021 18:30:37 +0100 Subject: [PATCH] NOISSUE Support custom,latest,recommended loader versions for ATL This provides support for modpacks using the new loader mechanism in ATLauncher and using a non-specific version target. --- .../atlauncher/ATLPackInstallTask.cpp | 47 +++++++++++++++---- .../atlauncher/ATLPackInstallTask.h | 18 +++++-- .../atlauncher/ATLPackManifest.cpp | 26 ++++++---- .../pages/modplatform/atlauncher/AtlPage.cpp | 39 ++++++++++++++- .../pages/modplatform/atlauncher/AtlPage.h | 5 +- 5 files changed, 109 insertions(+), 26 deletions(-) diff --git a/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp b/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp index 12ceaccd..32420415 100644 --- a/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/api/logic/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -18,8 +18,9 @@ namespace ATLauncher { -PackInstallTask::PackInstallTask(QString pack, QString version) +PackInstallTask::PackInstallTask(UserInteractionSupport *support, QString pack, QString version) { + m_support = support; m_pack = pack; m_version_name = version; } @@ -154,20 +155,47 @@ QString PackInstallTask::getVersionForLoader(QString uid) auto vlist = ENV.metadataIndex()->get(uid); if(!vlist) { - emitFailed(tr("Failed to get local metadata index for ") + uid); + emitFailed(tr("Failed to get local metadata index for %1").arg(uid)); return Q_NULLPTR; } - // todo: filter by Minecraft version - - if(m_version.loader.recommended) { - return vlist.get()->getRecommended().get()->descriptor(); + if(!vlist->isLoaded()) { + vlist->load(Net::Mode::Online); } - else if(m_version.loader.latest) { - return vlist.get()->at(0)->descriptor(); + + if(m_version.loader.recommended || m_version.loader.latest) { + for (int i = 0; i < vlist->versions().size(); i++) { + auto version = vlist->versions().at(i); + auto reqs = version->requires(); + + // filter by minecraft version, if the loader depends on a certain version. + // not all mod loaders depend on a given Minecraft version, so we won't do this + // filtering for those loaders. + if (m_version.loader.type != "fabric") { + auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) { + return req.uid == "net.minecraft"; + }); + if (iter == reqs.end()) continue; + if (iter->equalsVersion != m_version.minecraft) continue; + } + + if (m_version.loader.recommended) { + // first recommended build we find, we use. + if (!version->isRecommended()) continue; + } + + return version->descriptor(); + } + + emitFailed(tr("Failed to find version for %1 loader").arg(m_version.loader.type)); } else if(m_version.loader.choose) { - // todo: implement + // Fabric Loader doesn't depend on a given Minecraft version. + if (m_version.loader.type == "fabric") { + return m_support->chooseVersion(vlist, Q_NULLPTR); + } + + return m_support->chooseVersion(vlist, m_version.minecraft); } } @@ -451,7 +479,6 @@ void PackInstallTask::downloadMods() auto cacheName = fileName.completeBaseName() + "-" + mod.md5 + "." + fileName.suffix(); if (mod.type == ModType::Extract || mod.type == ModType::TexturePackExtract || mod.type == ModType::ResourcePackExtract) { - auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName); entry->setStale(true); modsToExtract.insert(entry->getFullPath(), mod); diff --git a/api/logic/modplatform/atlauncher/ATLPackInstallTask.h b/api/logic/modplatform/atlauncher/ATLPackInstallTask.h index 78544bab..3647e471 100644 --- a/api/logic/modplatform/atlauncher/ATLPackInstallTask.h +++ b/api/logic/modplatform/atlauncher/ATLPackInstallTask.h @@ -15,12 +15,23 @@ namespace ATLauncher { +class MULTIMC_LOGIC_EXPORT UserInteractionSupport { + +public: + /** + * Requests a user interaction to select a component version from a given version list + * and constrained to a given Minecraft version. + */ + virtual QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) = 0; + +}; + class MULTIMC_LOGIC_EXPORT PackInstallTask : public InstanceTask { Q_OBJECT public: - explicit PackInstallTask(QString pack, QString version); + explicit PackInstallTask(UserInteractionSupport *support, QString pack, QString version); virtual ~PackInstallTask(){} bool abort() override; @@ -54,6 +65,8 @@ private: void install(); private: + UserInteractionSupport *m_support; + NetJobPtr jobPtr; QByteArray response; @@ -76,9 +89,6 @@ private: QFuture m_modExtractFuture; QFutureWatcher m_modExtractFutureWatcher; - QFuture m_decompFuture; - QFutureWatcher m_decompFutureWatcher; - }; } diff --git a/api/logic/modplatform/atlauncher/ATLPackManifest.cpp b/api/logic/modplatform/atlauncher/ATLPackManifest.cpp index 84389330..50682391 100644 --- a/api/logic/modplatform/atlauncher/ATLPackManifest.cpp +++ b/api/logic/modplatform/atlauncher/ATLPackManifest.cpp @@ -81,12 +81,15 @@ static ATLauncher::ModType parseModType(QString rawType) { static void loadVersionLoader(ATLauncher::VersionLoader & p, QJsonObject & obj) { p.type = Json::requireString(obj, "type"); - p.latest = Json::ensureBoolean(obj, QString("latest"), false); p.choose = Json::ensureBoolean(obj, QString("choose"), false); - p.recommended = Json::ensureBoolean(obj, QString("recommended"), false); auto metadata = Json::requireObject(obj, "metadata"); - p.version = Json::requireString(metadata, "version"); + + if (metadata.contains("version")) { + p.version = Json::requireString(metadata, "version"); + } + p.latest = Json::ensureBoolean(metadata, QString("latest"), false); + p.recommended = Json::ensureBoolean(metadata, QString("recommended"), false); } static void loadVersionLibrary(ATLauncher::VersionLibrary & p, QJsonObject & obj) { @@ -169,12 +172,15 @@ void ATLauncher::loadVersion(PackVersion & v, QJsonObject & obj) } } - auto mods = Json::requireArray(obj, "mods"); - for (const auto modRaw : mods) - { - auto modObj = Json::requireObject(modRaw); - ATLauncher::VersionMod mod; - loadVersionMod(mod, modObj); - v.mods.append(mod); + + if(obj.contains("mods")) { + auto mods = Json::requireArray(obj, "mods"); + for (const auto modRaw : mods) + { + auto modObj = Json::requireObject(modRaw); + ATLauncher::VersionMod mod; + loadVersionMod(mod, modObj); + v.mods.append(mod); + } } } diff --git a/application/pages/modplatform/atlauncher/AtlPage.cpp b/application/pages/modplatform/atlauncher/AtlPage.cpp index f90d734c..748f467c 100644 --- a/application/pages/modplatform/atlauncher/AtlPage.cpp +++ b/application/pages/modplatform/atlauncher/AtlPage.cpp @@ -4,6 +4,7 @@ #include "dialogs/NewInstanceDialog.h" #include #include +#include AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent) : QWidget(parent), ui(new Ui::AtlPage), dialog(dialog) @@ -50,7 +51,7 @@ void AtlPage::openedImpl() void AtlPage::suggestCurrent() { if(isOpened) { - dialog->setSuggestedPack(selected.name, new ATLauncher::PackInstallTask(selected.safeName, selectedVersion)); + dialog->setSuggestedPack(selected.name, new ATLauncher::PackInstallTask(this, selected.safeName, selectedVersion)); } auto editedLogoName = selected.safeName; @@ -112,3 +113,39 @@ void AtlPage::onVersionSelectionChanged(QString data) selectedVersion = data; suggestCurrent(); } + +QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) { + VersionSelectDialog vselect(vlist.get(), "Choose Version", MMC->activeWindow(), false); + if (minecraftVersion != Q_NULLPTR) { + vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion); + vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion)); + } + else { + vselect.setEmptyString(tr("No versions are currently available")); + } + vselect.setEmptyErrorString(tr("Couldn't load or download the version lists!")); + + // select recommended build + for (int i = 0; i < vlist->versions().size(); i++) { + auto version = vlist->versions().at(i); + auto reqs = version->requires(); + + // filter by minecraft version, if the loader depends on a certain version. + if (minecraftVersion != Q_NULLPTR) { + auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) { + return req.uid == "net.minecraft"; + }); + if (iter == reqs.end()) continue; + if (iter->equalsVersion != minecraftVersion) continue; + } + + // first recommended build we find, we use. + if (version->isRecommended()) { + vselect.setCurrentVersion(version->descriptor()); + break; + } + } + + vselect.exec(); + return vselect.selectedVersion()->descriptor(); +} diff --git a/application/pages/modplatform/atlauncher/AtlPage.h b/application/pages/modplatform/atlauncher/AtlPage.h index 715cf5f4..6a89b609 100644 --- a/application/pages/modplatform/atlauncher/AtlPage.h +++ b/application/pages/modplatform/atlauncher/AtlPage.h @@ -19,6 +19,7 @@ #include "AtlListModel.h" #include +#include #include "MultiMC.h" #include "pages/BasePage.h" @@ -31,7 +32,7 @@ namespace Ui class NewInstanceDialog; -class AtlPage : public QWidget, public BasePage +class AtlPage : public QWidget, public BasePage, public ATLauncher::UserInteractionSupport { Q_OBJECT @@ -61,6 +62,8 @@ public: private: void suggestCurrent(); + QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override; + private slots: void triggerSearch(); void resetSearch();