diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-05-16 19:51:40 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-05-16 19:51:40 -0500 |
| commit | 549b84b0f8815737c93913b200dde3821a062cb0 (patch) | |
| tree | f6bfd96729016847438beda9416c93f447838077 /libs/game_bethesda/src/games/starfield/gamestarfield.cpp | |
| parent | a0747cabb420d699be3a1dd4c63f47c5153bd7b9 (diff) | |
mo2: catch up to upstream 2.5.3 Betas 3-11
Multi-area sync against the upstream MO2 2.5.3 beta line. Roughly three
logical sections share the diff:
Catch-up (Betas 3-11):
- nxmaccessmanager: drop "supporter" from validRoles so non-premium
supporters get the right download path (Beta 10)
- mainwindow: disable tutorial triggers at the trigger sites; Qt 6.11
lockup on child windows (Beta 4)
- basic_games: add Kingdom Come Deliverance 2, Slay the Spire 2
(Betas 11, 6)
- uibase: add NXM collections parsing fields/accessors + (?:nxm|modl)
scheme support in NXMUrl (Beta 9)
- Starfield: blueprintPrefix() on IPluginGame; plugins.txt write
suppression for blueprint plugins; hasInvalidBlueprint /
hasUnpairedBlueprint diagnoses; Title-keyed content catalog
consolidation (Betas 3-5)
- downloadmanager + systemtraymanager + organizercore + iuserinterface
+ settings: add Beta 11 "show notifications when downloads complete
or fail" toggle and the showNotification plumbing
- nxmaccessmanager: restore upstream re-entry guard for OAuth refresh
and the styled OAuth response page (Beta 11)
- organizer_en.ts and game-bethesda *_en.ts: pull upstream HEAD strings
Workarounds tab removed:
- Delete settingsdialogworkarounds.{h,cpp}; drop the tab in
settingsdialog.ui; move "Enable archives parsing" into General
- Hardcode GameSettings::forceEnableCoreFiles() to true so the
primary-master toggle-off bug (DLCs unchecked on tab refresh) can't
recur; setter becomes a no-op
- No-op stubs for offlineMode, useProxy, useCustomBrowser, Steam
appID/credentials, executablesBlacklist, skipFileSuffixes,
skipDirectories — UI gone, accessors keep call sites green
- settingsdialognexus drops the custom-browser wiring; spawn drops the
"Change the blacklist" Retry path
Beta 9 download manager port:
- fileID-first match in nxmFilesAvailable and
nxmFileInfoFromMd5Available; filename remains the fallback
- NexusInterface::isActiveFileStatus() helper; rewrite of
nxmUpdatesAvailable to use pickNewestVersion /
findUpdateChainSuccessors / resolveInstalledFileId. ARCHIVED_HIDDEN
now correctly treated as inactive
- std::optional<unsigned int> reservedID on DownloadInfo factories and
on the three addDownload overloads; startDownloadURLs and
startDownloadURLWithMeta return the canonical DownloadID instead of
m_ActiveDownloads.size()-1 (which was the index, not an ID)
- QHash<unsigned int, DownloadInfo*> m_ByID maintained alongside
m_ActiveDownloads at every mutation site; downloadInfoByID is now
O(1) via m_ByID.value(id, nullptr)
LOOT remains intentionally stripped (lootcli build cruft cleaned up
separately). BSA wide-path skipped — Linux UTF-8 paths already work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'libs/game_bethesda/src/games/starfield/gamestarfield.cpp')
| -rw-r--r-- | libs/game_bethesda/src/games/starfield/gamestarfield.cpp | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/libs/game_bethesda/src/games/starfield/gamestarfield.cpp b/libs/game_bethesda/src/games/starfield/gamestarfield.cpp index ebec948..06a6d79 100644 --- a/libs/game_bethesda/src/games/starfield/gamestarfield.cpp +++ b/libs/game_bethesda/src/games/starfield/gamestarfield.cpp @@ -22,6 +22,7 @@ #include <QDir> #include <QFileInfo> #include <QList> +#include <QRegularExpression> #include <QObject> #include <QString> #include <QStringList> @@ -337,15 +338,23 @@ QStringList GameStarfield::CCPlugins() const // as Creations. The StarfieldUnmanagedMods class handles parsing mod names and files. if (unmanagedMods.get()) { auto contentCatalog = unmanagedMods->parseContentCatalog(); - for (const auto& mod : contentCatalog) { - if (!plugins.contains(mod.first, Qt::CaseInsensitive)) { - plugins.append(mod.first); + for (auto& mod : contentCatalog) { + QStringList pluginFiles = mod.second.files.filter(QRegularExpression( + "\\.es(m|p|l)$", QRegularExpression::CaseInsensitiveOption)); + if (!pluginFiles.isEmpty()) { + plugins += pluginFiles; } } } + plugins.removeDuplicates(); return plugins; } +QString GameStarfield::blueprintPrefix() const +{ + return "blueprintships-"; +} + IPluginGame::SortMechanism GameStarfield::sortMechanism() const { return IPluginGame::SortMechanism::LOOT; @@ -380,6 +389,10 @@ std::vector<unsigned int> GameStarfield::activeProblems() const if (testFilePresent()) result.push_back(PROBLEM_TEST_FILE); } + if (hasInvalidBlueprint()) + result.push_back(PROBLEM_INVALID_BLUEPRINT); + if (hasUnpairedBlueprint()) + result.push_back(PROBLEM_UNPAIRED_BLUEPRINT); } return result; } @@ -412,6 +425,38 @@ bool GameStarfield::testFilePresent() const return false; } +bool GameStarfield::hasInvalidBlueprint() const +{ + auto plugins = m_Organizer->pluginList()->pluginNames(); + for (auto plugin : plugins) { + if (m_Organizer->pluginList()->isBlueprintFlagged(plugin)) { + if (!plugin.startsWith(blueprintPrefix(), Qt::CaseInsensitive) || + !m_Organizer->pluginList()->hasMasterExtension(plugin)) + return true; + } else if (plugin.startsWith(blueprintPrefix(), Qt::CaseInsensitive)) { + return true; + } + } + return false; +} + +bool GameStarfield::hasUnpairedBlueprint() const +{ + auto plugins = m_Organizer->pluginList()->pluginNames(); + for (auto plugin : plugins) { + if (plugin.startsWith(blueprintPrefix(), Qt::CaseInsensitive) && + m_Organizer->pluginList()->hasMasterExtension(plugin)) { + QString parent = plugin.mid(blueprintPrefix().size(), + plugin.size() - blueprintPrefix().size() - 4); + auto mainPlugin = plugins.filter(QRegularExpression( + "^" + parent + "\\.es(m|p|l)$", QRegularExpression::CaseInsensitiveOption)); + if (mainPlugin.isEmpty()) + return true; + } + } + return false; +} + QString GameStarfield::shortDescription(unsigned int key) const { switch (key) { @@ -419,6 +464,10 @@ QString GameStarfield::shortDescription(unsigned int key) const return tr("You have active ESP plugins in Starfield"); case PROBLEM_TEST_FILE: return tr("sTestFile entries are present"); + case PROBLEM_INVALID_BLUEPRINT: + return tr("Invalid blueprint plugins found"); + case PROBLEM_UNPAIRED_BLUEPRINT: + return tr("Unpaired blueprint plugins found"); } return ""; } @@ -446,6 +495,17 @@ QString GameStarfield::fullDescription(unsigned int key) const "settings in your StarfieldCustom.ini. These must be removed or the game " "will not read the plugins.txt file. Management is still disabled.</p>"); } + case PROBLEM_INVALID_BLUEPRINT: + return tr( + "<p>You have a blueprint file that is invalid. Blueprints require the " + "blueprint flag and prefix and must have the ESM extension to be valid.</p>"); + case PROBLEM_UNPAIRED_BLUEPRINT: + return tr( + "<p>You have a valid blueprint file that has no paired main plugin. The only " + "way to load blueprint files is by enabling a main plugin with the same base " + "name. This is the part after the prefix and before the extension.</p><p>eg. " + "<strong>BlueprintShips-example.esm</strong> should have a paired main plugin " + "<strong>example.esm</strong></p>"); } return ""; } |
