diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index 09c83e0b1..0cd33a2b3 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -16,6 +16,7 @@ #include "VersionList.h" #include +#include #include "Application.h" #include "Index.h" @@ -273,4 +274,31 @@ void VersionList::waitToLoad() task->start(); ev.exec(); } + +Version::Ptr VersionList::getRecommendedForParent(const QString& uid, const QString& version) +{ + auto foundExplicit = std::find_if(m_versions.begin(), m_versions.end(), [uid, version](Version::Ptr ver) -> bool { + auto& reqs = ver->requiredSet(); + auto parentReq = std::find_if(reqs.begin(), reqs.end(), [uid, version](const Require& req) -> bool { + return req.uid == uid && req.equalsVersion == version; + }); + return parentReq != reqs.end() && ver->isRecommended(); + }); + if (foundExplicit != m_versions.end()) { + return *foundExplicit; + } + + Version::Ptr latestCompat = nullptr; + for (auto ver : m_versions) { + auto& reqs = ver->requiredSet(); + auto parentReq = std::find_if(reqs.begin(), reqs.end(), [uid, version](const Require& req) -> bool { + return req.uid == uid && req.equalsVersion == version; + }); + if (parentReq != reqs.end()) { + latestCompat = getBetterVersion(latestCompat, ver); + } + } + return latestCompat; +} + } // namespace Meta diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h index 24ff6a1ce..b746d3232 100644 --- a/launcher/meta/VersionList.h +++ b/launcher/meta/VersionList.h @@ -43,6 +43,8 @@ class VersionList : public BaseVersionList, public BaseEntity { void sortVersions() override; BaseVersion::Ptr getRecommended() const override; + Version::Ptr getRecommendedForParent(const QString& uid, const QString& version); + QVariant data(const QModelIndex& index, int role) const override; RoleList providesRoles() const override; diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 32a1deb68..f03ffacc0 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -402,3 +402,8 @@ void Component::updateCachedData() emit dataChanged(); } } + +QDebug operator<<(QDebug d, const Component& comp) { + d << "Component(" << comp.m_uid << " : " << comp.m_cachedVersion << ")"; + return d; +} diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 4b17cdf07..b258d8241 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -38,6 +38,8 @@ */ #include +#include +#include #include #include #include @@ -47,10 +49,14 @@ #include #include #include +#include +#include "Application.h" #include "Exception.h" #include "FileSystem.h" #include "Json.h" +#include "meta/Index.h" +#include "meta/JsonFormat.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/OneSixVersionFormat.h" #include "minecraft/ProfileUtils.h" @@ -58,7 +64,6 @@ #include "ComponentUpdateTask.h" #include "PackProfile.h" #include "PackProfile_p.h" -#include "minecraft/mod/Mod.h" #include "modplatform/ModIndex.h" static const QMap modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge }, @@ -956,6 +961,35 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version if (component->revert()) { component->setVersion(version); component->setImportant(important); + component->updateCachedData(); + // remove linked componants to let them reresolve their versions + if (important) { + auto linked = collectTreeLinked(uid); + for (auto comp : linked) { + if (comp->isCustom()) { + continue; + } + if (modloaderMapping.contains(comp->getID())) { + qDebug() << comp->getID() << "is a mod loader, setting new recomended version..."; + auto versionList = APPLICATION->metadataIndex()->get(comp->getID()); + if (versionList) { + auto recomended = versionList->getRecommendedForParent(comp->getID(), version); + if (recomended) { + qDebug() << "Setting updated loader version: " << comp->getID() << " = " << recomended->version(); + setComponentVersion(comp->getID(), recomended->version()); + } else { + qDebug() << "no recomended verison for" << comp->getID(); + } + } else { + qDebug() << "no version list in metadata index for" << comp->getID(); + } + } else { + qDebug() << comp->getID() << ":" << comp->getVersion() << "linked to important component: " << uid + << " | Removing so it re-resolves"; + remove(comp->getID()); + } + } + } return true; } return false; @@ -969,6 +1003,35 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version } } +ComponentContainer PackProfile::collectTreeLinked(const QString& uid) +{ + ComponentContainer linked; + for (auto comp : d->components) { + qDebug() << "scanning" << comp->getID() << "for tree link"; + auto dep = std::find_if(comp->m_cachedRequires.cbegin(), comp->m_cachedRequires.cend(), + [uid](const Meta::Require& req) -> bool { return req.uid == uid; }); + if (dep != comp->m_cachedRequires.cend()) { + qDebug() << comp->getID() << "depends on" << uid; + linked.append(comp); + } + } + auto iter = d->componentIndex.find(uid); + if (iter != d->componentIndex.end()) { + ComponentPtr comp = *iter; + comp->updateCachedData(); + qDebug() << comp->getID() << "has" << comp->m_cachedRequires.size() << "dependencies"; + for (auto dep : comp->m_cachedRequires) { + qDebug() << uid << "depends on" << comp->getID(); + auto found = d->componentIndex.find(dep.uid); + if (found != d->componentIndex.end()) { + qDebug() << comp->getID() << "is present"; + linked.append(*found); + } + } + } + return linked; +} + QString PackProfile::getComponentVersion(const QString& uid) const { const auto iter = d->componentIndex.find(uid); diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h index e58e9ae9a..f733b3524 100644 --- a/launcher/minecraft/PackProfile.h +++ b/launcher/minecraft/PackProfile.h @@ -48,6 +48,7 @@ #include "Component.h" #include "LaunchProfile.h" +#include "minecraft/PackProfile_p.h" #include "modplatform/ModIndex.h" #include "net/Mode.h" @@ -119,6 +120,9 @@ class PackProfile : public QAbstractListModel { bool setComponentVersion(const QString& uid, const QString& version, bool important = false); + /// collects components that are dependant on or dependencies of the component + ComponentContainer collectTreeLinked(const QString& uid); + bool installEmpty(const QString& uid, const QString& name); QString patchFilePathForUid(const QString& uid) const;