From 44bf0315ada1715145a8ed91b4f573ec7fcc4092 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:55:58 -0700 Subject: [PATCH 01/21] feat(components) recomend the correct lwjgl version for the minecraft version Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/meta/VersionList.cpp | 12 +++++++++++- launcher/meta/VersionList.h | 3 +++ launcher/ui/pages/instance/VersionPage.cpp | 18 ++++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index f21e4594a..09c83e0b1 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -99,7 +99,7 @@ QVariant VersionList::data(const QModelIndex& index, int role) const case VersionPtrRole: return QVariant::fromValue(version); case RecommendedRole: - return version->isRecommended(); + return version->isRecommended() || m_externalRecommendsVersions.contains(version->version()); // FIXME: this should be determined in whatever view/proxy is used... // case LatestRole: return version == getLatestStable(); default: @@ -179,6 +179,16 @@ void VersionList::parse(const QJsonObject& obj) parseVersionList(obj, this); } +void VersionList::addExternalRecomends(const QVector& recomends) +{ + m_externalRecommendsVersions.append(recomends); +} + +void VersionList::clearExternalRecomends() +{ + m_externalRecommendsVersions.clear(); +} + // FIXME: this is dumb, we have 'recommended' as part of the metadata already... static const Meta::Version::Ptr& getBetterVersion(const Meta::Version::Ptr& a, const Meta::Version::Ptr& b) { diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h index 90e0c8e5e..24ff6a1ce 100644 --- a/launcher/meta/VersionList.h +++ b/launcher/meta/VersionList.h @@ -68,6 +68,8 @@ class VersionList : public BaseVersionList, public BaseEntity { void merge(const VersionList::Ptr& other); void mergeFromIndex(const VersionList::Ptr& other); void parse(const QJsonObject& obj) override; + void addExternalRecomends(const QVector& recomends); + void clearExternalRecomends(); signals: void nameChanged(const QString& name); @@ -77,6 +79,7 @@ class VersionList : public BaseVersionList, public BaseEntity { private: QVector m_versions; + QStringList m_externalRecommendsVersions; QHash m_lookup; QString m_uid; QString m_name; diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index 807bc5d58..545798499 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -49,8 +49,10 @@ #include #include #include +#include #include "VersionPage.h" +#include "meta/JsonFormat.h" #include "ui/dialogs/InstallLoaderDialog.h" #include "ui_VersionPage.h" @@ -63,11 +65,9 @@ #include "DesktopServices.h" #include "Exception.h" -#include "Version.h" #include "icons/IconList.h" #include "minecraft/PackProfile.h" #include "minecraft/auth/AccountList.h" -#include "minecraft/mod/Mod.h" #include "meta/Index.h" #include "meta/VersionList.h" @@ -370,11 +370,25 @@ void VersionPage::on_actionChange_version_triggered() auto patch = m_profile->getComponent(versionRow); auto name = patch->getName(); auto list = patch->getVersionList(); + list->clearExternalRecomends(); if (!list) { return; } auto uid = list->uid(); + // recommend the correct lwjgl version for the current minecraft version + if (uid == "org.lwjgl" || uid == "org.lwjgl3") { + auto minecraft = m_profile->getComponent("net.minecraft"); + auto lwjglReq = std::find_if(minecraft->m_cachedRequires.cbegin(), minecraft->m_cachedRequires.cend(), + [uid](const Meta::Require& req) -> bool { return req.uid == uid; }); + if (lwjglReq != minecraft->m_cachedRequires.cend()) { + auto lwjglVersion = !lwjglReq->equalsVersion.isEmpty() ? lwjglReq->equalsVersion : lwjglReq->suggests; + if (!lwjglVersion.isEmpty()) { + list->addExternalRecomends({ lwjglVersion }); + } + } + } + VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this); if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") { vselect.setEmptyString(tr("No intermediary mappings versions are currently available.")); From a791e22853da4c93f006883f78f22a4664f06972 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:46:14 -0700 Subject: [PATCH 02/21] fix(instance components): resolve instance componants when changing minecraft version Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/meta/VersionList.cpp | 28 +++++++++++++ launcher/meta/VersionList.h | 2 + launcher/minecraft/Component.cpp | 5 +++ launcher/minecraft/PackProfile.cpp | 65 +++++++++++++++++++++++++++++- launcher/minecraft/PackProfile.h | 4 ++ 5 files changed, 103 insertions(+), 1 deletion(-) 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; From ce280c2d04c8536cc06c012208899430fb6037de Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 24 Jun 2024 12:55:33 -0700 Subject: [PATCH 03/21] fix misepellings Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/PackProfile.cpp | 15 +++++++-------- launcher/minecraft/PackProfile_p.h | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index b258d8241..bdc80b923 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -961,8 +961,7 @@ 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 + // remove linked components to let them re-resolve their versions if (important) { auto linked = collectTreeLinked(uid); for (auto comp : linked) { @@ -970,15 +969,15 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version continue; } if (modloaderMapping.contains(comp->getID())) { - qDebug() << comp->getID() << "is a mod loader, setting new recomended version..."; + qDebug() << comp->getID() << "is a mod loader, setting new recommended 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()); + auto recommended = versionList->getRecommendedForParent(comp->getID(), version); + if (recommended) { + qDebug() << "Setting updated loader version: " << comp->getID() << " = " << recommended->version(); + setComponentVersion(comp->getID(), recommended->version()); } else { - qDebug() << "no recomended verison for" << comp->getID(); + qDebug() << "no recommended version for" << comp->getID(); } } else { qDebug() << "no version list in metadata index for" << comp->getID(); diff --git a/launcher/minecraft/PackProfile_p.h b/launcher/minecraft/PackProfile_p.h index 0cd4fb839..4fb3621f0 100644 --- a/launcher/minecraft/PackProfile_p.h +++ b/launcher/minecraft/PackProfile_p.h @@ -3,8 +3,8 @@ #include #include #include -#include #include "Component.h" +#include "tasks/Task.h" class MinecraftInstance; using ComponentContainer = QList; From a94a081b9c1347d65157ae3162d9adb8fee93c6a Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:08:23 -0700 Subject: [PATCH 04/21] add better profile logging properly resolve important dependencies Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/CMakeLists.txt | 27 +++- launcher/meta/VersionList.cpp | 4 + launcher/meta/VersionList.h | 1 + launcher/minecraft/Component.cpp | 12 ++ launcher/minecraft/Component.h | 2 + launcher/minecraft/ComponentUpdateTask.cpp | 61 ++++----- launcher/minecraft/ComponentUpdateTask_p.h | 4 +- launcher/minecraft/Logging.cpp | 25 ++++ launcher/minecraft/Logging.h | 26 ++++ launcher/minecraft/PackProfile.cpp | 136 +++++++++++++-------- launcher/modplatform/ModIndex.h | 2 +- 11 files changed, 215 insertions(+), 85 deletions(-) create mode 100644 launcher/minecraft/Logging.cpp create mode 100644 launcher/minecraft/Logging.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 366719dec..e18a8b950 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -206,6 +206,11 @@ set(ICONS_SOURCES # Support for Minecraft instances and launch set(MINECRAFT_SOURCES + + # Logging + minecraft/Logging.h + minecraft/Logging.cpp + # Minecraft support minecraft/auth/AccountData.cpp minecraft/auth/AccountData.h @@ -650,6 +655,22 @@ ecm_qt_declare_logging_category(CORE_SOURCES EXPORT "${Launcher_Name}" ) +ecm_qt_export_logging_category( + IDENTIFIER instanceProfileC + CATEGORY_NAME "launcher.instance.profile" + DEFAULT_SEVERITY Debug + DESCRIPTION "Profile actions" + EXPORT "${Launcher_Name}" +) + +ecm_qt_export_logging_category( + IDENTIFIER instanceProfileResolveC + CATEGORY_NAME "launcher.instance.profile.resolve" + DEFAULT_SEVERITY Debug + DESCRIPTION "Profile component resolusion actions" + EXPORT "${Launcher_Name}" +) + ecm_qt_export_logging_category( IDENTIFIER taskLogC CATEGORY_NAME "launcher.task" @@ -662,7 +683,7 @@ ecm_qt_export_logging_category( IDENTIFIER taskNetLogC CATEGORY_NAME "launcher.task.net" DEFAULT_SEVERITY Debug - DESCRIPTION "task network action" + DESCRIPTION "Task network action" EXPORT "${Launcher_Name}" ) @@ -670,14 +691,14 @@ ecm_qt_export_logging_category( IDENTIFIER taskDownloadLogC CATEGORY_NAME "launcher.task.net.download" DEFAULT_SEVERITY Debug - DESCRIPTION "task network download actions" + DESCRIPTION "Task network download actions" EXPORT "${Launcher_Name}" ) ecm_qt_export_logging_category( IDENTIFIER taskUploadLogC CATEGORY_NAME "launcher.task.net.upload" DEFAULT_SEVERITY Debug - DESCRIPTION "task network upload actions" + DESCRIPTION "Task network upload actions" EXPORT "${Launcher_Name}" ) diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index 0cd33a2b3..c133e7d1a 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -287,7 +287,11 @@ Version::Ptr VersionList::getRecommendedForParent(const QString& uid, const QStr if (foundExplicit != m_versions.end()) { return *foundExplicit; } + return nullptr; +} +Version::Ptr VersionList::getLatestForParent(const QString& uid, const QString& version) +{ Version::Ptr latestCompat = nullptr; for (auto ver : m_versions) { auto& reqs = ver->requiredSet(); diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h index b746d3232..05ecd91d2 100644 --- a/launcher/meta/VersionList.h +++ b/launcher/meta/VersionList.h @@ -44,6 +44,7 @@ class VersionList : public BaseVersionList, public BaseEntity { BaseVersion::Ptr getRecommended() const override; Version::Ptr getRecommendedForParent(const QString& uid, const QString& version); + Version::Ptr getLatestForParent(const QString& uid, const QString& version); QVariant data(const QModelIndex& index, int role) const override; diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index f03ffacc0..175e88d08 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -403,6 +403,18 @@ void Component::updateCachedData() } } +void Component::waitLoadMeta() { + + if (!m_loaded) { + if (!m_metaVersion || !m_metaVersion->isLoaded()) { + // wait for the loaded version from meta + m_metaVersion = APPLICATION->metadataIndex()->getLoadedVersion(m_uid, m_version); + } + m_loaded = true; + updateCachedData(); + } +} + QDebug operator<<(QDebug d, const Component& comp) { d << "Component(" << comp.m_uid << " : " << comp.m_cachedVersion << ")"; return d; diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 8aa6b4743..581a3db95 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -64,6 +64,8 @@ class Component : public QObject, public ProblemProvider { bool revert(); void updateCachedData(); + + void waitLoadMeta(); signals: void dataChanged(); diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index 4d205af6c..7bdc11400 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -8,6 +8,7 @@ #include "cassert" #include "meta/Index.h" #include "meta/Version.h" +#include "minecraft/MinecraftInstance.h" #include "minecraft/OneSixVersionFormat.h" #include "minecraft/ProfileUtils.h" #include "net/Mode.h" @@ -15,6 +16,8 @@ #include "Application.h" #include "tasks/Task.h" +#include "minecraft/Logging.h" + /* * This is responsible for loading the components of a component list AND resolving dependency issues between them */ @@ -36,7 +39,7 @@ ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent) : Task(parent) { d.reset(new ComponentUpdateTaskData); - d->m_list = list; + d->m_profile = list; d->mode = mode; d->netmode = netmode; } @@ -45,7 +48,7 @@ ComponentUpdateTask::~ComponentUpdateTask() {} void ComponentUpdateTask::executeTask() { - qDebug() << "Loading components"; + qCDebug(instanceProfileResolveC) << "Loading components"; loadComponents(); } @@ -63,7 +66,7 @@ LoadResult composeLoadResult(LoadResult a, LoadResult b) static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net::Mode netmode) { if (component->m_loaded) { - qDebug() << component->getName() << "is already loaded"; + qCDebug(instanceProfileResolveC) << component->getName() << "is already loaded"; return LoadResult::LoadedLocal; } @@ -144,7 +147,7 @@ void ComponentUpdateTask::loadComponents() d->remoteLoadSuccessful = true; // load all the components OR their lists... - for (auto component : d->m_list->d->components) { + for (auto component : d->m_profile->d->components) { Task::Ptr loadTask; LoadResult singleResult; RemoteLoadStatus::Type loadType; @@ -175,7 +178,7 @@ void ComponentUpdateTask::loadComponents() } result = composeLoadResult(result, singleResult); if (loadTask) { - qDebug() << "Remote loading is being run for" << component->getName(); + qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" << "Remote loading is being run for" << component->getName(); connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); }); connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); }); connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); @@ -270,7 +273,7 @@ static bool gatherRequirementsFromComponents(const ComponentContainer& input, Re output.erase(componenRequireEx); output.insert(result.outcome); } else { - qCritical() << "Conflicting requirements:" << componentRequire.uid << "versions:" << componentRequire.equalsVersion + qCCritical(instanceProfileResolveC) << "Conflicting requirements:" << componentRequire.uid << "versions:" << componentRequire.equalsVersion << ";" << (*found).equalsVersion; } succeeded &= result.ok; @@ -353,22 +356,22 @@ static bool getTrivialComponentChanges(const ComponentIndex& index, const Requir } while (false); switch (decision) { case Decision::Undetermined: - qCritical() << "No decision for" << reqStr; + qCCritical(instanceProfileResolveC) << "No decision for" << reqStr; succeeded = false; break; case Decision::Met: - qDebug() << reqStr << "Is met."; + qCDebug(instanceProfileResolveC) << reqStr << "Is met."; break; case Decision::Missing: - qDebug() << reqStr << "Is missing and should be added at" << req.indexOfFirstDependee; + qCDebug(instanceProfileResolveC) << 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."; + qCDebug(instanceProfileResolveC) << 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."; + qCDebug(instanceProfileResolveC) << reqStr << "already has different version that cannot be changed."; succeeded = false; break; } @@ -381,7 +384,7 @@ static bool getTrivialComponentChanges(const ComponentIndex& index, const Requir // FIXME: throw all this away and use a graph void ComponentUpdateTask::resolveDependencies(bool checkOnly) { - qDebug() << "Resolving dependencies"; + qCDebug(instanceProfileResolveC) << "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 @@ -393,8 +396,8 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) * * 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; + auto& components = d->m_profile->d->components; + auto& componentIndex = d->m_profile->d->componentIndex; RequireExSet allRequires; QStringList toRemove; @@ -407,10 +410,10 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) } getTrivialRemovals(components, allRequires, toRemove); if (!toRemove.isEmpty()) { - qDebug() << "Removing obsolete components..."; + qCDebug(instanceProfileResolveC) << "Removing obsolete components..."; for (auto& remove : toRemove) { - qDebug() << "Removing" << remove; - d->m_list->remove(remove); + qCDebug(instanceProfileResolveC) << "Removing" << remove; + d->m_profile->remove(remove); } } } while (!toRemove.isEmpty()); @@ -434,14 +437,14 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) if (toAdd.size()) { // add stuff... for (auto& add : toAdd) { - auto component = makeShared(d->m_list, add.uid); + auto component = makeShared(d->m_profile, add.uid); if (!add.equalsVersion.isEmpty()) { // exact version - qDebug() << "Adding" << add.uid << "version" << add.equalsVersion << "at position" << add.indexOfFirstDependee; + qCDebug(instanceProfileResolveC) << "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; + qCDebug(instanceProfileResolveC) << "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()) { @@ -464,7 +467,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) } component->m_dependencyOnly = true; // FIXME: this should not work directly with the component list - d->m_list->insertComponent(add.indexOfFirstDependee, component); + d->m_profile->insertComponent(add.indexOfFirstDependee, component); componentIndex[add.uid] = component; } recursionNeeded = true; @@ -473,7 +476,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) // 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; + qCDebug(instanceProfileResolveC) << "Setting version of " << change.uid << "to" << change.equalsVersion; auto component = componentIndex[change.uid]; component->setVersion(change.equalsVersion); } @@ -490,7 +493,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) { if (static_cast(d->remoteLoadStatusList.size()) < taskIndex) { - qWarning() << "Got task index outside of results" << taskIndex; + qCWarning(instanceProfileResolveC) << "Got task index outside of results" << taskIndex; return; } auto& taskSlot = d->remoteLoadStatusList[taskIndex]; @@ -498,16 +501,16 @@ void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) disconnect(taskSlot.task.get(), &Task::failed, this, nullptr); disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr); if (taskSlot.finished) { - qWarning() << "Got multiple results from remote load task" << taskIndex; + qCWarning(instanceProfileResolveC) << "Got multiple results from remote load task" << taskIndex; return; } - qDebug() << "Remote task" << taskIndex << "succeeded"; + qCDebug(instanceProfileResolveC) << "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); + auto component = d->m_profile->getComponent(taskSlot.PackProfileIndex); component->m_loaded = true; component->updateCachedData(); } @@ -517,7 +520,7 @@ void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg) { if (static_cast(d->remoteLoadStatusList.size()) < taskIndex) { - qWarning() << "Got task index outside of results" << taskIndex; + qCWarning(instanceProfileResolveC) << "Got task index outside of results" << taskIndex; return; } auto& taskSlot = d->remoteLoadStatusList[taskIndex]; @@ -525,10 +528,10 @@ void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg) disconnect(taskSlot.task.get(), &Task::failed, this, nullptr); disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr); if (taskSlot.finished) { - qWarning() << "Got multiple results from remote load task" << taskIndex; + qCWarning(instanceProfileResolveC) << "Got multiple results from remote load task" << taskIndex; return; } - qDebug() << "Remote task" << taskIndex << "failed: " << msg; + qCDebug(instanceProfileResolveC) << "Remote task" << taskIndex << "failed: " << msg; d->remoteLoadSuccessful = false; taskSlot.succeeded = false; taskSlot.finished = true; diff --git a/launcher/minecraft/ComponentUpdateTask_p.h b/launcher/minecraft/ComponentUpdateTask_p.h index b82553700..2fc0b6d9a 100644 --- a/launcher/minecraft/ComponentUpdateTask_p.h +++ b/launcher/minecraft/ComponentUpdateTask_p.h @@ -6,6 +6,8 @@ #include "net/Mode.h" #include "tasks/Task.h" +#include "minecraft/ComponentUpdateTask.h" + class PackProfile; struct RemoteLoadStatus { @@ -18,7 +20,7 @@ struct RemoteLoadStatus { }; struct ComponentUpdateTaskData { - PackProfile* m_list = nullptr; + PackProfile* m_profile = nullptr; QList remoteLoadStatusList; bool remoteLoadSuccessful = true; size_t remoteTasksInProgress = 0; diff --git a/launcher/minecraft/Logging.cpp b/launcher/minecraft/Logging.cpp new file mode 100644 index 000000000..92596de3e --- /dev/null +++ b/launcher/minecraft/Logging.cpp @@ -0,0 +1,25 @@ + +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * 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, version 3. + * + * 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 . + * + */ + +#include "minecraft/Logging.h" +#include + +Q_LOGGING_CATEGORY(instanceProfileC, "launcher.instance.profile") +Q_LOGGING_CATEGORY(instanceProfileResolveC, "launcher.instance.profile.resolve") diff --git a/launcher/minecraft/Logging.h b/launcher/minecraft/Logging.h new file mode 100644 index 000000000..00d43f419 --- /dev/null +++ b/launcher/minecraft/Logging.h @@ -0,0 +1,26 @@ + +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * + * 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, version 3. + * + * 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 . + * + */ + +#pragma once + +#include + +Q_DECLARE_LOGGING_CATEGORY(instanceProfileC) +Q_DECLARE_LOGGING_CATEGORY(instanceProfileResolveC) diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index bdc80b923..09a2ac0cb 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -39,7 +39,6 @@ #include #include -#include #include #include #include @@ -66,6 +65,8 @@ #include "PackProfile_p.h" #include "modplatform/ModIndex.h" +#include "minecraft/Logging.h" + static const QMap modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge }, { "net.minecraftforge", ModPlatform::Forge }, { "net.fabricmc.fabric-loader", ModPlatform::Fabric }, @@ -159,16 +160,16 @@ static bool savePackProfile(const QString& filename, const ComponentContainer& c obj.insert("components", orderArray); QSaveFile outFile(filename); if (!outFile.open(QFile::WriteOnly)) { - qCritical() << "Couldn't open" << outFile.fileName() << "for writing:" << outFile.errorString(); + qCCritical(instanceProfileC) << "Couldn't open" << outFile.fileName() << "for writing:" << outFile.errorString(); return false; } auto data = QJsonDocument(obj).toJson(QJsonDocument::Indented); if (outFile.write(data) != data.size()) { - qCritical() << "Couldn't write all the data into" << outFile.fileName() << "because:" << outFile.errorString(); + qCCritical(instanceProfileC) << "Couldn't write all the data into" << outFile.fileName() << "because:" << outFile.errorString(); return false; } if (!outFile.commit()) { - qCritical() << "Couldn't save" << outFile.fileName() << "because:" << outFile.errorString(); + qCCritical(instanceProfileC) << "Couldn't save" << outFile.fileName() << "because:" << outFile.errorString(); } return true; } @@ -181,12 +182,12 @@ static bool loadPackProfile(PackProfile* parent, { QFile componentsFile(filename); if (!componentsFile.exists()) { - qWarning() << "Components file doesn't exist. This should never happen."; + qCWarning(instanceProfileC) << "Components file" << filename << "doesn't exist. This should never happen."; return false; } if (!componentsFile.open(QFile::ReadOnly)) { - qCritical() << "Couldn't open" << componentsFile.fileName() << " for reading:" << componentsFile.errorString(); - qWarning() << "Ignoring overriden order"; + qCCritical(instanceProfileC) << "Couldn't open" << componentsFile.fileName() << " for reading:" << componentsFile.errorString(); + qCWarning(instanceProfileC) << "Ignoring overridden order"; return false; } @@ -194,8 +195,8 @@ static bool loadPackProfile(PackProfile* parent, QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(componentsFile.readAll(), &error); if (error.error != QJsonParseError::NoError) { - qCritical() << "Couldn't parse" << componentsFile.fileName() << ":" << error.errorString(); - qWarning() << "Ignoring overriden order"; + qCCritical(instanceProfileC) << "Couldn't parse" << componentsFile.fileName() << ":" << error.errorString(); + qCWarning(instanceProfileC) << "Ignoring overridden order"; return false; } @@ -213,7 +214,7 @@ static bool loadPackProfile(PackProfile* parent, container.append(componentFromJsonV1(parent, componentJsonPattern, comp_obj)); } } catch ([[maybe_unused]] const JSONValidationError& err) { - qCritical() << "Couldn't parse" << componentsFile.fileName() << ": bad file format"; + qCCritical(instanceProfileC) << "Couldn't parse" << componentsFile.fileName() << ": bad file format"; container.clear(); return false; } @@ -246,12 +247,12 @@ void PackProfile::buildingFromScratch() void PackProfile::scheduleSave() { if (!d->loaded) { - qDebug() << "Component list should never save if it didn't successfully load, instance:" << d->m_instance->name(); + qDebug() << d->m_instance->name() << "|" << "Component list should never save if it didn't successfully load"; return; } if (!d->dirty) { d->dirty = true; - qDebug() << "Component list save is scheduled for" << d->m_instance->name(); + qDebug() << d->m_instance->name() << "|" << "Component list save is scheduled"; } d->m_saveTimer.start(); } @@ -278,7 +279,7 @@ QString PackProfile::patchFilePathForUid(const QString& uid) const void PackProfile::save_internal() { - qDebug() << "Component list save performed now for" << d->m_instance->name(); + qDebug() << d->m_instance->name() << "|" << "Component list save performed now"; auto filename = componentsFilePath(); savePackProfile(filename, d->components); d->dirty = false; @@ -291,7 +292,7 @@ bool PackProfile::load() // load the new component list and swap it with the current one... ComponentContainer newComponents; if (!loadPackProfile(this, filename, patchesPattern(), newComponents)) { - qCritical() << "Failed to load the component config for instance" << d->m_instance->name(); + qCritical() << d->m_instance->name() << "|" << "Failed to load the component config"; return false; } else { // FIXME: actually use fine-grained updates, not this... @@ -304,7 +305,7 @@ bool PackProfile::load() d->componentIndex.clear(); for (auto component : newComponents) { if (d->componentIndex.contains(component->m_uid)) { - qWarning() << "Ignoring duplicate component entry" << component->m_uid; + qWarning() << d->m_instance->name() << "|" << "Ignoring duplicate component entry" << component->m_uid; continue; } connect(component.get(), &Component::dataChanged, this, &PackProfile::componentDataChanged); @@ -352,14 +353,14 @@ void PackProfile::resolve(Net::Mode netmode) void PackProfile::updateSucceeded() { - qDebug() << "Component list update/resolve task succeeded for" << d->m_instance->name(); + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Component list update/resolve task succeeded"; d->m_updateTask.reset(); invalidateLaunchProfile(); } void PackProfile::updateFailed(const QString& error) { - qDebug() << "Component list update/resolve task failed for" << d->m_instance->name() << "Reason:" << error; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Component list update/resolve task failed " << "Reason:" << error; d->m_updateTask.reset(); invalidateLaunchProfile(); } @@ -375,11 +376,11 @@ void PackProfile::insertComponent(size_t index, ComponentPtr component) { auto id = component->getID(); if (id.isEmpty()) { - qWarning() << "Attempt to add a component with empty ID!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Attempt to add a component with empty ID!"; return; } if (d->componentIndex.contains(id)) { - qWarning() << "Attempt to add a component that is already present!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Attempt to add a component that is already present!"; return; } beginInsertRows(QModelIndex(), static_cast(index), static_cast(index)); @@ -394,7 +395,7 @@ void PackProfile::componentDataChanged() { auto objPtr = qobject_cast(sender()); if (!objPtr) { - qWarning() << "PackProfile got dataChanged signal from a non-Component!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "PackProfile got dataChanged signal from a non-Component!"; return; } if (objPtr->getID() == "net.minecraft") { @@ -410,19 +411,20 @@ void PackProfile::componentDataChanged() } index++; } - qWarning() << "PackProfile got dataChanged signal from a Component which does not belong to it!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "PackProfile got dataChanged signal from a Component which does not belong to it!"; } bool PackProfile::remove(const int index) { auto patch = getComponent(index); if (!patch->isRemovable()) { - qWarning() << "Patch" << patch->getID() << "is non-removable"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is non-removable"; return false; } if (!removeComponent_internal(patch)) { - qCritical() << "Patch" << patch->getID() << "could not be removed"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be removed"; return false; } @@ -451,11 +453,11 @@ bool PackProfile::customize(int index) { auto patch = getComponent(index); if (!patch->isCustomizable()) { - qDebug() << "Patch" << patch->getID() << "is not customizable"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is not customizable"; return false; } if (!patch->customize()) { - qCritical() << "Patch" << patch->getID() << "could not be customized"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be customized"; return false; } invalidateLaunchProfile(); @@ -467,11 +469,11 @@ bool PackProfile::revertToBase(int index) { auto patch = getComponent(index); if (!patch->isRevertible()) { - qDebug() << "Patch" << patch->getID() << "is not revertible"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is not revertible"; return false; } if (!patch->revert()) { - qCritical() << "Patch" << patch->getID() << "could not be reverted"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be reverted"; return false; } invalidateLaunchProfile(); @@ -684,7 +686,8 @@ bool PackProfile::installComponents(QStringList selectedFiles) const QString target = FS::PathCombine(patchDir, versionFile->uid + ".json"); if (!QFile::copy(source, target)) { - qWarning() << "Component" << source << "could not be copied to target" << target; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Component" << source << "could not be copied to target" + << target; result = false; continue; } @@ -717,7 +720,8 @@ bool PackProfile::installEmpty(const QString& uid, const QString& name) QString patchFileName = FS::PathCombine(patchDir, uid + ".json"); QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() + << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -737,7 +741,8 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) if (fileName.size()) { QFile patchFile(fileName); if (patchFile.exists() && !patchFile.remove()) { - qCritical() << "File" << fileName << "could not be removed because:" << patchFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "File" << fileName + << "could not be removed because:" << patchFile.errorString(); return false; } } @@ -753,7 +758,8 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) if (finfo.exists()) { QFile jarModFile(jar[0]); if (!jarModFile.remove()) { - qCritical() << "File" << jar[0] << "could not be removed because:" << jarModFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "File" << jar[0] + << "could not be removed because:" << jarModFile.errorString(); return false; } return true; @@ -810,7 +816,8 @@ bool PackProfile::installJarMods_internal(QStringList filepaths) QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() + << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -864,7 +871,8 @@ bool PackProfile::installCustomJar_internal(QString filepath) QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() + << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -919,7 +927,8 @@ bool PackProfile::installAgents_internal(QStringList filepaths) QFile patchFile(FS::PathCombine(patchDir, targetId + ".json")); if (!patchFile.open(QFile::WriteOnly)) { - qCritical() << "Error opening" << patchFile.fileName() << "for reading:" << patchFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << patchFile.fileName() + << "for reading:" << patchFile.errorString(); return false; } @@ -941,12 +950,13 @@ std::shared_ptr PackProfile::getProfile() const try { auto profile = std::make_shared(); for (auto file : d->components) { - qDebug() << "Applying" << file->getID() << (file->getProblemSeverity() == ProblemSeverity::Error ? "ERROR" : "GOOD"); + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Applying" << file->getID() + << (file->getProblemSeverity() == ProblemSeverity::Error ? "ERROR" : "GOOD"); file->applyTo(profile.get()); } d->m_profile = profile; } catch (const Exception& error) { - qWarning() << "Couldn't apply profile patches because: " << error.cause(); + qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Couldn't apply profile patches because: " << error.cause(); } } return d->m_profile; @@ -959,36 +969,58 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version ComponentPtr component = *iter; // set existing if (component->revert()) { - component->setVersion(version); - component->setImportant(important); // remove linked components to let them re-resolve their versions if (important) { + component->waitLoadMeta(); 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 recommended version..."; + qCDebug(instanceProfileC) + << d->m_instance->name() << "|" << comp->getID() << "is a mod loader, updating it to a compatible version"; + auto versionList = APPLICATION->metadataIndex()->get(comp->getID()); + versionList->waitToLoad(); if (versionList) { - auto recommended = versionList->getRecommendedForParent(comp->getID(), version); + auto recommended = versionList->getRecommendedForParent(uid, version); if (recommended) { - qDebug() << "Setting updated loader version: " << comp->getID() << " = " << recommended->version(); - setComponentVersion(comp->getID(), recommended->version()); + qCDebug(instanceProfileC) + << d->m_instance->name() << "|" << "setting updated loader to recommended version: " << comp->getID() + << " = " << recommended->version(); + comp->setVersion(recommended->version()); } else { - qDebug() << "no recommended version for" << comp->getID(); + auto latest = versionList->getLatestForParent(uid, version); + if (latest) { + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "setting updated loader to latest compatible version: " << comp->getID() + << " = " << latest->version(); + comp->setVersion(latest->version()); + } else { + qCDebug(instanceProfileC) + << d->m_instance->name() << "|" << "no compatible version for" << comp->getID() << "removing"; + remove(comp->getID()); + } } } else { - qDebug() << "no version list in metadata index for" << comp->getID(); + qCDebug(instanceProfileC) + << d->m_instance->name() << "|" << "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"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << comp->getID() << ":" << comp->getVersion() + << "linked to important component: " << uid << " | Removing so it re-resolves"; remove(comp->getID()); } } } + // set new version + component->setVersion(version); + component->setImportant(important); + + if (important) { + resolve(Net::Mode::Online); + } return true; } return false; @@ -1006,11 +1038,12 @@ ComponentContainer PackProfile::collectTreeLinked(const QString& uid) { ComponentContainer linked; for (auto comp : d->components) { - qDebug() << "scanning" << comp->getID() << "for tree link"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "scanning" << comp->getID() << ":" << comp->getVersion() + << "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; + qCDebug(instanceProfileResolveC) << comp->getID() << ":" << comp->getVersion() << "depends on" << uid; linked.append(comp); } } @@ -1018,12 +1051,13 @@ ComponentContainer PackProfile::collectTreeLinked(const QString& uid) if (iter != d->componentIndex.end()) { ComponentPtr comp = *iter; comp->updateCachedData(); - qDebug() << comp->getID() << "has" << comp->m_cachedRequires.size() << "dependencies"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << comp->getID() << ":" << comp->getVersion() << "has" + << comp->m_cachedRequires.size() << "dependencies"; for (auto dep : comp->m_cachedRequires) { - qDebug() << uid << "depends on" << comp->getID(); + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << uid << "depends on" << dep.uid; auto found = d->componentIndex.find(dep.uid); if (found != d->componentIndex.end()) { - qDebug() << comp->getID() << "is present"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" << (*found)->getID() << "is present"; linked.append(*found); } } diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index 91c9898a9..b3f86933f 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -44,7 +44,7 @@ namespace ProviderCapabilities { const char* name(ResourceProvider); QString readableName(ResourceProvider); QStringList hashType(ResourceProvider); -}; // namespace ProviderCapabilities +} // namespace ProviderCapabilities struct ModpackAuthor { QString name; From cf319649f9c457bba14d097ae9ce4c839be188b2 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:28:42 -0700 Subject: [PATCH 05/21] fix qt5 lwjgl recommend + spelling Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/meta/VersionList.cpp | 6 +++--- launcher/meta/VersionList.h | 4 ++-- launcher/ui/pages/instance/VersionPage.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index c133e7d1a..8bc326839 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -180,12 +180,12 @@ void VersionList::parse(const QJsonObject& obj) parseVersionList(obj, this); } -void VersionList::addExternalRecomends(const QVector& recomends) +void VersionList::addExternalRecommends(const QStringList& recommends) { - m_externalRecommendsVersions.append(recomends); + m_externalRecommendsVersions.append(recommends); } -void VersionList::clearExternalRecomends() +void VersionList::clearExternalRecommends() { m_externalRecommendsVersions.clear(); } diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h index 05ecd91d2..2e46a79f0 100644 --- a/launcher/meta/VersionList.h +++ b/launcher/meta/VersionList.h @@ -71,8 +71,8 @@ class VersionList : public BaseVersionList, public BaseEntity { void merge(const VersionList::Ptr& other); void mergeFromIndex(const VersionList::Ptr& other); void parse(const QJsonObject& obj) override; - void addExternalRecomends(const QVector& recomends); - void clearExternalRecomends(); + void addExternalRecommends(const QStringList& recommends); + void clearExternalRecommends(); signals: void nameChanged(const QString& name); diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index 545798499..8ae21d2e4 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -370,7 +370,7 @@ void VersionPage::on_actionChange_version_triggered() auto patch = m_profile->getComponent(versionRow); auto name = patch->getName(); auto list = patch->getVersionList(); - list->clearExternalRecomends(); + list->clearExternalRecommends(); if (!list) { return; } @@ -384,7 +384,7 @@ void VersionPage::on_actionChange_version_triggered() if (lwjglReq != minecraft->m_cachedRequires.cend()) { auto lwjglVersion = !lwjglReq->equalsVersion.isEmpty() ? lwjglReq->equalsVersion : lwjglReq->suggests; if (!lwjglVersion.isEmpty()) { - list->addExternalRecomends({ lwjglVersion }); + list->addExternalRecommends({ lwjglVersion }); } } } From 474effe7c74a8d78a6e35cd742e99669353bf19e Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 25 Jun 2024 11:13:15 +0300 Subject: [PATCH 06/21] clang-format Signed-off-by: Trial97 --- launcher/meta/VersionList.cpp | 5 +- launcher/meta/VersionList.h | 1 - launcher/minecraft/Component.cpp | 7 +- launcher/minecraft/Component.h | 2 +- launcher/minecraft/ComponentUpdateTask.cpp | 10 +- launcher/minecraft/PackProfile.cpp | 101 ++++++++++++--------- 6 files changed, 74 insertions(+), 52 deletions(-) diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index 8bc326839..28a42d28d 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -254,8 +254,9 @@ void VersionList::setupAddedVersion(const int row, const Version::Ptr& version) connect(version.get(), &Version::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector() << RequiresRole); }); - connect(version.get(), &Version::timeChanged, this, - [this, row]() { emit dataChanged(index(row), index(row), { TimeRole, SortRole }); }); + connect(version.get(), &Version::timeChanged, this, [this, row]() { + emit dataChanged(index(row), index(row), { TimeRole, SortRole }); + }); connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), { TypeRole }); }); } diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h index 2e46a79f0..eb79e96f1 100644 --- a/launcher/meta/VersionList.h +++ b/launcher/meta/VersionList.h @@ -46,7 +46,6 @@ class VersionList : public BaseVersionList, public BaseEntity { Version::Ptr getRecommendedForParent(const QString& uid, const QString& version); Version::Ptr getLatestForParent(const QString& uid, const QString& version); - QVariant data(const QModelIndex& index, int role) const override; RoleList providesRoles() const override; QHash roleNames() const override; diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 175e88d08..6ea9ee60b 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -403,8 +403,8 @@ void Component::updateCachedData() } } -void Component::waitLoadMeta() { - +void Component::waitLoadMeta() +{ if (!m_loaded) { if (!m_metaVersion || !m_metaVersion->isLoaded()) { // wait for the loaded version from meta @@ -415,7 +415,8 @@ void Component::waitLoadMeta() { } } -QDebug operator<<(QDebug d, const Component& comp) { +QDebug operator<<(QDebug d, const Component& comp) +{ d << "Component(" << comp.m_uid << " : " << comp.m_cachedVersion << ")"; return d; } diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 581a3db95..67d79e231 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -64,7 +64,7 @@ class Component : public QObject, public ProblemProvider { bool revert(); void updateCachedData(); - + void waitLoadMeta(); signals: diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index 7bdc11400..dc59d2dc9 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -178,7 +178,8 @@ void ComponentUpdateTask::loadComponents() } result = composeLoadResult(result, singleResult); if (loadTask) { - qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" << "Remote loading is being run for" << component->getName(); + qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" + << "Remote loading is being run for" << component->getName(); connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); }); connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); }); connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); @@ -273,8 +274,8 @@ static bool gatherRequirementsFromComponents(const ComponentContainer& input, Re output.erase(componenRequireEx); output.insert(result.outcome); } else { - qCCritical(instanceProfileResolveC) << "Conflicting requirements:" << componentRequire.uid << "versions:" << componentRequire.equalsVersion - << ";" << (*found).equalsVersion; + qCCritical(instanceProfileResolveC) << "Conflicting requirements:" << componentRequire.uid + << "versions:" << componentRequire.equalsVersion << ";" << (*found).equalsVersion; } succeeded &= result.ok; } else { @@ -440,7 +441,8 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) auto component = makeShared(d->m_profile, add.uid); if (!add.equalsVersion.isEmpty()) { // exact version - qCDebug(instanceProfileResolveC) << "Adding" << add.uid << "version" << add.equalsVersion << "at position" << add.indexOfFirstDependee; + qCDebug(instanceProfileResolveC) + << "Adding" << add.uid << "version" << add.equalsVersion << "at position" << add.indexOfFirstDependee; component->m_version = add.equalsVersion; } else { // version needs to be decided diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 09a2ac0cb..ce57288f6 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -247,12 +247,14 @@ void PackProfile::buildingFromScratch() void PackProfile::scheduleSave() { if (!d->loaded) { - qDebug() << d->m_instance->name() << "|" << "Component list should never save if it didn't successfully load"; + qDebug() << d->m_instance->name() << "|" + << "Component list should never save if it didn't successfully load"; return; } if (!d->dirty) { d->dirty = true; - qDebug() << d->m_instance->name() << "|" << "Component list save is scheduled"; + qDebug() << d->m_instance->name() << "|" + << "Component list save is scheduled"; } d->m_saveTimer.start(); } @@ -279,7 +281,8 @@ QString PackProfile::patchFilePathForUid(const QString& uid) const void PackProfile::save_internal() { - qDebug() << d->m_instance->name() << "|" << "Component list save performed now"; + qDebug() << d->m_instance->name() << "|" + << "Component list save performed now"; auto filename = componentsFilePath(); savePackProfile(filename, d->components); d->dirty = false; @@ -292,7 +295,8 @@ bool PackProfile::load() // load the new component list and swap it with the current one... ComponentContainer newComponents; if (!loadPackProfile(this, filename, patchesPattern(), newComponents)) { - qCritical() << d->m_instance->name() << "|" << "Failed to load the component config"; + qCritical() << d->m_instance->name() << "|" + << "Failed to load the component config"; return false; } else { // FIXME: actually use fine-grained updates, not this... @@ -305,7 +309,8 @@ bool PackProfile::load() d->componentIndex.clear(); for (auto component : newComponents) { if (d->componentIndex.contains(component->m_uid)) { - qWarning() << d->m_instance->name() << "|" << "Ignoring duplicate component entry" << component->m_uid; + qWarning() << d->m_instance->name() << "|" + << "Ignoring duplicate component entry" << component->m_uid; continue; } connect(component.get(), &Component::dataChanged, this, &PackProfile::componentDataChanged); @@ -353,14 +358,17 @@ void PackProfile::resolve(Net::Mode netmode) void PackProfile::updateSucceeded() { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Component list update/resolve task succeeded"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "Component list update/resolve task succeeded"; d->m_updateTask.reset(); invalidateLaunchProfile(); } void PackProfile::updateFailed(const QString& error) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Component list update/resolve task failed " << "Reason:" << error; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "Component list update/resolve task failed " + << "Reason:" << error; d->m_updateTask.reset(); invalidateLaunchProfile(); } @@ -376,11 +384,13 @@ void PackProfile::insertComponent(size_t index, ComponentPtr component) { auto id = component->getID(); if (id.isEmpty()) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Attempt to add a component with empty ID!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "Attempt to add a component with empty ID!"; return; } if (d->componentIndex.contains(id)) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Attempt to add a component that is already present!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "Attempt to add a component that is already present!"; return; } beginInsertRows(QModelIndex(), static_cast(index), static_cast(index)); @@ -395,7 +405,8 @@ void PackProfile::componentDataChanged() { auto objPtr = qobject_cast(sender()); if (!objPtr) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "PackProfile got dataChanged signal from a non-Component!"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "PackProfile got dataChanged signal from a non-Component!"; return; } if (objPtr->getID() == "net.minecraft") { @@ -419,12 +430,14 @@ bool PackProfile::remove(const int index) { auto patch = getComponent(index); if (!patch->isRemovable()) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is non-removable"; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "is non-removable"; return false; } if (!removeComponent_internal(patch)) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be removed"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "could not be removed"; return false; } @@ -453,11 +466,13 @@ bool PackProfile::customize(int index) { auto patch = getComponent(index); if (!patch->isCustomizable()) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is not customizable"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "is not customizable"; return false; } if (!patch->customize()) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be customized"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "could not be customized"; return false; } invalidateLaunchProfile(); @@ -469,11 +484,13 @@ bool PackProfile::revertToBase(int index) { auto patch = getComponent(index); if (!patch->isRevertible()) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "is not revertible"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "is not revertible"; return false; } if (!patch->revert()) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Patch" << patch->getID() << "could not be reverted"; + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Patch" << patch->getID() << "could not be reverted"; return false; } invalidateLaunchProfile(); @@ -686,8 +703,8 @@ bool PackProfile::installComponents(QStringList selectedFiles) const QString target = FS::PathCombine(patchDir, versionFile->uid + ".json"); if (!QFile::copy(source, target)) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Component" << source << "could not be copied to target" - << target; + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "Component" << source << "could not be copied to target" << target; result = false; continue; } @@ -720,8 +737,8 @@ bool PackProfile::installEmpty(const QString& uid, const QString& name) QString patchFileName = FS::PathCombine(patchDir, uid + ".json"); QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -741,8 +758,8 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) if (fileName.size()) { QFile patchFile(fileName); if (patchFile.exists() && !patchFile.remove()) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "File" << fileName - << "could not be removed because:" << patchFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "File" << fileName << "could not be removed because:" << patchFile.errorString(); return false; } } @@ -758,8 +775,8 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) if (finfo.exists()) { QFile jarModFile(jar[0]); if (!jarModFile.remove()) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "File" << jar[0] - << "could not be removed because:" << jarModFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "File" << jar[0] << "could not be removed because:" << jarModFile.errorString(); return false; } return true; @@ -816,8 +833,8 @@ bool PackProfile::installJarMods_internal(QStringList filepaths) QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -871,8 +888,8 @@ bool PackProfile::installCustomJar_internal(QString filepath) QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -927,8 +944,8 @@ bool PackProfile::installAgents_internal(QStringList filepaths) QFile patchFile(FS::PathCombine(patchDir, targetId + ".json")); if (!patchFile.open(QFile::WriteOnly)) { - qCCritical(instanceProfileC) << d->m_instance->name() << "|" << "Error opening" << patchFile.fileName() - << "for reading:" << patchFile.errorString(); + qCCritical(instanceProfileC) << d->m_instance->name() << "|" + << "Error opening" << patchFile.fileName() << "for reading:" << patchFile.errorString(); return false; } @@ -950,13 +967,15 @@ std::shared_ptr PackProfile::getProfile() const try { auto profile = std::make_shared(); for (auto file : d->components) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "Applying" << file->getID() + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "Applying" << file->getID() << (file->getProblemSeverity() == ProblemSeverity::Error ? "ERROR" : "GOOD"); file->applyTo(profile.get()); } d->m_profile = profile; } catch (const Exception& error) { - qCWarning(instanceProfileC) << d->m_instance->name() << "|" << "Couldn't apply profile patches because: " << error.cause(); + qCWarning(instanceProfileC) << d->m_instance->name() << "|" + << "Couldn't apply profile patches because: " << error.cause(); } } return d->m_profile; @@ -986,9 +1005,9 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version if (versionList) { auto recommended = versionList->getRecommendedForParent(uid, version); if (recommended) { - qCDebug(instanceProfileC) - << d->m_instance->name() << "|" << "setting updated loader to recommended version: " << comp->getID() - << " = " << recommended->version(); + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "setting updated loader to recommended version: " << comp->getID() << " = " + << recommended->version(); comp->setVersion(recommended->version()); } else { auto latest = versionList->getLatestForParent(uid, version); @@ -998,14 +1017,14 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version << " = " << latest->version(); comp->setVersion(latest->version()); } else { - qCDebug(instanceProfileC) - << d->m_instance->name() << "|" << "no compatible version for" << comp->getID() << "removing"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "no compatible version for" << comp->getID() << "removing"; remove(comp->getID()); } } } else { - qCDebug(instanceProfileC) - << d->m_instance->name() << "|" << "no version list in metadata index for" << comp->getID(); + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "no version list in metadata index for" << comp->getID(); } } else { qCDebug(instanceProfileC) << d->m_instance->name() << "|" << comp->getID() << ":" << comp->getVersion() @@ -1038,8 +1057,8 @@ ComponentContainer PackProfile::collectTreeLinked(const QString& uid) { ComponentContainer linked; for (auto comp : d->components) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << "scanning" << comp->getID() << ":" << comp->getVersion() - << "for tree link"; + qCDebug(instanceProfileC) << d->m_instance->name() << "|" + << "scanning" << comp->getID() << ":" << comp->getVersion() << "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()) { From a85d6cb1f2a12efd40b12f5a59fbb56a8d1cc4fd Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:42:25 -0700 Subject: [PATCH 07/21] move resolution into update actions in task. Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/Component.cpp | 37 ++++- launcher/minecraft/Component.h | 33 +++++ launcher/minecraft/ComponentUpdateTask.cpp | 151 +++++++++++++++++++++ launcher/minecraft/ComponentUpdateTask.h | 5 + launcher/minecraft/PackProfile.cpp | 83 +---------- launcher/minecraft/PackProfile.h | 4 - 6 files changed, 231 insertions(+), 82 deletions(-) diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 6ea9ee60b..67f26a02e 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -38,6 +38,7 @@ #include #include +#include #include "Application.h" #include "FileSystem.h" @@ -235,7 +236,8 @@ ProblemSeverity Component::getProblemSeverity() const { auto file = getVersionFile(); if (file) { - return file->getProblemSeverity(); + auto severity = file->getProblemSeverity(); + return m_componentProblemSeverity > severity ? m_componentProblemSeverity : severity; } return ProblemSeverity::Error; } @@ -244,11 +246,27 @@ const QList Component::getProblems() const { auto file = getVersionFile(); if (file) { - return file->getProblems(); + auto problems = file->getProblems(); + problems.append(m_componentProblems); + return problems; } return { { ProblemSeverity::Error, QObject::tr("Patch is not loaded yet.") } }; } +void Component::addComponentProblem(ProblemSeverity severity, const QString& description) +{ + if (severity > m_componentProblemSeverity) { + m_componentProblemSeverity = severity; + } + m_componentProblems.append({ severity, description }); +} + +void Component::resetComponentProblems() +{ + m_componentProblems.clear(); + m_componentProblemSeverity = ProblemSeverity::None; +} + void Component::setVersion(const QString& version) { if (version == m_version) { @@ -415,6 +433,21 @@ void Component::waitLoadMeta() } } +void Component::setUpdateAction(UpdateAction action) +{ + m_updateAction = action; +} + +std::optional Component::getUpdateAction() +{ + return m_updateAction; +} + +void Component::clearUpdateAction() +{ + m_updateAction.reset(); +} + QDebug operator<<(QDebug d, const Component& comp) { d << "Component(" << comp.m_uid << " : " << comp.m_cachedVersion << ")"; diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 67d79e231..50c4e02db 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "ProblemProvider.h" #include "QObjectPtr.h" #include "meta/JsonFormat.h" @@ -16,6 +17,26 @@ class VersionList; } // namespace Meta class VersionFile; +struct UpdateActionChangeVerison { + /// version to change to + QString targetVersion; +}; +struct UpdateActionLatestRecommendedCompatable { + /// Parent uid + QString parentUid; + QString parentName; + /// Parent version + QString version; + /// +}; +struct UpdateActionRemove {}; +struct UpdateActionImportantChanged { + QString oldVersion; +}; + +using UpdateAction = + std::variant; + class Component : public QObject, public ProblemProvider { Q_OBJECT public: @@ -58,6 +79,8 @@ class Component : public QObject, public ProblemProvider { const QList getProblems() const override; ProblemSeverity getProblemSeverity() const override; + void addComponentProblem(ProblemSeverity severity, const QString& description); + void resetComponentProblems(); void setVersion(const QString& version); bool customize(); @@ -67,6 +90,11 @@ class Component : public QObject, public ProblemProvider { void waitLoadMeta(); + void setUpdateAction(UpdateAction action); + void clearUpdateAction(); + std::optional getUpdateAction(); + std::optional takeUpdateAction(); + signals: void dataChanged(); @@ -104,6 +132,11 @@ class Component : public QObject, public ProblemProvider { std::shared_ptr m_metaVersion; std::shared_ptr m_file; bool m_loaded = false; + + private: + QList m_componentProblems; + ProblemSeverity m_componentProblemSeverity = ProblemSeverity::None; + std::optional m_updateAction = std::nullopt; }; using ComponentPtr = shared_qobject_ptr; diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index dc59d2dc9..8f19f20c8 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -1,9 +1,11 @@ #include "ComponentUpdateTask.h" +#include #include "Component.h" #include "ComponentUpdateTask_p.h" #include "PackProfile.h" #include "PackProfile_p.h" +#include "ProblemProvider.h" #include "Version.h" #include "cassert" #include "meta/Index.h" @@ -196,6 +198,7 @@ void ComponentUpdateTask::loadComponents() switch (result) { case LoadResult::LoadedLocal: { // Everything got loaded. Advance to dependency resolution. + performUpdateActions(); resolveDependencies(d->mode == Mode::Launch || d->netmode == Net::Mode::Offline); break; } @@ -380,6 +383,42 @@ static bool getTrivialComponentChanges(const ComponentIndex& index, const Requir return succeeded; } +ComponentContainer ComponentUpdateTask::collectTreeLinked(const QString& uid) +{ + ComponentContainer linked; + + auto& components = d->m_profile->d->components; + auto& componentIndex = d->m_profile->d->componentIndex; + auto& instance = d->m_profile->d->m_instance; + for (auto comp : components) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" + << "scanning" << comp->getID() << ":" << comp->getVersion() << "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()) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" << comp->getID() << ":" << comp->getVersion() << "depends on" + << uid; + linked.append(comp); + } + } + auto iter = componentIndex.find(uid); + if (iter != componentIndex.end()) { + ComponentPtr comp = *iter; + comp->updateCachedData(); + qCDebug(instanceProfileResolveC) << instance->name() << "|" << comp->getID() << ":" << comp->getVersion() << "has" + << comp->m_cachedRequires.size() << "dependencies"; + for (auto dep : comp->m_cachedRequires) { + qCDebug(instanceProfileC) << instance->name() << "|" << uid << "depends on" << dep.uid; + auto found = componentIndex.find(dep.uid); + if (found != componentIndex.end()) { + qCDebug(instanceProfileC) << instance->name() << "|" << (*found)->getID() << "is present"; + linked.append(*found); + } + } + } + return linked; +} + // 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 @@ -488,10 +527,121 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) if (recursionNeeded) { loadComponents(); } else { + finalizeComponents(); emitSucceeded(); } } +// Variant visitation via lambda +template +struct overload : Ts... { + using Ts::operator()...; +}; +template +overload(Ts...) -> overload; + +void ComponentUpdateTask::performUpdateActions() +{ + auto& components = d->m_profile->d->components; + + bool addedActions; + do { + addedActions = false; + for (auto component : components) { + if (auto action = component->getUpdateAction()) { + auto visitor = overload{ + [&component](const UpdateActionChangeVerison& cv) { + component->setVersion(cv.targetVersion); + component->waitLoadMeta(); + }, + [&component](const UpdateActionLatestRecommendedCompatable lrc) { + auto versionList = APPLICATION->metadataIndex()->get(component->getID()); + versionList->waitToLoad(); + if (versionList) { + auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); + if (recommended) { + component->setVersion(recommended->version()); + component->waitLoadMeta(); + return; + } + + auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); + if (latest) { + component->setVersion(latest->version()); + component->waitLoadMeta(); + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No compatible version of %1 found for %2 %3") + .arg(component->getName(), lrc.parentName, lrc.version)); + } + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No version list in metadata index for %1").arg(component->getID())); + } + }, + [this, &component](const UpdateActionRemove&) { d->m_profile->remove(component->getID()); }, + [this, &component, &addedActions](const UpdateActionImportantChanged&) { + auto linked = collectTreeLinked(component->getID()); + for (auto comp : linked) { + if (comp->isCustom()) { + continue; + } + auto compUid = comp->getID(); + auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), + [compUid](const Meta::Require& req) { return req.uid == compUid; }); + if (parentReq != component->m_cachedRequires.end()) { + auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; + if (!newVersion.isEmpty()) { + comp->setUpdateAction(UpdateAction{ UpdateActionChangeVerison{ newVersion } }); + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + addedActions = true; + } + } + }; + std::visit(visitor, *action); + component->clearUpdateAction(); + } + } + } while (addedActions); +} + +void ComponentUpdateTask::finalizeComponents() +{ + auto& components = d->m_profile->d->components; + auto& componentIndex = d->m_profile->d->componentIndex; + for (auto component : components) { + for (auto req : component->m_cachedRequires) { + auto found = componentIndex.find(req.uid); + if (found == componentIndex.cend()) { + component->addComponentProblem( + ProblemSeverity::Error, + QObject::tr("%1 is missing requirement %2 %3") + .arg(component->getName(), req.uid, req.equalsVersion.isEmpty() ? req.suggests : req.equalsVersion)); + } else { + auto reqComp = *found; + if (!reqComp->getProblems().isEmpty()) { + component->addComponentProblem( + reqComp->getProblemSeverity(), + QObject::tr("%1, a dependency of this component, has reported issues").arg(reqComp->getName())); + } + } + } + } +} + void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) { if (static_cast(d->remoteLoadStatusList.size()) < taskIndex) { @@ -551,6 +701,7 @@ void ComponentUpdateTask::checkIfAllFinished() if (d->remoteLoadSuccessful) { // nothing bad happened... clear the temp load status and proceed with looking at dependencies d->remoteLoadStatusList.clear(); + performUpdateActions(); resolveDependencies(d->mode == Mode::Launch); } else { // remote load failed... report error and bail diff --git a/launcher/minecraft/ComponentUpdateTask.h b/launcher/minecraft/ComponentUpdateTask.h index 2f396a049..484c0bedd 100644 --- a/launcher/minecraft/ComponentUpdateTask.h +++ b/launcher/minecraft/ComponentUpdateTask.h @@ -1,5 +1,6 @@ #pragma once +#include "minecraft/Component.h" #include "net/Mode.h" #include "tasks/Task.h" @@ -21,7 +22,11 @@ class ComponentUpdateTask : public Task { private: void loadComponents(); + /// collects components that are dependent on or dependencies of the component + QList collectTreeLinked(const QString& uid); void resolveDependencies(bool checkOnly); + void performUpdateActions(); + void finalizeComponents(); void remoteLoadSucceeded(size_t index); void remoteLoadFailed(size_t index, const QString& msg); diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index ce57288f6..debbf0fa7 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include "Application.h" #include "Exception.h" @@ -56,6 +57,7 @@ #include "Json.h" #include "meta/Index.h" #include "meta/JsonFormat.h" +#include "minecraft/Component.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/OneSixVersionFormat.h" #include "minecraft/ProfileUtils.h" @@ -67,6 +69,8 @@ #include "minecraft/Logging.h" +#include "ui/dialogs/CustomMessageBox.h" + static const QMap modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge }, { "net.minecraftforge", ModPlatform::Forge }, { "net.fabricmc.fabric-loader", ModPlatform::Fabric }, @@ -988,58 +992,16 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version ComponentPtr component = *iter; // set existing if (component->revert()) { - // remove linked components to let them re-resolve their versions - if (important) { - component->waitLoadMeta(); - auto linked = collectTreeLinked(uid); - for (auto comp : linked) { - if (comp->isCustom()) { - continue; - } - if (modloaderMapping.contains(comp->getID())) { - qCDebug(instanceProfileC) - << d->m_instance->name() << "|" << comp->getID() << "is a mod loader, updating it to a compatible version"; - - auto versionList = APPLICATION->metadataIndex()->get(comp->getID()); - versionList->waitToLoad(); - if (versionList) { - auto recommended = versionList->getRecommendedForParent(uid, version); - if (recommended) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" - << "setting updated loader to recommended version: " << comp->getID() << " = " - << recommended->version(); - comp->setVersion(recommended->version()); - } else { - auto latest = versionList->getLatestForParent(uid, version); - if (latest) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" - << "setting updated loader to latest compatible version: " << comp->getID() - << " = " << latest->version(); - comp->setVersion(latest->version()); - } else { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" - << "no compatible version for" << comp->getID() << "removing"; - remove(comp->getID()); - } - } - } else { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" - << "no version list in metadata index for" << comp->getID(); - } - } else { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << comp->getID() << ":" << comp->getVersion() - << "linked to important component: " << uid << " | Removing so it re-resolves"; - remove(comp->getID()); - } - } - } // set new version + auto oldVersion = component->getVersion(); component->setVersion(version); component->setImportant(important); if (important) { + component->setUpdateAction(UpdateAction{ UpdateActionImportantChanged{ oldVersion } }); resolve(Net::Mode::Online); } + return true; } return false; @@ -1053,37 +1015,6 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version } } -ComponentContainer PackProfile::collectTreeLinked(const QString& uid) -{ - ComponentContainer linked; - for (auto comp : d->components) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" - << "scanning" << comp->getID() << ":" << comp->getVersion() << "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()) { - qCDebug(instanceProfileResolveC) << comp->getID() << ":" << comp->getVersion() << "depends on" << uid; - linked.append(comp); - } - } - auto iter = d->componentIndex.find(uid); - if (iter != d->componentIndex.end()) { - ComponentPtr comp = *iter; - comp->updateCachedData(); - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << comp->getID() << ":" << comp->getVersion() << "has" - << comp->m_cachedRequires.size() << "dependencies"; - for (auto dep : comp->m_cachedRequires) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << uid << "depends on" << dep.uid; - auto found = d->componentIndex.find(dep.uid); - if (found != d->componentIndex.end()) { - qCDebug(instanceProfileC) << d->m_instance->name() << "|" << (*found)->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 f733b3524..e58e9ae9a 100644 --- a/launcher/minecraft/PackProfile.h +++ b/launcher/minecraft/PackProfile.h @@ -48,7 +48,6 @@ #include "Component.h" #include "LaunchProfile.h" -#include "minecraft/PackProfile_p.h" #include "modplatform/ModIndex.h" #include "net/Mode.h" @@ -120,9 +119,6 @@ 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; From 4ed92a95c2b362d09a8a2ff81926c282f1227c4c Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:28:09 -0700 Subject: [PATCH 08/21] fix segfaults consistently set component problems Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/Component.cpp | 5 +- launcher/minecraft/Component.h | 17 +- launcher/minecraft/ComponentUpdateTask.cpp | 183 +++++++++++++-------- 3 files changed, 131 insertions(+), 74 deletions(-) diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 67f26a02e..00d3f2e42 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -45,6 +45,7 @@ #include "OneSixVersionFormat.h" #include "VersionFile.h" #include "meta/Version.h" +#include "minecraft/Component.h" #include "minecraft/PackProfile.h" #include @@ -438,14 +439,14 @@ void Component::setUpdateAction(UpdateAction action) m_updateAction = action; } -std::optional Component::getUpdateAction() +UpdateAction Component::getUpdateAction() { return m_updateAction; } void Component::clearUpdateAction() { - m_updateAction.reset(); + m_updateAction = UpdateAction{ UpdateActionNone{} }; } QDebug operator<<(QDebug d, const Component& comp) diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 50c4e02db..94a964182 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "ProblemProvider.h" #include "QObjectPtr.h" #include "meta/JsonFormat.h" @@ -17,7 +18,7 @@ class VersionList; } // namespace Meta class VersionFile; -struct UpdateActionChangeVerison { +struct UpdateActionChangeVersion { /// version to change to QString targetVersion; }; @@ -34,8 +35,13 @@ struct UpdateActionImportantChanged { QString oldVersion; }; -using UpdateAction = - std::variant; +using UpdateActionNone = std::monostate; + +using UpdateAction = std::variant; class Component : public QObject, public ProblemProvider { Q_OBJECT @@ -92,8 +98,7 @@ class Component : public QObject, public ProblemProvider { void setUpdateAction(UpdateAction action); void clearUpdateAction(); - std::optional getUpdateAction(); - std::optional takeUpdateAction(); + UpdateAction getUpdateAction(); signals: void dataChanged(); @@ -136,7 +141,7 @@ class Component : public QObject, public ProblemProvider { private: QList m_componentProblems; ProblemSeverity m_componentProblemSeverity = ProblemSeverity::None; - std::optional m_updateAction = std::nullopt; + UpdateAction m_updateAction = UpdateAction{ UpdateActionNone{} }; }; using ComponentPtr = shared_qobject_ptr; diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index 8f19f20c8..8001627e4 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -153,6 +153,7 @@ void ComponentUpdateTask::loadComponents() Task::Ptr loadTask; LoadResult singleResult; RemoteLoadStatus::Type loadType; + component->resetComponentProblems(); // 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 @@ -445,6 +446,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) allRequires.clear(); toRemove.clear(); if (!gatherRequirementsFromComponents(components, allRequires)) { + finalizeComponents(); emitFailed(tr("Conflicting requirements detected during dependency checking!")); return; } @@ -461,10 +463,12 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) RequireExSet toChange; bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange); if (!succeeded) { + finalizeComponents(); emitFailed(tr("Instance has conflicting dependencies.")); return; } if (checkOnly) { + finalizeComponents(); if (toAdd.size() || toChange.size()) { emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch.")); } else { @@ -542,77 +546,115 @@ overload(Ts...) -> overload; void ComponentUpdateTask::performUpdateActions() { - auto& components = d->m_profile->d->components; - + auto& instance = d->m_profile->d->m_instance; bool addedActions; + QStringList toRemove; do { addedActions = false; + toRemove.clear(); + auto& components = d->m_profile->d->components; + auto& componentIndex = d->m_profile->d->componentIndex; for (auto component : components) { - if (auto action = component->getUpdateAction()) { - auto visitor = overload{ - [&component](const UpdateActionChangeVerison& cv) { - component->setVersion(cv.targetVersion); - component->waitLoadMeta(); - }, - [&component](const UpdateActionLatestRecommendedCompatable lrc) { - auto versionList = APPLICATION->metadataIndex()->get(component->getID()); - versionList->waitToLoad(); - if (versionList) { - auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); - if (recommended) { - component->setVersion(recommended->version()); - component->waitLoadMeta(); - return; - } + if (!component) { + continue; + } + auto action = component->getUpdateAction(); + auto visitor = + overload{ [](const UpdateActionNone&) { + // noop + }, + [&component, &instance](const UpdateActionChangeVersion& cv) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" + << "UpdateActionChangeVersion" << component->getID() << ":" + << component->getVersion() << "change to" << cv.targetVersion; + component->setVersion(cv.targetVersion); + component->waitLoadMeta(); + }, + [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" << component->getVersion() + << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; + auto versionList = APPLICATION->metadataIndex()->get(component->getID()); + versionList->waitToLoad(); + if (versionList) { + auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); + if (recommended) { + component->setVersion(recommended->version()); + component->waitLoadMeta(); + return; + } - auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); - if (latest) { - component->setVersion(latest->version()); - component->waitLoadMeta(); - } else { - component->addComponentProblem(ProblemSeverity::Error, - QObject::tr("No compatible version of %1 found for %2 %3") - .arg(component->getName(), lrc.parentName, lrc.version)); - } - } else { - component->addComponentProblem(ProblemSeverity::Error, - QObject::tr("No version list in metadata index for %1").arg(component->getID())); - } - }, - [this, &component](const UpdateActionRemove&) { d->m_profile->remove(component->getID()); }, - [this, &component, &addedActions](const UpdateActionImportantChanged&) { - auto linked = collectTreeLinked(component->getID()); - for (auto comp : linked) { - if (comp->isCustom()) { - continue; - } - auto compUid = comp->getID(); - auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), - [compUid](const Meta::Require& req) { return req.uid == compUid; }); - if (parentReq != component->m_cachedRequires.end()) { - auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; - if (!newVersion.isEmpty()) { - comp->setUpdateAction(UpdateAction{ UpdateActionChangeVerison{ newVersion } }); - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - addedActions = true; - } - } - }; - std::visit(visitor, *action); - component->clearUpdateAction(); + auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); + if (latest) { + component->setVersion(latest->version()); + component->waitLoadMeta(); + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No compatible version of %1 found for %2 %3") + .arg(component->getName(), lrc.parentName, lrc.version)); + } + } else { + component->addComponentProblem( + ProblemSeverity::Error, + QObject::tr("No version list in metadata index for %1").arg(component->getID())); + } + }, + [&component, &instance, &toRemove](const UpdateActionRemove&) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateActionRemove" << component->getID() << ":" << component->getVersion() << "removing"; + toRemove.append(component->getID()); + }, + [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() << "was changed from" + << ic.oldVersion << "updating linked components"; + auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion); + for (auto oldReq : oldVersion->requiredSet()) { + auto currentlyRequired = component->m_cachedRequires.find(oldReq); + if (currentlyRequired == component->m_cachedRequires.cend()) { + auto oldReqComp = componentIndex.find(oldReq.uid); + if (oldReqComp != componentIndex.cend()) { + (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} }); + addedActions = true; + } + } + } + auto linked = collectTreeLinked(component->getID()); + for (auto comp : linked) { + if (comp->isCustom()) { + continue; + } + auto compUid = comp->getID(); + auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), + [compUid](const Meta::Require& req) { return req.uid == compUid; }); + if (parentReq != component->m_cachedRequires.end()) { + auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; + if (!newVersion.isEmpty()) { + comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + addedActions = true; + } + } }; + std::visit(visitor, action); + component->clearUpdateAction(); + for (auto uid : toRemove) { + d->m_profile->remove(uid); } } } while (addedActions); @@ -637,6 +679,15 @@ void ComponentUpdateTask::finalizeComponents() reqComp->getProblemSeverity(), QObject::tr("%1, a dependency of this component, has reported issues").arg(reqComp->getName())); } + if (!req.equalsVersion.isEmpty() && req.equalsVersion != reqComp->getVersion()) { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("%1, a dependency of this component, is not the required version %2") + .arg(reqComp->getName(), req.equalsVersion)); + } else if (!req.suggests.isEmpty() && req.suggests != reqComp->getVersion()) { + component->addComponentProblem(ProblemSeverity::Warning, + QObject::tr("%1, a dependency of this component, is not the suggested version %2") + .arg(reqComp->getName(), req.suggests)); + } } } } From c4cc1cfe4f30147c85b804825048b3c5288537a8 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Thu, 27 Jun 2024 19:25:38 -0700 Subject: [PATCH 09/21] Warn about known conflicting modloaders Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/Component.cpp | 16 ++ launcher/minecraft/Component.h | 15 ++ launcher/minecraft/ComponentUpdateTask.cpp | 199 +++++++++++---------- launcher/minecraft/PackProfile.cpp | 9 +- 4 files changed, 137 insertions(+), 102 deletions(-) diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 00d3f2e42..329e6b78e 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -225,6 +225,22 @@ bool Component::isVersionChangeable() return false; } +bool Component::isKnownModloader() +{ + auto iter = KNOWN_MODLOADERS.find(m_uid); + return iter != KNOWN_MODLOADERS.cend(); +} + +QStringList Component::knownConfictingComponents() +{ + auto iter = KNOWN_MODLOADERS.find(m_uid); + if (iter != KNOWN_MODLOADERS.cend()) { + return (*iter).knownConfictingComponents; + } else { + return {}; + } +} + void Component::setImportant(bool state) { if (m_important != state) { diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 94a964182..3669638f2 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -9,6 +9,7 @@ #include "ProblemProvider.h" #include "QObjectPtr.h" #include "meta/JsonFormat.h" +#include "modplatform/ModIndex.h" class PackProfile; class LaunchProfile; @@ -43,6 +44,18 @@ using UpdateAction = std::variant; +struct ModloaderMapEntry { + ModPlatform::ModLoaderType type; + QStringList knownConfictingComponents; +}; +static const QMap KNOWN_MODLOADERS{ + { "net.neoforged", { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, + { "net.minecraftforge", { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, + { "net.fabricmc.fabric-loader", { ModPlatform::Fabric, { "net.minecraftforge", "net.neoforged", "org.quiltmc.quilt-loader" } } }, + { "org.quiltmc.quilt-loader", { ModPlatform::Quilt, { "net.minecraftforge", "net.neoforged", "net.fabricmc.fabric-loader" } } }, + { "com.mumfrey.liteloader", { ModPlatform::LiteLoader, {} } } +}; + class Component : public QObject, public ProblemProvider { Q_OBJECT public: @@ -65,6 +78,8 @@ class Component : public QObject, public ProblemProvider { bool isRemovable(); bool isCustom(); bool isVersionChangeable(); + bool isKnownModloader(); + QStringList knownConfictingComponents(); // DEPRECATED: explicit numeric order values, used for loading old non-component config. TODO: refactor and move to migration code void setOrder(int order); diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index 8001627e4..1617a8f82 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -181,8 +181,8 @@ void ComponentUpdateTask::loadComponents() } result = composeLoadResult(result, singleResult); if (loadTask) { - qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" - << "Remote loading is being run for" << component->getName(); + qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" << "Remote loading is being run for" + << component->getName(); connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); }); connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); }); connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); @@ -392,8 +392,8 @@ ComponentContainer ComponentUpdateTask::collectTreeLinked(const QString& uid) auto& componentIndex = d->m_profile->d->componentIndex; auto& instance = d->m_profile->d->m_instance; for (auto comp : components) { - qCDebug(instanceProfileResolveC) << instance->name() << "|" - << "scanning" << comp->getID() << ":" << comp->getVersion() << "for tree link"; + qCDebug(instanceProfileResolveC) << instance->name() << "|" << "scanning" << comp->getID() << ":" << comp->getVersion() + << "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()) { @@ -559,98 +559,94 @@ void ComponentUpdateTask::performUpdateActions() continue; } auto action = component->getUpdateAction(); - auto visitor = - overload{ [](const UpdateActionNone&) { - // noop - }, - [&component, &instance](const UpdateActionChangeVersion& cv) { - qCDebug(instanceProfileResolveC) << instance->name() << "|" - << "UpdateActionChangeVersion" << component->getID() << ":" - << component->getVersion() << "change to" << cv.targetVersion; - component->setVersion(cv.targetVersion); - component->waitLoadMeta(); - }, - [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { - qCDebug(instanceProfileResolveC) - << instance->name() << "|" - << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" << component->getVersion() - << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; - auto versionList = APPLICATION->metadataIndex()->get(component->getID()); - versionList->waitToLoad(); - if (versionList) { - auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); - if (recommended) { - component->setVersion(recommended->version()); - component->waitLoadMeta(); - return; - } + auto visitor = overload{ + [](const UpdateActionNone&) { + // noop + }, + [&component, &instance](const UpdateActionChangeVersion& cv) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" << "UpdateActionChangeVersion" << component->getID() << ":" + << component->getVersion() << "change to" << cv.targetVersion; + component->setVersion(cv.targetVersion); + component->waitLoadMeta(); + }, + [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" + << component->getVersion() << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; + auto versionList = APPLICATION->metadataIndex()->get(component->getID()); + versionList->waitToLoad(); + if (versionList) { + auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); + if (recommended) { + component->setVersion(recommended->version()); + component->waitLoadMeta(); + return; + } - auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); - if (latest) { - component->setVersion(latest->version()); - component->waitLoadMeta(); - } else { - component->addComponentProblem(ProblemSeverity::Error, - QObject::tr("No compatible version of %1 found for %2 %3") - .arg(component->getName(), lrc.parentName, lrc.version)); - } - } else { - component->addComponentProblem( - ProblemSeverity::Error, - QObject::tr("No version list in metadata index for %1").arg(component->getID())); - } - }, - [&component, &instance, &toRemove](const UpdateActionRemove&) { - qCDebug(instanceProfileResolveC) - << instance->name() << "|" - << "UpdateActionRemove" << component->getID() << ":" << component->getVersion() << "removing"; - toRemove.append(component->getID()); - }, - [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) { - qCDebug(instanceProfileResolveC) - << instance->name() << "|" - << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() << "was changed from" - << ic.oldVersion << "updating linked components"; - auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion); - for (auto oldReq : oldVersion->requiredSet()) { - auto currentlyRequired = component->m_cachedRequires.find(oldReq); - if (currentlyRequired == component->m_cachedRequires.cend()) { - auto oldReqComp = componentIndex.find(oldReq.uid); - if (oldReqComp != componentIndex.cend()) { - (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} }); - addedActions = true; - } - } - } - auto linked = collectTreeLinked(component->getID()); - for (auto comp : linked) { - if (comp->isCustom()) { - continue; - } - auto compUid = comp->getID(); - auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), - [compUid](const Meta::Require& req) { return req.uid == compUid; }); - if (parentReq != component->m_cachedRequires.end()) { - auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; - if (!newVersion.isEmpty()) { - comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - addedActions = true; - } - } }; + auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); + if (latest) { + component->setVersion(latest->version()); + component->waitLoadMeta(); + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No compatible version of %1 found for %2 %3") + .arg(component->getName(), lrc.parentName, lrc.version)); + } + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No version list in metadata index for %1").arg(component->getID())); + } + }, + [&component, &instance, &toRemove](const UpdateActionRemove&) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" << "UpdateActionRemove" << component->getID() << ":" + << component->getVersion() << "removing"; + toRemove.append(component->getID()); + }, + [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() + << "was changed from" << ic.oldVersion << "updating linked components"; + auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion); + for (auto oldReq : oldVersion->requiredSet()) { + auto currentlyRequired = component->m_cachedRequires.find(oldReq); + if (currentlyRequired == component->m_cachedRequires.cend()) { + auto oldReqComp = componentIndex.find(oldReq.uid); + if (oldReqComp != componentIndex.cend()) { + (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} }); + addedActions = true; + } + } + } + auto linked = collectTreeLinked(component->getID()); + for (auto comp : linked) { + if (comp->isCustom()) { + continue; + } + auto compUid = comp->getID(); + auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), + [compUid](const Meta::Require& req) { return req.uid == compUid; }); + if (parentReq != component->m_cachedRequires.end()) { + auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; + if (!newVersion.isEmpty()) { + comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + addedActions = true; + } + } + }; std::visit(visitor, action); component->clearUpdateAction(); for (auto uid : toRemove) { @@ -690,6 +686,19 @@ void ComponentUpdateTask::finalizeComponents() } } } + for (auto conflict : component->knownConfictingComponents()) { + auto found = componentIndex.find(conflict); + if (found != componentIndex.cend()) { + auto foundComp = *found; + if (foundComp ->isCustom()) { + continue; + } + component->addComponentProblem( + ProblemSeverity::Warning, + QObject::tr("%1 and %2 are known to not work together. It is recommended to remove one of them.") + .arg(component->getName(), foundComp->getName())); + } + } } } diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index debbf0fa7..c4a2dd273 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -71,11 +71,6 @@ #include "ui/dialogs/CustomMessageBox.h" -static const QMap modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge }, - { "net.minecraftforge", ModPlatform::Forge }, - { "net.fabricmc.fabric-loader", ModPlatform::Fabric }, - { "org.quiltmc.quilt-loader", ModPlatform::Quilt }, - { "com.mumfrey.liteloader", ModPlatform::LiteLoader } }; PackProfile::PackProfile(MinecraftInstance* instance) : QAbstractListModel() { @@ -1040,12 +1035,12 @@ std::optional PackProfile::getModLoaders() ModPlatform::ModLoaderTypes result; bool has_any_loader = false; - QMapIterator i(modloaderMapping); + QMapIterator i(KNOWN_MODLOADERS); while (i.hasNext()) { i.next(); if (auto c = getComponent(i.key()); c != nullptr && c->isEnabled()) { - result |= i.value(); + result |= i.value().type; has_any_loader = true; } } From 492c78a570f52d23d58b54e38c4a4785865960e6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 28 Jun 2024 13:41:07 +0300 Subject: [PATCH 10/21] format the code Signed-off-by: Trial97 --- launcher/minecraft/ComponentUpdateTask.cpp | 188 +++++++++++---------- launcher/minecraft/PackProfile.cpp | 1 - 2 files changed, 96 insertions(+), 93 deletions(-) diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index 1617a8f82..f4efba36f 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -181,8 +181,8 @@ void ComponentUpdateTask::loadComponents() } result = composeLoadResult(result, singleResult); if (loadTask) { - qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" << "Remote loading is being run for" - << component->getName(); + qCDebug(instanceProfileResolveC) << d->m_profile->d->m_instance->name() << "|" + << "Remote loading is being run for" << component->getName(); connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); }); connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); }); connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); @@ -392,8 +392,8 @@ ComponentContainer ComponentUpdateTask::collectTreeLinked(const QString& uid) auto& componentIndex = d->m_profile->d->componentIndex; auto& instance = d->m_profile->d->m_instance; for (auto comp : components) { - qCDebug(instanceProfileResolveC) << instance->name() << "|" << "scanning" << comp->getID() << ":" << comp->getVersion() - << "for tree link"; + qCDebug(instanceProfileResolveC) << instance->name() << "|" + << "scanning" << comp->getID() << ":" << comp->getVersion() << "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()) { @@ -559,94 +559,98 @@ void ComponentUpdateTask::performUpdateActions() continue; } auto action = component->getUpdateAction(); - auto visitor = overload{ - [](const UpdateActionNone&) { - // noop - }, - [&component, &instance](const UpdateActionChangeVersion& cv) { - qCDebug(instanceProfileResolveC) << instance->name() << "|" << "UpdateActionChangeVersion" << component->getID() << ":" - << component->getVersion() << "change to" << cv.targetVersion; - component->setVersion(cv.targetVersion); - component->waitLoadMeta(); - }, - [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { - qCDebug(instanceProfileResolveC) - << instance->name() << "|" << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" - << component->getVersion() << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; - auto versionList = APPLICATION->metadataIndex()->get(component->getID()); - versionList->waitToLoad(); - if (versionList) { - auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); - if (recommended) { - component->setVersion(recommended->version()); - component->waitLoadMeta(); - return; - } + auto visitor = + overload{ [](const UpdateActionNone&) { + // noop + }, + [&component, &instance](const UpdateActionChangeVersion& cv) { + qCDebug(instanceProfileResolveC) << instance->name() << "|" + << "UpdateActionChangeVersion" << component->getID() << ":" + << component->getVersion() << "change to" << cv.targetVersion; + component->setVersion(cv.targetVersion); + component->waitLoadMeta(); + }, + [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" << component->getVersion() + << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; + auto versionList = APPLICATION->metadataIndex()->get(component->getID()); + versionList->waitToLoad(); + if (versionList) { + auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); + if (recommended) { + component->setVersion(recommended->version()); + component->waitLoadMeta(); + return; + } - auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); - if (latest) { - component->setVersion(latest->version()); - component->waitLoadMeta(); - } else { - component->addComponentProblem(ProblemSeverity::Error, - QObject::tr("No compatible version of %1 found for %2 %3") - .arg(component->getName(), lrc.parentName, lrc.version)); - } - } else { - component->addComponentProblem(ProblemSeverity::Error, - QObject::tr("No version list in metadata index for %1").arg(component->getID())); - } - }, - [&component, &instance, &toRemove](const UpdateActionRemove&) { - qCDebug(instanceProfileResolveC) << instance->name() << "|" << "UpdateActionRemove" << component->getID() << ":" - << component->getVersion() << "removing"; - toRemove.append(component->getID()); - }, - [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) { - qCDebug(instanceProfileResolveC) - << instance->name() << "|" << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() - << "was changed from" << ic.oldVersion << "updating linked components"; - auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion); - for (auto oldReq : oldVersion->requiredSet()) { - auto currentlyRequired = component->m_cachedRequires.find(oldReq); - if (currentlyRequired == component->m_cachedRequires.cend()) { - auto oldReqComp = componentIndex.find(oldReq.uid); - if (oldReqComp != componentIndex.cend()) { - (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} }); - addedActions = true; - } - } - } - auto linked = collectTreeLinked(component->getID()); - for (auto comp : linked) { - if (comp->isCustom()) { - continue; - } - auto compUid = comp->getID(); - auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), - [compUid](const Meta::Require& req) { return req.uid == compUid; }); - if (parentReq != component->m_cachedRequires.end()) { - auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; - if (!newVersion.isEmpty()) { - comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ - component->getID(), - component->getName(), - component->getVersion(), - } }); - } - addedActions = true; - } - } - }; + auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); + if (latest) { + component->setVersion(latest->version()); + component->waitLoadMeta(); + } else { + component->addComponentProblem(ProblemSeverity::Error, + QObject::tr("No compatible version of %1 found for %2 %3") + .arg(component->getName(), lrc.parentName, lrc.version)); + } + } else { + component->addComponentProblem( + ProblemSeverity::Error, + QObject::tr("No version list in metadata index for %1").arg(component->getID())); + } + }, + [&component, &instance, &toRemove](const UpdateActionRemove&) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateActionRemove" << component->getID() << ":" << component->getVersion() << "removing"; + toRemove.append(component->getID()); + }, + [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) { + qCDebug(instanceProfileResolveC) + << instance->name() << "|" + << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() << "was changed from" + << ic.oldVersion << "updating linked components"; + auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion); + for (auto oldReq : oldVersion->requiredSet()) { + auto currentlyRequired = component->m_cachedRequires.find(oldReq); + if (currentlyRequired == component->m_cachedRequires.cend()) { + auto oldReqComp = componentIndex.find(oldReq.uid); + if (oldReqComp != componentIndex.cend()) { + (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} }); + addedActions = true; + } + } + } + auto linked = collectTreeLinked(component->getID()); + for (auto comp : linked) { + if (comp->isCustom()) { + continue; + } + auto compUid = comp->getID(); + auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), + [compUid](const Meta::Require& req) { return req.uid == compUid; }); + if (parentReq != component->m_cachedRequires.end()) { + auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; + if (!newVersion.isEmpty()) { + comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + } else { + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + component->getID(), + component->getName(), + component->getVersion(), + } }); + } + addedActions = true; + } + } }; std::visit(visitor, action); component->clearUpdateAction(); for (auto uid : toRemove) { @@ -690,7 +694,7 @@ void ComponentUpdateTask::finalizeComponents() auto found = componentIndex.find(conflict); if (found != componentIndex.cend()) { auto foundComp = *found; - if (foundComp ->isCustom()) { + if (foundComp->isCustom()) { continue; } component->addComponentProblem( diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index c4a2dd273..8623c500f 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -71,7 +71,6 @@ #include "ui/dialogs/CustomMessageBox.h" - PackProfile::PackProfile(MinecraftInstance* instance) : QAbstractListModel() { d.reset(new PackProfileData); From 8488d11c69ad181b4f4f303c4a8984938110b40f Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Fri, 28 Jun 2024 09:59:57 -0700 Subject: [PATCH 11/21] review suggestions + spelling Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/Component.cpp | 17 ++++++++++++++--- launcher/minecraft/Component.h | 17 ++++++----------- launcher/minecraft/ComponentUpdateTask.cpp | 21 +++++++++------------ launcher/minecraft/PackProfile.cpp | 2 +- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index 329e6b78e..df27ac071 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -38,7 +38,6 @@ #include #include -#include #include "Application.h" #include "FileSystem.h" @@ -50,6 +49,14 @@ #include +const QMap Component::KNOWN_MODLOADERS = { + { "net.neoforged", { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, + { "net.minecraftforge", { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, + { "net.fabricmc.fabric-loader", { ModPlatform::Fabric, { "net.minecraftforge", "net.neoforged", "org.quiltmc.quilt-loader" } } }, + { "org.quiltmc.quilt-loader", { ModPlatform::Quilt, { "net.minecraftforge", "net.neoforged", "net.fabricmc.fabric-loader" } } }, + { "com.mumfrey.liteloader", { ModPlatform::LiteLoader, {} } } +}; + Component::Component(PackProfile* parent, const QString& uid) { assert(parent); @@ -231,11 +238,11 @@ bool Component::isKnownModloader() return iter != KNOWN_MODLOADERS.cend(); } -QStringList Component::knownConfictingComponents() +QStringList Component::knownConflictingComponents() { auto iter = KNOWN_MODLOADERS.find(m_uid); if (iter != KNOWN_MODLOADERS.cend()) { - return (*iter).knownConfictingComponents; + return (*iter).knownConflictingComponents; } else { return {}; } @@ -276,12 +283,16 @@ void Component::addComponentProblem(ProblemSeverity severity, const QString& des m_componentProblemSeverity = severity; } m_componentProblems.append({ severity, description }); + + emit dataChanged(); } void Component::resetComponentProblems() { m_componentProblems.clear(); m_componentProblemSeverity = ProblemSeverity::None; + + emit dataChanged(); } void Component::setVersion(const QString& version) diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index 3669638f2..7ff30889f 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -23,7 +23,7 @@ struct UpdateActionChangeVersion { /// version to change to QString targetVersion; }; -struct UpdateActionLatestRecommendedCompatable { +struct UpdateActionLatestRecommendedCompatible { /// Parent uid QString parentUid; QString parentName; @@ -40,20 +40,13 @@ using UpdateActionNone = std::monostate; using UpdateAction = std::variant; struct ModloaderMapEntry { ModPlatform::ModLoaderType type; - QStringList knownConfictingComponents; -}; -static const QMap KNOWN_MODLOADERS{ - { "net.neoforged", { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, - { "net.minecraftforge", { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, - { "net.fabricmc.fabric-loader", { ModPlatform::Fabric, { "net.minecraftforge", "net.neoforged", "org.quiltmc.quilt-loader" } } }, - { "org.quiltmc.quilt-loader", { ModPlatform::Quilt, { "net.minecraftforge", "net.neoforged", "net.fabricmc.fabric-loader" } } }, - { "com.mumfrey.liteloader", { ModPlatform::LiteLoader, {} } } + QStringList knownConflictingComponents; }; class Component : public QObject, public ProblemProvider { @@ -66,6 +59,8 @@ class Component : public QObject, public ProblemProvider { virtual ~Component() {} + static const QMap KNOWN_MODLOADERS; + void applyTo(LaunchProfile* profile); bool isEnabled(); @@ -79,7 +74,7 @@ class Component : public QObject, public ProblemProvider { bool isCustom(); bool isVersionChangeable(); bool isKnownModloader(); - QStringList knownConfictingComponents(); + QStringList knownConflictingComponents(); // DEPRECATED: explicit numeric order values, used for loading old non-component config. TODO: refactor and move to migration code void setOrder(int order); diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index f4efba36f..6656a84f8 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -570,25 +570,22 @@ void ComponentUpdateTask::performUpdateActions() component->setVersion(cv.targetVersion); component->waitLoadMeta(); }, - [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) { + [&component, &instance](const UpdateActionLatestRecommendedCompatible lrc) { qCDebug(instanceProfileResolveC) << instance->name() << "|" - << "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" << component->getVersion() + << "UpdateActionLatestRecommendedCompatible" << component->getID() << ":" << component->getVersion() << "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version; auto versionList = APPLICATION->metadataIndex()->get(component->getID()); - versionList->waitToLoad(); if (versionList) { + versionList->waitToLoad(); auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); + if (!recommended) { + recommended = versionList->getLatestForParent(lrc.parentUid, lrc.version); + } if (recommended) { component->setVersion(recommended->version()); component->waitLoadMeta(); return; - } - - auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); - if (latest) { - component->setVersion(latest->version()); - component->waitLoadMeta(); } else { component->addComponentProblem(ProblemSeverity::Error, QObject::tr("No compatible version of %1 found for %2 %3") @@ -635,14 +632,14 @@ void ComponentUpdateTask::performUpdateActions() if (!newVersion.isEmpty()) { comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } }); } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatible{ component->getID(), component->getName(), component->getVersion(), } }); } } else { - comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ + comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatible{ component->getID(), component->getName(), component->getVersion(), @@ -690,7 +687,7 @@ void ComponentUpdateTask::finalizeComponents() } } } - for (auto conflict : component->knownConfictingComponents()) { + for (auto conflict : component->knownConflictingComponents()) { auto found = componentIndex.find(conflict); if (found != componentIndex.cend()) { auto foundComp = *found; diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 8623c500f..d992a18f3 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -1034,7 +1034,7 @@ std::optional PackProfile::getModLoaders() ModPlatform::ModLoaderTypes result; bool has_any_loader = false; - QMapIterator i(KNOWN_MODLOADERS); + QMapIterator i(Component::KNOWN_MODLOADERS); while (i.hasNext()) { i.next(); From c886111e18566c10ec15e5c389a3d4d1da3d2ccf Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 6 Jul 2024 09:09:54 +0300 Subject: [PATCH 12/21] format the code Signed-off-by: Trial97 --- launcher/meta/VersionList.cpp | 5 ++--- launcher/minecraft/Component.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp index 28a42d28d..8bc326839 100644 --- a/launcher/meta/VersionList.cpp +++ b/launcher/meta/VersionList.cpp @@ -254,9 +254,8 @@ void VersionList::setupAddedVersion(const int row, const Version::Ptr& version) connect(version.get(), &Version::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector() << RequiresRole); }); - connect(version.get(), &Version::timeChanged, this, [this, row]() { - emit dataChanged(index(row), index(row), { TimeRole, SortRole }); - }); + connect(version.get(), &Version::timeChanged, this, + [this, row]() { emit dataChanged(index(row), index(row), { TimeRole, SortRole }); }); connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), { TypeRole }); }); } diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index df27ac071..aeb8a398f 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -291,7 +291,7 @@ void Component::resetComponentProblems() { m_componentProblems.clear(); m_componentProblemSeverity = ProblemSeverity::None; - + emit dataChanged(); } From c666d060fc1503e307d2acbdb1443a26090e6801 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 19 Jul 2024 17:10:04 +0300 Subject: [PATCH 13/21] fix merge issue Signed-off-by: Trial97 --- launcher/minecraft/PackProfile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index ad8652488..f1d2473c2 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -1048,8 +1048,8 @@ QList PackProfile::getModLoadersList() { QList result; for (auto c : d->components) { - if (c->isEnabled() && modloaderMapping.contains(c->getID())) { - result.append(modloaderMapping[c->getID()]); + if (c->isEnabled() && Component::KNOWN_MODLOADERS.contains(c->getID())) { + result.append(Component::KNOWN_MODLOADERS[c->getID()].type); } } From 4ea7132bdfdfc53690ababf66f1123c7e0217595 Mon Sep 17 00:00:00 2001 From: Kurumi78 <30587387+Kurumi78@users.noreply.github.com> Date: Fri, 30 Aug 2024 02:08:07 -0500 Subject: [PATCH 14/21] Add webp validIconExtensions Add webp to list of valid file extensions for Icons Signed-off-by: Kurumi78 <30587387+Kurumi78@users.noreply.github.com> --- launcher/icons/IconUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/icons/IconUtils.cpp b/launcher/icons/IconUtils.cpp index 6825dd6da..87e948729 100644 --- a/launcher/icons/IconUtils.cpp +++ b/launcher/icons/IconUtils.cpp @@ -39,7 +39,7 @@ #include "FileSystem.h" namespace { -static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg" } }; +static const QStringList validIconExtensions = { { "svg", "png", "ico", "gif", "jpg", "jpeg", "webp" } }; } namespace IconUtils { From 166207753c85d7295208989cd446399f5e833c01 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 5 Sep 2024 09:36:45 +0300 Subject: [PATCH 15/21] ensure that the shortcut destination exists Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index b5c2c95cf..7f38cff04 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -921,6 +921,10 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri if (destination.isEmpty()) { destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name)); } + if (!ensureFilePathExists(destination)) { + qWarning() << "Destination path can't be created!"; + return false; + } #if defined(Q_OS_MACOS) // Create the Application QDir applicationDirectory = From c2a2e95183977bee5aebdca57fc6e342d7b9c9ed Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 7 Sep 2024 21:35:01 -0700 Subject: [PATCH 16/21] fix: Forge and neoforge conflict with quilt, not fabric twice Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- launcher/minecraft/Component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index aeb8a398f..1073ef324 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -50,8 +50,8 @@ #include const QMap Component::KNOWN_MODLOADERS = { - { "net.neoforged", { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, - { "net.minecraftforge", { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "net.fabricmc.fabric-loader" } } }, + { "net.neoforged", { ModPlatform::NeoForge, { "net.minecraftforge", "net.fabricmc.fabric-loader", "org.quiltmc.quilt-loader" } } }, + { "net.minecraftforge", { ModPlatform::Forge, { "net.neoforged", "net.fabricmc.fabric-loader", "org.quiltmc.quilt-loader" } } }, { "net.fabricmc.fabric-loader", { ModPlatform::Fabric, { "net.minecraftforge", "net.neoforged", "org.quiltmc.quilt-loader" } } }, { "org.quiltmc.quilt-loader", { ModPlatform::Quilt, { "net.minecraftforge", "net.neoforged", "net.fabricmc.fabric-loader" } } }, { "com.mumfrey.liteloader", { ModPlatform::LiteLoader, {} } } From 14fb54afd9673eebf43fad454db966e740c2c8e3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 8 Sep 2024 01:00:59 +0300 Subject: [PATCH 17/21] Fix launch when no java is loaded Signed-off-by: Trial97 --- launcher/BaseInstance.h | 4 +- launcher/CMakeLists.txt | 6 +- launcher/NullInstance.h | 2 +- launcher/RuntimeContext.h | 23 +----- launcher/launch/LaunchStep.cpp | 3 +- launcher/launch/LaunchStep.h | 7 +- launcher/launch/LaunchTask.cpp | 1 - launcher/launch/LaunchTask.h | 3 +- launcher/launch/TaskStepWrapper.cpp | 65 +++++++++++++++++ .../{steps/Update.h => TaskStepWrapper.h} | 11 +-- launcher/launch/steps/CheckJava.cpp | 3 + launcher/launch/steps/CheckJava.h | 2 +- launcher/launch/steps/QuitAfterGameStop.h | 2 +- launcher/launch/steps/Update.cpp | 73 ------------------- launcher/minecraft/LaunchProfile.cpp | 1 + launcher/minecraft/MinecraftInstance.cpp | 54 ++++++++------ launcher/minecraft/MinecraftInstance.h | 4 +- launcher/minecraft/MinecraftLoadAndCheck.cpp | 35 ++++----- launcher/minecraft/MinecraftLoadAndCheck.h | 22 ++---- launcher/minecraft/MinecraftUpdate.cpp | 63 ---------------- launcher/minecraft/MinecraftUpdate.h | 33 --------- launcher/minecraft/PackProfile.h | 6 +- launcher/minecraft/launch/AutoInstallJava.h | 1 - launcher/minecraft/launch/ClaimAccount.h | 2 +- launcher/minecraft/update/AssetUpdateTask.cpp | 3 +- launcher/minecraft/update/AssetUpdateTask.h | 2 +- launcher/minecraft/update/FMLLibrariesTask.h | 2 +- launcher/minecraft/update/FoldersTask.cpp | 2 +- launcher/minecraft/update/FoldersTask.h | 2 +- launcher/minecraft/update/LibrariesTask.h | 2 +- launcher/ui/pages/instance/VersionPage.cpp | 14 +++- 31 files changed, 163 insertions(+), 290 deletions(-) create mode 100644 launcher/launch/TaskStepWrapper.cpp rename launcher/launch/{steps/Update.h => TaskStepWrapper.h} (73%) delete mode 100644 launcher/launch/steps/Update.cpp delete mode 100644 launcher/minecraft/MinecraftUpdate.cpp delete mode 100644 launcher/minecraft/MinecraftUpdate.h diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 8c80331bc..2be28d1ec 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -181,7 +181,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this createUpdateTask() = 0; /// returns a valid launcher (task container) virtual shared_qobject_ptr createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0; @@ -215,7 +215,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this traits() const override { return {}; }; QString instanceConfigFolder() const override { return instanceRoot(); }; shared_qobject_ptr createLaunchTask(AuthSessionPtr, MinecraftTarget::Ptr) override { return nullptr; } - shared_qobject_ptr createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; } + QList createUpdateTask() override { return {}; } QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); } QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); } QMap getVariables() override { return QMap(); } diff --git a/launcher/RuntimeContext.h b/launcher/RuntimeContext.h index c57140d28..85304a5bc 100644 --- a/launcher/RuntimeContext.h +++ b/launcher/RuntimeContext.h @@ -20,13 +20,13 @@ #include #include +#include "SysInfo.h" #include "settings/SettingsObject.h" struct RuntimeContext { QString javaArchitecture; QString javaRealArchitecture; - QString javaPath; - QString system; + QString system = SysInfo::currentSystem(); QString mappedJavaRealArchitecture() const { @@ -45,8 +45,6 @@ struct RuntimeContext { { javaArchitecture = instanceSettings->get("JavaArchitecture").toString(); javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString(); - javaPath = instanceSettings->get("JavaPath").toString(); - system = currentSystem(); } QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); } @@ -68,21 +66,4 @@ struct RuntimeContext { return x; } - - static QString currentSystem() - { -#if defined(Q_OS_LINUX) - return "linux"; -#elif defined(Q_OS_MACOS) - return "osx"; -#elif defined(Q_OS_WINDOWS) - return "windows"; -#elif defined(Q_OS_FREEBSD) - return "freebsd"; -#elif defined(Q_OS_OPENBSD) - return "openbsd"; -#else - return "unknown"; -#endif - } }; diff --git a/launcher/launch/LaunchStep.cpp b/launcher/launch/LaunchStep.cpp index ebc534617..f3e9dfce0 100644 --- a/launcher/launch/LaunchStep.cpp +++ b/launcher/launch/LaunchStep.cpp @@ -16,9 +16,8 @@ #include "LaunchStep.h" #include "LaunchTask.h" -void LaunchStep::bind(LaunchTask* parent) +LaunchStep::LaunchStep(LaunchTask* parent) : Task(parent), m_parent(parent) { - m_parent = parent; connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch); connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine); connect(this, &LaunchStep::logLines, parent, &LaunchTask::onLogLines); diff --git a/launcher/launch/LaunchStep.h b/launcher/launch/LaunchStep.h index 6a28afb1f..d49d7545b 100644 --- a/launcher/launch/LaunchStep.h +++ b/launcher/launch/LaunchStep.h @@ -24,11 +24,8 @@ class LaunchTask; class LaunchStep : public Task { Q_OBJECT public: /* methods */ - explicit LaunchStep(LaunchTask* parent) : Task(nullptr), m_parent(parent) { bind(parent); }; - virtual ~LaunchStep() {}; - - private: /* methods */ - void bind(LaunchTask* parent); + explicit LaunchStep(LaunchTask* parent); + virtual ~LaunchStep() = default; signals: void logLines(QStringList lines, MessageLevel::Enum level); diff --git a/launcher/launch/LaunchTask.cpp b/launcher/launch/LaunchTask.cpp index 06a32bd28..4e4f5ead4 100644 --- a/launcher/launch/LaunchTask.cpp +++ b/launcher/launch/LaunchTask.cpp @@ -44,7 +44,6 @@ #include #include #include "MessageLevel.h" -#include "java/JavaChecker.h" #include "tasks/Task.h" void LaunchTask::init() diff --git a/launcher/launch/LaunchTask.h b/launcher/launch/LaunchTask.h index ae24b9a26..2fd8c78c7 100644 --- a/launcher/launch/LaunchTask.h +++ b/launcher/launch/LaunchTask.h @@ -41,7 +41,6 @@ #include "BaseInstance.h" #include "LaunchStep.h" #include "LogModel.h" -#include "LoggedProcess.h" #include "MessageLevel.h" class LaunchTask : public Task { @@ -55,7 +54,7 @@ class LaunchTask : public Task { public: /* methods */ static shared_qobject_ptr create(InstancePtr inst); - virtual ~LaunchTask() {}; + virtual ~LaunchTask() = default; void appendStep(shared_qobject_ptr step); void prependStep(shared_qobject_ptr step); diff --git a/launcher/launch/TaskStepWrapper.cpp b/launcher/launch/TaskStepWrapper.cpp new file mode 100644 index 000000000..136057620 --- /dev/null +++ b/launcher/launch/TaskStepWrapper.cpp @@ -0,0 +1,65 @@ +/* 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 "TaskStepWrapper.h" +#include "tasks/Task.h" + +void TaskStepWrapper::executeTask() +{ + if (m_state == Task::State::AbortedByUser) { + emitFailed(tr("Task aborted.")); + return; + } + connect(m_task.get(), &Task::finished, this, &TaskStepWrapper::updateFinished); + connect(m_task.get(), &Task::progress, this, &TaskStepWrapper::setProgress); + connect(m_task.get(), &Task::stepProgress, this, &TaskStepWrapper::propagateStepProgress); + connect(m_task.get(), &Task::status, this, &TaskStepWrapper::setStatus); + connect(m_task.get(), &Task::details, this, &TaskStepWrapper::setDetails); + emit progressReportingRequest(); +} + +void TaskStepWrapper::proceed() +{ + m_task->start(); +} + +void TaskStepWrapper::updateFinished() +{ + if (m_task->wasSuccessful()) { + m_task.reset(); + emitSucceeded(); + } else { + QString reason = tr("Instance update failed because: %1\n\n").arg(m_task->failReason()); + m_task.reset(); + emit logLine(reason, MessageLevel::Fatal); + emitFailed(reason); + } +} + +bool TaskStepWrapper::canAbort() const +{ + if (m_task) { + return m_task->canAbort(); + } + return true; +} + +bool TaskStepWrapper::abort() +{ + if (m_task && m_task->canAbort()) { + return m_task->abort(); + } + return Task::abort(); +} diff --git a/launcher/launch/steps/Update.h b/launcher/launch/TaskStepWrapper.h similarity index 73% rename from launcher/launch/steps/Update.h rename to launcher/launch/TaskStepWrapper.h index 878a43e7e..aec1b7037 100644 --- a/launcher/launch/steps/Update.h +++ b/launcher/launch/TaskStepWrapper.h @@ -21,12 +21,11 @@ #include #include -// FIXME: stupid. should be defined by the instance type? or even completely abstracted away... -class Update : public LaunchStep { +class TaskStepWrapper : public LaunchStep { Q_OBJECT public: - explicit Update(LaunchTask* parent, Net::Mode mode) : LaunchStep(parent), m_mode(mode) {}; - virtual ~Update() {}; + explicit TaskStepWrapper(LaunchTask* parent, Task::Ptr task) : LaunchStep(parent), m_task(task) {}; + virtual ~TaskStepWrapper() = default; void executeTask() override; bool canAbort() const override; @@ -38,7 +37,5 @@ class Update : public LaunchStep { void updateFinished(); private: - Task::Ptr m_updateTask; - bool m_aborted = false; - Net::Mode m_mode = Net::Mode::Offline; + Task::Ptr m_task; }; diff --git a/launcher/launch/steps/CheckJava.cpp b/launcher/launch/steps/CheckJava.cpp index 99ff62b67..55d13b58c 100644 --- a/launcher/launch/steps/CheckJava.cpp +++ b/launcher/launch/steps/CheckJava.cpp @@ -106,6 +106,7 @@ void CheckJava::executeTask() auto vendorString = instance->settings()->get("JavaVendor").toString(); printJavaInfo(verString, archString, realArchString, vendorString); } + m_parent->instance()->updateRuntimeContext(); emitSucceeded(); } @@ -124,6 +125,7 @@ void CheckJava::checkJavaFinished(const JavaChecker::Result& result) emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error); emit logLines(result.outLog.split('\n'), MessageLevel::Warning); emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher); + m_parent->instance()->updateRuntimeContext(); emitSucceeded(); return; } @@ -135,6 +137,7 @@ void CheckJava::checkJavaFinished(const JavaChecker::Result& result) instance->settings()->set("JavaRealArchitecture", result.realPlatform); instance->settings()->set("JavaVendor", result.javaVendor); instance->settings()->set("JavaSignature", m_javaSignature); + m_parent->instance()->updateRuntimeContext(); emitSucceeded(); return; } diff --git a/launcher/launch/steps/CheckJava.h b/launcher/launch/steps/CheckJava.h index 7bb1ceb7e..1c59b0053 100644 --- a/launcher/launch/steps/CheckJava.h +++ b/launcher/launch/steps/CheckJava.h @@ -23,7 +23,7 @@ class CheckJava : public LaunchStep { Q_OBJECT public: explicit CheckJava(LaunchTask* parent) : LaunchStep(parent) {}; - virtual ~CheckJava() {}; + virtual ~CheckJava() = default; virtual void executeTask(); virtual bool canAbort() const { return false; } diff --git a/launcher/launch/steps/QuitAfterGameStop.h b/launcher/launch/steps/QuitAfterGameStop.h index d4324cce6..19ca59632 100644 --- a/launcher/launch/steps/QuitAfterGameStop.h +++ b/launcher/launch/steps/QuitAfterGameStop.h @@ -24,7 +24,7 @@ class QuitAfterGameStop : public LaunchStep { Q_OBJECT public: explicit QuitAfterGameStop(LaunchTask* parent) : LaunchStep(parent) {}; - virtual ~QuitAfterGameStop() {}; + virtual ~QuitAfterGameStop() = default; virtual void executeTask(); virtual bool canAbort() const { return false; } diff --git a/launcher/launch/steps/Update.cpp b/launcher/launch/steps/Update.cpp deleted file mode 100644 index f23c0bb4b..000000000 --- a/launcher/launch/steps/Update.cpp +++ /dev/null @@ -1,73 +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 "Update.h" -#include - -void Update::executeTask() -{ - if (m_aborted) { - emitFailed(tr("Task aborted.")); - return; - } - m_updateTask.reset(m_parent->instance()->createUpdateTask(m_mode)); - if (m_updateTask) { - connect(m_updateTask.get(), &Task::finished, this, &Update::updateFinished); - connect(m_updateTask.get(), &Task::progress, this, &Update::setProgress); - connect(m_updateTask.get(), &Task::stepProgress, this, &Update::propagateStepProgress); - connect(m_updateTask.get(), &Task::status, this, &Update::setStatus); - connect(m_updateTask.get(), &Task::details, this, &Update::setDetails); - emit progressReportingRequest(); - return; - } - emitSucceeded(); -} - -void Update::proceed() -{ - m_updateTask->start(); -} - -void Update::updateFinished() -{ - if (m_updateTask->wasSuccessful()) { - m_updateTask.reset(); - emitSucceeded(); - } else { - QString reason = tr("Instance update failed because: %1\n\n").arg(m_updateTask->failReason()); - m_updateTask.reset(); - emit logLine(reason, MessageLevel::Fatal); - emitFailed(reason); - } -} - -bool Update::canAbort() const -{ - if (m_updateTask) { - return m_updateTask->canAbort(); - } - return true; -} - -bool Update::abort() -{ - m_aborted = true; - if (m_updateTask) { - if (m_updateTask->canAbort()) { - return m_updateTask->abort(); - } - } - return true; -} diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp index 468798850..c11a0f915 100644 --- a/launcher/minecraft/LaunchProfile.cpp +++ b/launcher/minecraft/LaunchProfile.cpp @@ -164,6 +164,7 @@ void LaunchProfile::applyCompatibleJavaMajors(QList& javaMajor) { m_compatibleJavaMajors.append(javaMajor); } + void LaunchProfile::applyCompatibleJavaName(QString javaName) { if (!javaName.isEmpty()) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index d861056bf..c94f3f234 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -43,6 +43,9 @@ #include "minecraft/launch/CreateGameFolders.h" #include "minecraft/launch/ExtractNatives.h" #include "minecraft/launch/PrintInstanceInfo.h" +#include "minecraft/update/AssetUpdateTask.h" +#include "minecraft/update/FMLLibrariesTask.h" +#include "minecraft/update/LibrariesTask.h" #include "settings/Setting.h" #include "settings/SettingsObject.h" @@ -53,13 +56,13 @@ #include "pathmatcher/RegexpMatcher.h" #include "launch/LaunchTask.h" +#include "launch/TaskStepWrapper.h" #include "launch/steps/CheckJava.h" #include "launch/steps/LookupServerAddress.h" #include "launch/steps/PostLaunchCommand.h" #include "launch/steps/PreLaunchCommand.h" #include "launch/steps/QuitAfterGameStop.h" #include "launch/steps/TextPrint.h" -#include "launch/steps/Update.h" #include "minecraft/launch/ClaimAccount.h" #include "minecraft/launch/LauncherPartLaunch.h" @@ -70,9 +73,6 @@ #include "java/JavaUtils.h" -#include "meta/Index.h" -#include "meta/VersionList.h" - #include "icons/IconList.h" #include "mod/ModFolderModel.h" @@ -84,7 +84,6 @@ #include "AssetsUtils.h" #include "MinecraftLoadAndCheck.h" -#include "MinecraftUpdate.h" #include "PackProfile.h" #include "minecraft/gameoptions/GameOptions.h" #include "minecraft/update/FoldersTask.h" @@ -218,6 +217,7 @@ void MinecraftInstance::loadSpecificSettings() void MinecraftInstance::updateRuntimeContext() { m_runtimeContext.updateFromInstanceSettings(m_settings); + m_components->invalidateLaunchProfile(); } QString MinecraftInstance::typeName() const @@ -1030,18 +1030,18 @@ QString MinecraftInstance::getStatusbarDescription() return description; } -Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode) +QList MinecraftInstance::createUpdateTask() { - updateRuntimeContext(); - switch (mode) { - case Net::Mode::Offline: { - return Task::Ptr(new MinecraftLoadAndCheck(this)); - } - case Net::Mode::Online: { - return Task::Ptr(new MinecraftUpdate(this)); - } - } - return nullptr; + return { + // create folders + makeShared(this), + // libraries download + makeShared(this), + // FML libraries download and copy into the instance + makeShared(this), + // assets update + makeShared(this), + }; } shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) @@ -1090,14 +1090,10 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(step); } - // if we aren't in offline mode,. - if (session->status != AuthSession::PlayableOffline) { - if (!session->demo) { - process->appendStep(makeShared(pptr, session)); - } - process->appendStep(makeShared(pptr, Net::Mode::Online)); - } else { - process->appendStep(makeShared(pptr, Net::Mode::Offline)); + // load meta + { + auto mode = session->status != AuthSession::PlayableOffline ? Net::Mode::Online : Net::Mode::Offline; + process->appendStep(makeShared(pptr, makeShared(this, mode, pptr))); } // check java @@ -1106,6 +1102,16 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(makeShared(pptr)); } + // if we aren't in offline mode,. + if (session->status != AuthSession::PlayableOffline) { + if (!session->demo) { + process->appendStep(makeShared(pptr, session)); + } + for (auto t : createUpdateTask()) { + process->appendStep(makeShared(pptr, t)); + } + } + // if there are any jar mods { process->appendStep(makeShared(pptr)); diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index ad2cda186..75e97ae45 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -104,7 +104,7 @@ class MinecraftInstance : public BaseInstance { /** Returns whether the instance, with its version, has support for demo mode. */ [[nodiscard]] bool supportsDemo() const; - void updateRuntimeContext(); + void updateRuntimeContext() override; ////// Profile management ////// std::shared_ptr getPackProfile() const; @@ -120,7 +120,7 @@ class MinecraftInstance : public BaseInstance { std::shared_ptr gameOptionsModel(); ////// Launch stuff ////// - Task::Ptr createUpdateTask(Net::Mode mode) override; + QList createUpdateTask() override; shared_qobject_ptr createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) override; QStringList extraArguments() override; QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override; diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp index 818e90cfc..655894d2a 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.cpp +++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp @@ -2,41 +2,42 @@ #include "MinecraftInstance.h" #include "PackProfile.h" -MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance* inst, QObject* parent) : Task(parent), m_inst(inst) {} +MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode, QObject* parent) + : Task(parent), m_inst(inst), m_netmode(netmode) +{} void MinecraftLoadAndCheck::executeTask() { // add offline metadata load task auto components = m_inst->getPackProfile(); - components->reload(Net::Mode::Offline); + components->reload(m_netmode); m_task = components->getCurrentTask(); if (!m_task) { emitSucceeded(); return; } - connect(m_task.get(), &Task::succeeded, this, &MinecraftLoadAndCheck::subtaskSucceeded); - connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed); - connect(m_task.get(), &Task::aborted, this, [this] { subtaskFailed(tr("Aborted")); }); - connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress); + connect(m_task.get(), &Task::succeeded, this, &MinecraftLoadAndCheck::emitSucceeded); + connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::emitFailed); + connect(m_task.get(), &Task::aborted, this, [this] { emitFailed(tr("Aborted")); }); + connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::setProgress); connect(m_task.get(), &Task::stepProgress, this, &MinecraftLoadAndCheck::propagateStepProgress); connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus); + connect(m_task.get(), &Task::details, this, &MinecraftLoadAndCheck::setDetails); } -void MinecraftLoadAndCheck::subtaskSucceeded() +bool MinecraftLoadAndCheck::canAbort() const { - if (isFinished()) { - qCritical() << "MinecraftUpdate: Subtask" << sender() << "succeeded, but work was already done!"; - return; + if (m_task) { + return m_task->canAbort(); } - emitSucceeded(); + return true; } -void MinecraftLoadAndCheck::subtaskFailed(QString error) +bool MinecraftLoadAndCheck::abort() { - if (isFinished()) { - qCritical() << "MinecraftUpdate: Subtask" << sender() << "failed, but work was already done!"; - return; + if (m_task && m_task->canAbort()) { + return m_task->abort(); } - emitFailed(error); -} + return Task::abort(); +} \ No newline at end of file diff --git a/launcher/minecraft/MinecraftLoadAndCheck.h b/launcher/minecraft/MinecraftLoadAndCheck.h index 09edaf909..72e9e0caa 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.h +++ b/launcher/minecraft/MinecraftLoadAndCheck.h @@ -15,32 +15,24 @@ #pragma once -#include -#include -#include - -#include +#include "net/Mode.h" #include "tasks/Task.h" -#include "QObjectPtr.h" - -class MinecraftVersion; class MinecraftInstance; class MinecraftLoadAndCheck : public Task { Q_OBJECT public: - explicit MinecraftLoadAndCheck(MinecraftInstance* inst, QObject* parent = 0); - virtual ~MinecraftLoadAndCheck() {}; + explicit MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode, QObject* parent = nullptr); + virtual ~MinecraftLoadAndCheck() = default; void executeTask() override; - private slots: - void subtaskSucceeded(); - void subtaskFailed(QString error); + bool canAbort() const override; + public slots: + bool abort() override; private: MinecraftInstance* m_inst = nullptr; Task::Ptr m_task; - QString m_preFailure; - QString m_fail_reason; + Net::Mode m_netmode; }; diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp deleted file mode 100644 index b63430aa8..000000000 --- a/launcher/minecraft/MinecraftUpdate.cpp +++ /dev/null @@ -1,63 +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 "MinecraftUpdate.h" -#include "MinecraftInstance.h" - -#include "minecraft/PackProfile.h" - -#include "tasks/SequentialTask.h" -#include "update/AssetUpdateTask.h" -#include "update/FMLLibrariesTask.h" -#include "update/FoldersTask.h" -#include "update/LibrariesTask.h" - -MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : SequentialTask(parent), m_inst(inst) {} - -void MinecraftUpdate::executeTask() -{ - m_queue.clear(); - // create folders - { - addTask(makeShared(m_inst)); - } - - // add metadata update task if necessary - { - auto components = m_inst->getPackProfile(); - components->reload(Net::Mode::Online); - auto task = components->getCurrentTask(); - if (task) { - addTask(task); - } - } - - // libraries download - { - addTask(makeShared(m_inst)); - } - - // FML libraries download and copy into the instance - { - addTask(makeShared(m_inst)); - } - - // assets update - { - addTask(makeShared(m_inst)); - } - - SequentialTask::executeTask(); -} diff --git a/launcher/minecraft/MinecraftUpdate.h b/launcher/minecraft/MinecraftUpdate.h deleted file mode 100644 index 456a13518..000000000 --- a/launcher/minecraft/MinecraftUpdate.h +++ /dev/null @@ -1,33 +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 "tasks/SequentialTask.h" - -class MinecraftInstance; - -// this needs to be a task because components->reload does stuff that may block -class MinecraftUpdate : public SequentialTask { - Q_OBJECT - public: - explicit MinecraftUpdate(MinecraftInstance* inst, QObject* parent = 0); - virtual ~MinecraftUpdate() = default; - - void executeTask() override; - - private: - MinecraftInstance* m_inst = nullptr; -}; diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h index 9b6710cc3..b2de26ea0 100644 --- a/launcher/minecraft/PackProfile.h +++ b/launcher/minecraft/PackProfile.h @@ -148,13 +148,13 @@ class PackProfile : public QAbstractListModel { std::optional getSupportedModLoaders(); QList getModLoadersList(); + /// apply the component patches. Catches all the errors and returns true/false for success/failure + void invalidateLaunchProfile(); + private: void scheduleSave(); bool saveIsScheduled() const; - /// apply the component patches. Catches all the errors and returns true/false for success/failure - void invalidateLaunchProfile(); - /// insert component so that its index is ideally the specified one (returns real index) void insertComponent(size_t index, ComponentPtr component); diff --git a/launcher/minecraft/launch/AutoInstallJava.h b/launcher/minecraft/launch/AutoInstallJava.h index 7e4efc50c..cbfcf5ee7 100644 --- a/launcher/minecraft/launch/AutoInstallJava.h +++ b/launcher/minecraft/launch/AutoInstallJava.h @@ -37,7 +37,6 @@ #include #include -#include "java/JavaMetadata.h" #include "meta/Version.h" #include "minecraft/MinecraftInstance.h" #include "tasks/Task.h" diff --git a/launcher/minecraft/launch/ClaimAccount.h b/launcher/minecraft/launch/ClaimAccount.h index 357a4d4c5..561f0e848 100644 --- a/launcher/minecraft/launch/ClaimAccount.h +++ b/launcher/minecraft/launch/ClaimAccount.h @@ -22,7 +22,7 @@ class ClaimAccount : public LaunchStep { Q_OBJECT public: explicit ClaimAccount(LaunchTask* parent, AuthSessionPtr session); - virtual ~ClaimAccount() {}; + virtual ~ClaimAccount() = default; void executeTask() override; void finalize() override; diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp index 8add02d84..acdddc833 100644 --- a/launcher/minecraft/update/AssetUpdateTask.cpp +++ b/launcher/minecraft/update/AssetUpdateTask.cpp @@ -1,5 +1,6 @@ #include "AssetUpdateTask.h" +#include "launch/LaunchStep.h" #include "minecraft/AssetsUtils.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" @@ -14,8 +15,6 @@ AssetUpdateTask::AssetUpdateTask(MinecraftInstance* inst) m_inst = inst; } -AssetUpdateTask::~AssetUpdateTask() {} - void AssetUpdateTask::executeTask() { setStatus(tr("Updating assets index...")); diff --git a/launcher/minecraft/update/AssetUpdateTask.h b/launcher/minecraft/update/AssetUpdateTask.h index 6f053a54a..88fac0ac5 100644 --- a/launcher/minecraft/update/AssetUpdateTask.h +++ b/launcher/minecraft/update/AssetUpdateTask.h @@ -7,7 +7,7 @@ class AssetUpdateTask : public Task { Q_OBJECT public: AssetUpdateTask(MinecraftInstance* inst); - virtual ~AssetUpdateTask(); + virtual ~AssetUpdateTask() = default; void executeTask() override; diff --git a/launcher/minecraft/update/FMLLibrariesTask.h b/launcher/minecraft/update/FMLLibrariesTask.h index 32712d239..4fe2648e8 100644 --- a/launcher/minecraft/update/FMLLibrariesTask.h +++ b/launcher/minecraft/update/FMLLibrariesTask.h @@ -9,7 +9,7 @@ class FMLLibrariesTask : public Task { Q_OBJECT public: FMLLibrariesTask(MinecraftInstance* inst); - virtual ~FMLLibrariesTask() {}; + virtual ~FMLLibrariesTask() = default; void executeTask() override; diff --git a/launcher/minecraft/update/FoldersTask.cpp b/launcher/minecraft/update/FoldersTask.cpp index c74e8d2ef..7d6fc4394 100644 --- a/launcher/minecraft/update/FoldersTask.cpp +++ b/launcher/minecraft/update/FoldersTask.cpp @@ -37,7 +37,7 @@ #include #include "minecraft/MinecraftInstance.h" -FoldersTask::FoldersTask(MinecraftInstance* inst) : Task() +FoldersTask::FoldersTask(MinecraftInstance* inst) { m_inst = inst; } diff --git a/launcher/minecraft/update/FoldersTask.h b/launcher/minecraft/update/FoldersTask.h index be4e33eb7..7df7ef81d 100644 --- a/launcher/minecraft/update/FoldersTask.h +++ b/launcher/minecraft/update/FoldersTask.h @@ -7,7 +7,7 @@ class FoldersTask : public Task { Q_OBJECT public: FoldersTask(MinecraftInstance* inst); - virtual ~FoldersTask() {}; + virtual ~FoldersTask() = default; void executeTask() override; diff --git a/launcher/minecraft/update/LibrariesTask.h b/launcher/minecraft/update/LibrariesTask.h index 441191154..838f9d9b4 100644 --- a/launcher/minecraft/update/LibrariesTask.h +++ b/launcher/minecraft/update/LibrariesTask.h @@ -7,7 +7,7 @@ class LibrariesTask : public Task { Q_OBJECT public: LibrariesTask(MinecraftInstance* inst); - virtual ~LibrariesTask() {}; + virtual ~LibrariesTask() = default; void executeTask() override; diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index c55d32efb..02bb08cab 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -50,7 +50,9 @@ #include #include +#include "QObjectPtr.h" #include "VersionPage.h" +#include "tasks/SequentialTask.h" #include "ui/dialogs/InstallLoaderDialog.h" #include "ui_VersionPage.h" @@ -415,14 +417,18 @@ void VersionPage::on_actionDownload_All_triggered() return; } - auto updateTask = m_inst->createUpdateTask(Net::Mode::Online); - if (!updateTask) { + auto updateTasks = m_inst->createUpdateTask(); + if (updateTasks.isEmpty()) { return; } + auto task = makeShared(this); + for (auto t : updateTasks) { + task->addTask(t); + } ProgressDialog tDialog(this); - connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError); + connect(task.get(), &Task::failed, this, &VersionPage::onGameUpdateError); // FIXME: unused return value - tDialog.execWithTask(updateTask.get()); + tDialog.execWithTask(task.get()); updateButtons(); m_container->refreshContainer(); } From 7fbf0d3bf3c3821916119a5303d6bc302f954580 Mon Sep 17 00:00:00 2001 From: QazCetelic Date: Mon, 9 Sep 2024 15:40:31 +0200 Subject: [PATCH 18/21] Sort files chronologically in descending order Signed-off-by: Qaz --- launcher/ui/pages/instance/ScreenshotsPage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index c3f955733..9c7df9d09 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -242,6 +242,10 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget* parent) : QMainWindow(pa m_model->setReadOnly(false); m_model->setNameFilters({ "*.png" }); m_model->setNameFilterDisables(false); + // Sorts by modified date instead of creation date because that column is not available and would require subclassing, this should work + // considering screenshots aren't modified after creation. + constexpr int file_modified_column_index = 3; + m_model->sort(file_modified_column_index, Qt::DescendingOrder); m_folder = path; m_valid = FS::ensureFolderPathExists(m_folder); From e2ef280da98facec04a0e2b3d0f0e8b8317db043 Mon Sep 17 00:00:00 2001 From: QazCetelic Date: Mon, 9 Sep 2024 16:24:40 +0200 Subject: [PATCH 19/21] DCO Remediation Commit for QazCetelic I, QazCetelic , hereby add my Signed-off-by to this commit: 7fbf0d3bf3c3821916119a5303d6bc302f954580 Signed-off-by: QazCetelic --- launcher/ui/pages/instance/ScreenshotsPage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index 9c7df9d09..b619a07b8 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -246,6 +246,7 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget* parent) : QMainWindow(pa // considering screenshots aren't modified after creation. constexpr int file_modified_column_index = 3; m_model->sort(file_modified_column_index, Qt::DescendingOrder); + m_folder = path; m_valid = FS::ensureFolderPathExists(m_folder); From 7e49fa04269b23c8cb4048a6a036aaf6d5e5bf8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:05:56 +0000 Subject: [PATCH 20/21] chore(deps): update determinatesystems/update-flake-lock action to v24 --- .github/workflows/update-flake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index e1ab2e86e..ecc38ff28 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - - uses: DeterminateSystems/update-flake-lock@v23 + - uses: DeterminateSystems/update-flake-lock@v24 with: commit-msg: "chore(nix): update lockfile" pr-title: "chore(nix): update lockfile" From c85294af9debc472446585b7851f41596fbcc0be Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 12 Sep 2024 17:57:57 +0300 Subject: [PATCH 21/21] Improve wizzard page Signed-off-by: Trial97 --- launcher/Application.cpp | 35 +++++-- launcher/CMakeLists.txt | 6 ++ .../ui/setupwizard/AutoJavaWizardPage.cpp | 33 +++++++ launcher/ui/setupwizard/AutoJavaWizardPage.h | 22 +++++ launcher/ui/setupwizard/AutoJavaWizardPage.ui | 93 +++++++++++++++++++ launcher/ui/setupwizard/JavaWizardPage.cpp | 4 +- launcher/ui/setupwizard/JavaWizardPage.h | 2 +- launcher/ui/setupwizard/LoginWizardPage.cpp | 45 +++++++++ launcher/ui/setupwizard/LoginWizardPage.h | 24 +++++ launcher/ui/setupwizard/LoginWizardPage.ui | 74 +++++++++++++++ launcher/ui/widgets/JavaSettingsWidget.cpp | 77 ++++++++++----- launcher/ui/widgets/JavaSettingsWidget.h | 8 +- 12 files changed, 384 insertions(+), 39 deletions(-) create mode 100644 launcher/ui/setupwizard/AutoJavaWizardPage.cpp create mode 100644 launcher/ui/setupwizard/AutoJavaWizardPage.h create mode 100644 launcher/ui/setupwizard/AutoJavaWizardPage.ui create mode 100644 launcher/ui/setupwizard/LoginWizardPage.cpp create mode 100644 launcher/ui/setupwizard/LoginWizardPage.h create mode 100644 launcher/ui/setupwizard/LoginWizardPage.ui diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 9cd0445e6..35eb6e91e 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -67,8 +67,10 @@ #include "ui/pages/global/MinecraftPage.h" #include "ui/pages/global/ProxyPage.h" +#include "ui/setupwizard/AutoJavaWizardPage.h" #include "ui/setupwizard/JavaWizardPage.h" #include "ui/setupwizard/LanguageWizardPage.h" +#include "ui/setupwizard/LoginWizardPage.h" #include "ui/setupwizard/PasteWizardPage.h" #include "ui/setupwizard/SetupWizard.h" #include "ui/setupwizard/ThemeWizardPage.h" @@ -650,6 +652,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) auto defaultEnableAutoJava = m_settings->get("JavaPath").toString().isEmpty(); m_settings->registerSetting("AutomaticJavaSwitch", defaultEnableAutoJava); m_settings->registerSetting("AutomaticJavaDownload", defaultEnableAutoJava); + m_settings->registerSetting("UserAskedAboutAutomaticJavaDownload", false); // Legacy settings m_settings->registerSetting("OnlineFixes", false); @@ -1077,13 +1080,15 @@ bool Application::createSetupWizard() } return false; }(); + bool askjava = BuildConfig.JAVA_DOWNLOADER_ENABLED && !javaRequired && !m_settings->get("AutomaticJavaDownload").toBool() && + !m_settings->get("AutomaticJavaSwitch").toBool() && !m_settings->get("UserAskedAboutAutomaticJavaDownload").toBool(); bool languageRequired = settings()->get("Language").toString().isEmpty(); bool pasteInterventionRequired = settings()->get("PastebinURL") != ""; bool validWidgets = m_themeManager->isValidApplicationTheme(settings()->get("ApplicationTheme").toString()); bool validIcons = m_themeManager->isValidIconTheme(settings()->get("IconTheme").toString()); + bool login = !m_accounts->anyAccountIsValid() && capabilities() & Application::SupportsMSA; bool themeInterventionRequired = !validWidgets || !validIcons; - bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired; - + bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired || askjava || login; if (wizardRequired) { // set default theme after going into theme wizard if (!validIcons) @@ -1100,6 +1105,8 @@ bool Application::createSetupWizard() if (javaRequired) { m_setupWizard->addPage(new JavaWizardPage(m_setupWizard)); + } else if (askjava) { + m_setupWizard->addPage(new AutoJavaWizardPage(m_setupWizard)); } if (pasteInterventionRequired) { @@ -1110,11 +1117,14 @@ bool Application::createSetupWizard() m_setupWizard->addPage(new ThemeWizardPage(m_setupWizard)); } + if (login) { + m_setupWizard->addPage(new LoginWizardPage(m_setupWizard)); + } connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished); m_setupWizard->show(); - return true; } - return false; + + return wizardRequired || login; } bool Application::updaterEnabled() @@ -1259,16 +1269,23 @@ Application::~Application() void Application::messageReceived(const QByteArray& message) { - if (status() != Initialized) { - qDebug() << "Received message" << message << "while still initializing. It will be ignored."; - return; - } - ApplicationMessage received; received.parse(message); auto& command = received.command; + if (status() != Initialized) { + bool isLoginAtempt = false; + if (command == "import") { + QString url = received.args["url"]; + isLoginAtempt = !url.isEmpty() && normalizeImportUrl(url).scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME; + } + if (!isLoginAtempt) { + qDebug() << "Received message" << message << "while still initializing. It will be ignored."; + return; + } + } + if (command == "activate") { showMainWindow(); } else if (command == "import") { diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index a65d53d06..975946740 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -842,6 +842,10 @@ SET(LAUNCHER_SOURCES ui/setupwizard/PasteWizardPage.h ui/setupwizard/ThemeWizardPage.cpp ui/setupwizard/ThemeWizardPage.h + ui/setupwizard/AutoJavaWizardPage.cpp + ui/setupwizard/AutoJavaWizardPage.h + ui/setupwizard/LoginWizardPage.cpp + ui/setupwizard/LoginWizardPage.h # GUI - themes ui/themes/FusionTheme.cpp @@ -1154,6 +1158,8 @@ endif() qt_wrap_ui(LAUNCHER_UI ui/MainWindow.ui ui/setupwizard/PasteWizardPage.ui + ui/setupwizard/AutoJavaWizardPage.ui + ui/setupwizard/LoginWizardPage.ui ui/setupwizard/ThemeWizardPage.ui ui/pages/global/AccountListPage.ui ui/pages/global/JavaPage.ui diff --git a/launcher/ui/setupwizard/AutoJavaWizardPage.cpp b/launcher/ui/setupwizard/AutoJavaWizardPage.cpp new file mode 100644 index 000000000..fd173e71d --- /dev/null +++ b/launcher/ui/setupwizard/AutoJavaWizardPage.cpp @@ -0,0 +1,33 @@ +#include "AutoJavaWizardPage.h" +#include "ui_AutoJavaWizardPage.h" + +#include "Application.h" + +AutoJavaWizardPage::AutoJavaWizardPage(QWidget* parent) : BaseWizardPage(parent), ui(new Ui::AutoJavaWizardPage) +{ + ui->setupUi(this); +} + +AutoJavaWizardPage::~AutoJavaWizardPage() +{ + delete ui; +} + +void AutoJavaWizardPage::initializePage() {} + +bool AutoJavaWizardPage::validatePage() +{ + auto s = APPLICATION->settings(); + + if (!ui->previousSettingsRadioButton->isChecked()) { + s->set("AutomaticJavaSwitch", true); + s->set("AutomaticJavaDownload", true); + } + s->set("UserAskedAboutAutomaticJavaDownload", true); + return true; +} + +void AutoJavaWizardPage::retranslate() +{ + ui->retranslateUi(this); +} diff --git a/launcher/ui/setupwizard/AutoJavaWizardPage.h b/launcher/ui/setupwizard/AutoJavaWizardPage.h new file mode 100644 index 000000000..fcdf5bdf1 --- /dev/null +++ b/launcher/ui/setupwizard/AutoJavaWizardPage.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include "BaseWizardPage.h" + +namespace Ui { +class AutoJavaWizardPage; +} + +class AutoJavaWizardPage : public BaseWizardPage { + Q_OBJECT + + public: + explicit AutoJavaWizardPage(QWidget* parent = nullptr); + ~AutoJavaWizardPage(); + + void initializePage() override; + bool validatePage() override; + void retranslate() override; + + private: + Ui::AutoJavaWizardPage* ui; +}; diff --git a/launcher/ui/setupwizard/AutoJavaWizardPage.ui b/launcher/ui/setupwizard/AutoJavaWizardPage.ui new file mode 100644 index 000000000..bd72cf695 --- /dev/null +++ b/launcher/ui/setupwizard/AutoJavaWizardPage.ui @@ -0,0 +1,93 @@ + + + AutoJavaWizardPage + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + <html><head/><body><p><span style=" font-size:14pt; font-weight:600;">New Feature Alert!</span></p></body></html> + + + Qt::RichText + + + true + + + + + + + We've added a feature to automatically download the correct Java version for each version of Minecraft(this can be changed in the Java Settings). Would you like to enable or disable this feature? + + + true + + + + + + + Qt::Horizontal + + + + + + + Enable Auto-Download + + + true + + + buttonGroup + + + + + + + Disable Auto-Download + + + false + + + buttonGroup + + + + + + + Qt::Vertical + + + + 20 + 156 + + + + + + + + + + + + diff --git a/launcher/ui/setupwizard/JavaWizardPage.cpp b/launcher/ui/setupwizard/JavaWizardPage.cpp index a47cebcaa..47718d6da 100644 --- a/launcher/ui/setupwizard/JavaWizardPage.cpp +++ b/launcher/ui/setupwizard/JavaWizardPage.cpp @@ -55,6 +55,7 @@ bool JavaWizardPage::validatePage() auto result = m_java_widget->validate(); settings->set("AutomaticJavaSwitch", m_java_widget->autoDetectJava()); settings->set("AutomaticJavaDownload", m_java_widget->autoDownloadJava()); + settings->set("UserAskedAboutAutomaticJavaDownload", true); switch (result) { default: case JavaSettingsWidget::ValidationStatus::Bad: { @@ -82,7 +83,6 @@ void JavaWizardPage::retranslate() { setTitle(tr("Java")); setSubTitle( - tr("You do not have a working Java set up yet or it went missing.\n" - "Please select one of the following or browse for a Java executable.")); + tr("Please select how much memory to allocate to instances and if Prism Launcher should manage java automatically or manually.")); m_java_widget->retranslate(); } diff --git a/launcher/ui/setupwizard/JavaWizardPage.h b/launcher/ui/setupwizard/JavaWizardPage.h index dde765f27..9bf9cfa2b 100644 --- a/launcher/ui/setupwizard/JavaWizardPage.h +++ b/launcher/ui/setupwizard/JavaWizardPage.h @@ -9,7 +9,7 @@ class JavaWizardPage : public BaseWizardPage { public: explicit JavaWizardPage(QWidget* parent = Q_NULLPTR); - virtual ~JavaWizardPage() {}; + virtual ~JavaWizardPage() = default; bool wantsRefreshButton() override; void refresh() override; diff --git a/launcher/ui/setupwizard/LoginWizardPage.cpp b/launcher/ui/setupwizard/LoginWizardPage.cpp new file mode 100644 index 000000000..6be24a2f7 --- /dev/null +++ b/launcher/ui/setupwizard/LoginWizardPage.cpp @@ -0,0 +1,45 @@ +#include "LoginWizardPage.h" +#include "minecraft/auth/AccountList.h" +#include "ui/dialogs/MSALoginDialog.h" +#include "ui_LoginWizardPage.h" + +#include "Application.h" + +LoginWizardPage::LoginWizardPage(QWidget* parent) : BaseWizardPage(parent), ui(new Ui::LoginWizardPage) +{ + ui->setupUi(this); +} + +LoginWizardPage::~LoginWizardPage() +{ + delete ui; +} + +void LoginWizardPage::initializePage() {} + +bool LoginWizardPage::validatePage() +{ + return true; +} + +void LoginWizardPage::retranslate() +{ + ui->retranslateUi(this); +} + +void LoginWizardPage::on_pushButton_clicked() +{ + wizard()->hide(); + auto account = MSALoginDialog::newAccount(nullptr); + wizard()->show(); + if (account) { + APPLICATION->accounts()->addAccount(account); + APPLICATION->accounts()->setDefaultAccount(account); + } + + if (wizard()->currentId() == wizard()->pageIds().last()) { + wizard()->accept(); + } else { + wizard()->next(); + } +} diff --git a/launcher/ui/setupwizard/LoginWizardPage.h b/launcher/ui/setupwizard/LoginWizardPage.h new file mode 100644 index 000000000..af71fc183 --- /dev/null +++ b/launcher/ui/setupwizard/LoginWizardPage.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include "BaseWizardPage.h" + +namespace Ui { +class LoginWizardPage; +} + +class LoginWizardPage : public BaseWizardPage { + Q_OBJECT + + public: + explicit LoginWizardPage(QWidget* parent = nullptr); + ~LoginWizardPage(); + + void initializePage() override; + bool validatePage() override; + void retranslate() override; + private slots: + void on_pushButton_clicked(); + + private: + Ui::LoginWizardPage* ui; +}; diff --git a/launcher/ui/setupwizard/LoginWizardPage.ui b/launcher/ui/setupwizard/LoginWizardPage.ui new file mode 100644 index 000000000..191316c4e --- /dev/null +++ b/launcher/ui/setupwizard/LoginWizardPage.ui @@ -0,0 +1,74 @@ + + + LoginWizardPage + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + <html><head/><body><p><span style=" font-size:14pt; font-weight:600;">Add Microsoft account</span></p></body></html> + + + Qt::RichText + + + true + + + + + + + In order to play Minecraft, you must have at least one Microsoft account logged in. Do you want to log in now? + + + true + + + + + + + Qt::Horizontal + + + + + + + Add Microsoft account + + + + + + + Qt::Vertical + + + + 20 + 156 + + + + + + + + + + + + diff --git a/launcher/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp index 8e2d94556..2b270c482 100644 --- a/launcher/ui/widgets/JavaSettingsWidget.cpp +++ b/launcher/ui/widgets/JavaSettingsWidget.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -34,11 +36,13 @@ JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent) goodIcon = APPLICATION->getThemedIcon("status-good"); yellowIcon = APPLICATION->getThemedIcon("status-yellow"); badIcon = APPLICATION->getThemedIcon("status-bad"); + m_memoryTimer = new QTimer(this); setupUi(); - connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int))); - connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int))); - connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int))); + connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int))); + connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int))); + connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int))); + connect(m_memoryTimer, &QTimer::timeout, this, &JavaSettingsWidget::memoryValueChanged); connect(m_versionWidget, &VersionSelectWidget::selectedVersionChanged, this, &JavaSettingsWidget::javaVersionSelected); connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaSettingsWidget::on_javaBrowseBtn_clicked); connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaSettingsWidget::javaPathEdited); @@ -55,7 +59,6 @@ void JavaSettingsWidget::setupUi() m_verticalLayout->setObjectName(QStringLiteral("verticalLayout")); m_versionWidget = new VersionSelectWidget(this); - m_verticalLayout->addWidget(m_versionWidget); m_horizontalLayout = new QHBoxLayout(); m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout")); @@ -73,8 +76,6 @@ void JavaSettingsWidget::setupUi() m_javaStatusBtn->setIcon(yellowIcon); m_horizontalLayout->addWidget(m_javaStatusBtn); - m_verticalLayout->addLayout(m_horizontalLayout); - m_memoryGroupBox = new QGroupBox(this); m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox")); m_gridLayout_2 = new QGridLayout(m_memoryGroupBox); @@ -136,8 +137,6 @@ void JavaSettingsWidget::setupUi() m_horizontalBtnLayout->addWidget(m_javaDownloadBtn); } - m_verticalLayout->addLayout(m_horizontalBtnLayout); - m_autoJavaGroupBox = new QGroupBox(this); m_autoJavaGroupBox->setObjectName(QStringLiteral("autoJavaGroupBox")); m_veriticalJavaLayout = new QVBoxLayout(m_autoJavaGroupBox); @@ -145,21 +144,42 @@ void JavaSettingsWidget::setupUi() m_autodetectJavaCheckBox = new QCheckBox(m_autoJavaGroupBox); m_autodetectJavaCheckBox->setObjectName("autodetectJavaCheckBox"); + m_autodetectJavaCheckBox->setChecked(true); m_veriticalJavaLayout->addWidget(m_autodetectJavaCheckBox); if (BuildConfig.JAVA_DOWNLOADER_ENABLED) { m_autodownloadCheckBox = new QCheckBox(m_autoJavaGroupBox); m_autodownloadCheckBox->setObjectName("autodownloadCheckBox"); - m_autodownloadCheckBox->setEnabled(false); + m_autodownloadCheckBox->setEnabled(m_autodetectJavaCheckBox->isChecked()); m_veriticalJavaLayout->addWidget(m_autodownloadCheckBox); connect(m_autodetectJavaCheckBox, &QCheckBox::stateChanged, this, [this] { m_autodownloadCheckBox->setEnabled(m_autodetectJavaCheckBox->isChecked()); if (!m_autodetectJavaCheckBox->isChecked()) m_autodownloadCheckBox->setChecked(false); }); + + connect(m_autodownloadCheckBox, &QCheckBox::stateChanged, this, [this] { + auto isChecked = m_autodownloadCheckBox->isChecked(); + m_versionWidget->setVisible(!isChecked); + m_javaStatusBtn->setVisible(!isChecked); + m_javaBrowseBtn->setVisible(!isChecked); + m_javaPathTextBox->setVisible(!isChecked); + m_javaDownloadBtn->setVisible(!isChecked); + if (!isChecked) { + m_verticalLayout->removeItem(m_verticalSpacer); + } else { + m_verticalLayout->addSpacerItem(m_verticalSpacer); + } + }); } m_verticalLayout->addWidget(m_autoJavaGroupBox); + m_verticalLayout->addLayout(m_horizontalBtnLayout); + + m_verticalLayout->addWidget(m_versionWidget); + m_verticalLayout->addLayout(m_horizontalLayout); + m_verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + retranslate(); } @@ -177,23 +197,16 @@ void JavaSettingsWidget::initialize() m_maxMemSpinBox->setValue(observedMaxMemory); m_permGenSpinBox->setValue(observedPermGenMemory); updateThresholds(); - if (BuildConfig.JAVA_DOWNLOADER_ENABLED) { - auto button = - CustomMessageBox::selectable(this, tr("Automatic Java Download"), - tr("%1 can automatically download the correct Java version for each version of Minecraft..\n" - "Do you want to enable Java auto-download?\n") - .arg(BuildConfig.LAUNCHER_DISPLAYNAME), - QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) - ->exec(); - auto checked = button == QMessageBox::Yes; - m_autodetectJavaCheckBox->setChecked(checked); - m_autodownloadCheckBox->setChecked(checked); + m_autodownloadCheckBox->setChecked(true); } } void JavaSettingsWidget::refresh() { + if (BuildConfig.JAVA_DOWNLOADER_ENABLED && m_autodownloadCheckBox->isChecked()) { + return; + } if (JavaUtils::getJavaCheckPath().isEmpty()) { JavaCommon::javaCheckNotFound(this); return; @@ -297,20 +310,21 @@ int JavaSettingsWidget::permGenSize() const return m_permGenSpinBox->value(); } -void JavaSettingsWidget::memoryValueChanged(int) +void JavaSettingsWidget::memoryValueChanged() { bool actuallyChanged = false; unsigned int min = m_minMemSpinBox->value(); unsigned int max = m_maxMemSpinBox->value(); unsigned int permgen = m_permGenSpinBox->value(); - QObject* obj = sender(); - if (obj == m_minMemSpinBox && min != observedMinMemory) { + if (min != observedMinMemory) { observedMinMemory = min; actuallyChanged = true; - } else if (obj == m_maxMemSpinBox && max != observedMaxMemory) { + } + if (max != observedMaxMemory) { observedMaxMemory = max; actuallyChanged = true; - } else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory) { + } + if (permgen != observedPermGenMemory) { observedPermGenMemory = permgen; actuallyChanged = true; } @@ -505,6 +519,9 @@ void JavaSettingsWidget::updateThresholds() } else if (observedMaxMemory < observedMinMemory) { iconName = "status-yellow"; m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value")); + } else if (BuildConfig.JAVA_DOWNLOADER_ENABLED && m_autodownloadCheckBox->isChecked()) { + iconName = "status-good"; + m_labelMaxMemIcon->setToolTip(""); } else if (observedMaxMemory > 2048 && !m_result.is_64bit) { iconName = "status-bad"; m_labelMaxMemIcon->setToolTip(tr("You are exceeding the maximum allocation supported by 32-bit installations of Java.")); @@ -530,3 +547,13 @@ bool JavaSettingsWidget::autoDetectJava() const { return m_autodetectJavaCheckBox->isChecked(); } + +void JavaSettingsWidget::onSpinBoxValueChanged(int) +{ + m_memoryTimer->start(500); +} + +JavaSettingsWidget::~JavaSettingsWidget() +{ + delete m_verticalSpacer; +}; \ No newline at end of file diff --git a/launcher/ui/widgets/JavaSettingsWidget.h b/launcher/ui/widgets/JavaSettingsWidget.h index 622c473fe..35be48478 100644 --- a/launcher/ui/widgets/JavaSettingsWidget.h +++ b/launcher/ui/widgets/JavaSettingsWidget.h @@ -17,6 +17,7 @@ class QGroupBox; class QGridLayout; class QLabel; class QToolButton; +class QSpacerItem; /** * This is a widget for all the Java settings dialogs and pages. @@ -26,7 +27,7 @@ class JavaSettingsWidget : public QWidget { public: explicit JavaSettingsWidget(QWidget* parent); - virtual ~JavaSettingsWidget() = default; + virtual ~JavaSettingsWidget(); enum class JavaStatus { NotSet, Pending, Good, DoesNotExist, DoesNotStart, ReturnedInvalidData } javaStatus = JavaStatus::NotSet; @@ -48,7 +49,8 @@ class JavaSettingsWidget : public QWidget { void updateThresholds(); protected slots: - void memoryValueChanged(int); + void onSpinBoxValueChanged(int); + void memoryValueChanged(); void javaPathEdited(const QString& path); void javaVersionSelected(BaseVersion::Ptr version); void on_javaBrowseBtn_clicked(); @@ -65,6 +67,7 @@ class JavaSettingsWidget : public QWidget { private: /* data */ VersionSelectWidget* m_versionWidget = nullptr; QVBoxLayout* m_verticalLayout = nullptr; + QSpacerItem* m_verticalSpacer = nullptr; QLineEdit* m_javaPathTextBox = nullptr; QPushButton* m_javaBrowseBtn = nullptr; @@ -99,4 +102,5 @@ class JavaSettingsWidget : public QWidget { uint64_t m_availableMemory = 0ull; shared_qobject_ptr m_checker; JavaChecker::Result m_result; + QTimer* m_memoryTimer; };