diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-06-10 23:56:47 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-06-10 23:56:47 -0500 |
| commit | 30d2c801a01eeb140ddd5adf8676f2626ecff3fa (patch) | |
| tree | 93d5fad39ec3c5b1420cc0498922deb78b6db413 | |
| parent | ce4aca6f32ad3a593fc722a12306711e4e5efa63 (diff) | |
Improve Proton launch context
| -rw-r--r-- | src/src/processrunner.cpp | 50 | ||||
| -rw-r--r-- | src/src/protonlauncher.cpp | 32 | ||||
| -rw-r--r-- | src/src/protonlauncher.h | 2 | ||||
| -rw-r--r-- | src/src/spawn.cpp | 62 | ||||
| -rw-r--r-- | src/src/spawn.h | 1 |
5 files changed, 130 insertions, 17 deletions
diff --git a/src/src/processrunner.cpp b/src/src/processrunner.cpp index 63ecf83..a0deae2 100644 --- a/src/src/processrunner.cpp +++ b/src/src/processrunner.cpp @@ -1,8 +1,10 @@ #include "processrunner.h" #include "env.h" #include "envmodule.h" +#include "fluorineconfig.h" #include "instancemanager.h" #include "iuserinterface.h" +#include "knowngames.h" #include "organizercore.h" #include <iplugingame.h> @@ -17,6 +19,7 @@ #include <QMetaObject> #include <QPointer> #include <QProcess> +#include <QSettings> #include <QThread> #include <cerrno> @@ -31,6 +34,31 @@ using namespace MOBase; +static QString steamAppIdFromFluorineConfig() +{ + if (auto cfg = FluorineConfig::load(); cfg.has_value() && cfg->app_id != 0) { + return QString::number(cfg->app_id); + } + + return {}; +} + +static QString steamAppIdFromKnownGame(const QString& gameName) +{ + if (const auto* knownGame = findKnownGameByTitle(gameName); + knownGame != nullptr && knownGame->steam_app_id != nullptr) { + return QString::fromLatin1(knownGame->steam_app_id); + } + + return {}; +} + +static bool steamOverlayEnabled(const Settings& settings) +{ + const QSettings instanceIni(settings.filename(), QSettings::IniFormat); + return instanceIni.value("fluorine/steam_overlay", false).toBool(); +} + void adjustForVirtualized(const IPluginGame* game, spawn::SpawnParameters& sp, const Settings& settings) { @@ -1173,6 +1201,7 @@ std::optional<ProcessRunner::Results> ProcessRunner::runBinary() const auto* game = m_core.managedGame(); auto& settings = m_core.settings(); + m_sp.gameDirectory = game->gameDirectory(); if (m_sp.steamAppID.trimmed().isEmpty()) { const QString gameSteamId = game->steamAPPId().trimmed(); @@ -1183,6 +1212,27 @@ std::optional<ProcessRunner::Results> ProcessRunner::runBinary() } } + const bool resolveOverlaySteamAppId = m_sp.useProton && steamOverlayEnabled(settings); + + if (resolveOverlaySteamAppId && m_sp.steamAppID.trimmed().isEmpty()) { + const QString knownSteamId = steamAppIdFromKnownGame(game->gameName()); + if (!knownSteamId.isEmpty()) { + m_sp.steamAppID = knownSteamId; + log::debug("process runner: using known-game steam app id '{}' for '{}'", + m_sp.steamAppID, game->gameName()); + } + } + + if (resolveOverlaySteamAppId && m_sp.steamAppID.trimmed().isEmpty()) { + const QString configSteamId = steamAppIdFromFluorineConfig(); + if (!configSteamId.isEmpty()) { + m_sp.steamAppID = configSteamId; + log::debug("process runner: using Fluorine config steam app id '{}' " + "for launch", + m_sp.steamAppID); + } + } + if (!checkSteam(parent, m_sp, game->gameDirectory(), m_sp.steamAppID, settings)) { return Error; } diff --git a/src/src/protonlauncher.cpp b/src/src/protonlauncher.cpp index 800d837..e7da03a 100644 --- a/src/src/protonlauncher.cpp +++ b/src/src/protonlauncher.cpp @@ -581,6 +581,12 @@ ProtonLauncher& ProtonLauncher::setWorkingDir(const QString& dir) return *this; } +ProtonLauncher& ProtonLauncher::setGameDirectory(const QString& dir) +{ + m_gameDirectory = dir.trimmed(); + return *this; +} + ProtonLauncher& ProtonLauncher::setProtonPath(const QString& path) { m_protonPath = path.trimmed(); @@ -723,8 +729,9 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const // before starting a new one. const QStringList protonArgs = QStringList() << "waitforexitandrun" << m_binary << m_arguments; QStringList pressureVesselImportantPaths; - pressureVesselImportantPaths << m_binary << m_workingDir << m_prefixPath - << m_bindMountSource << m_bindMountTarget; + pressureVesselImportantPaths << m_binary << m_workingDir << m_gameDirectory + << m_prefixPath << m_bindMountSource + << m_bindMountTarget; // If SLR is enabled, wrap the whole proton invocation inside the // pressure-vessel container provided by SteamLinuxRuntime_sniper. @@ -739,20 +746,13 @@ bool ProtonLauncher::launchWithProton(qint64& pid) const // Build: [wrappers] run_script [--filesystem=...] -- proton_script protonArgs QStringList slrArgs; - // Expose host directories to the pressure-vessel container. - // Without --filesystem= flags, the container's mount namespace - // may not see FUSE mounts or system-installed Proton paths. - if (!m_binary.isEmpty()) { - QString gameDir = QFileInfo(m_binary).absolutePath(); - const QFileInfo gameDirInfo(gameDir); - if (gameDirInfo.fileName().compare(QStringLiteral("bin"), - Qt::CaseInsensitive) == 0) { - const QString gameRoot = gameDirInfo.dir().absolutePath(); - if (QFileInfo(gameRoot).exists()) { - gameDir = gameRoot; - } - } - slrArgs << QStringLiteral("--filesystem=%1").arg(gameDir); + // Expose the managed game root. Extenders frequently live below a + // nested bin directory but load assets/modules from the root. + if (!m_gameDirectory.isEmpty() && QFileInfo::exists(m_gameDirectory)) { + slrArgs << QStringLiteral("--filesystem=%1").arg(m_gameDirectory); + } else if (!m_binary.isEmpty()) { + slrArgs << QStringLiteral("--filesystem=%1") + .arg(QFileInfo(m_binary).absolutePath()); } if (!m_prefixPath.isEmpty()) { slrArgs << QStringLiteral("--filesystem=%1").arg(m_prefixPath); diff --git a/src/src/protonlauncher.h b/src/src/protonlauncher.h index 25c4b16..f0ce09b 100644 --- a/src/src/protonlauncher.h +++ b/src/src/protonlauncher.h @@ -16,6 +16,7 @@ public: ProtonLauncher& setBinary(const QString& path); ProtonLauncher& setArguments(const QStringList& args); ProtonLauncher& setWorkingDir(const QString& dir); + ProtonLauncher& setGameDirectory(const QString& dir); ProtonLauncher& setProtonPath(const QString& path); ProtonLauncher& setPrefix(const QString& path); ProtonLauncher& setSteamAppId(uint32_t id); @@ -50,6 +51,7 @@ private: QString m_binary; QStringList m_arguments; QString m_workingDir; + QString m_gameDirectory; QString m_protonPath; QString m_prefixPath; uint32_t m_steamAppId{0}; diff --git a/src/src/spawn.cpp b/src/src/spawn.cpp index ec41221..701304b 100644 --- a/src/src/spawn.cpp +++ b/src/src/spawn.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "env.h" #include "envmodule.h" #include "fluorineconfig.h" +#include "knowngames.h" #include "protonlauncher.h" #include "settings.h" #include "shared/appconfig.h" @@ -192,6 +193,38 @@ uint32_t parseSteamAppId(const QString& steamAppId) return (ok ? n : 0u); } +static uint32_t steamAppIdFromFluorineConfig() +{ + if (auto cfg = FluorineConfig::load(); cfg.has_value()) { + return cfg->app_id; + } + + return 0; +} + +static uint32_t steamAppIdFromKnownGame(const QString& gameName) +{ + if (const auto* knownGame = findKnownGameByTitle(gameName); + knownGame != nullptr && knownGame->steam_app_id != nullptr) { + bool ok = false; + const auto n = QString::fromLatin1(knownGame->steam_app_id).toUInt(&ok); + return (ok ? n : 0u); + } + + return 0; +} + +static bool steamOverlayEnabledForCurrentInstance() +{ + const Settings* instanceForLaunch = Settings::maybeInstance(); + if (!instanceForLaunch) { + return false; + } + + const QSettings instanceIni(instanceForLaunch->filename(), QSettings::IniFormat); + return instanceIni.value("fluorine/steam_overlay", false).toBool(); +} + QString firstExistingSetting(const QSettings& settings, const QStringList& keys) { for (const QString& key : keys) { @@ -406,11 +439,38 @@ int spawn(const SpawnParameters& sp, pid_t& processId) logSpawning(sp, bin + " " + sp.arguments); + uint32_t steamAppId = parseSteamAppId(sp.steamAppID); + const bool resolveOverlaySteamAppId = + sp.useProton && steamOverlayEnabledForCurrentInstance(); + if (resolveOverlaySteamAppId && steamAppId == 0) { + const Settings* instanceForLaunch = Settings::maybeInstance(); + if (instanceForLaunch) { + const auto gameName = instanceForLaunch->game().name(); + if (gameName && !gameName->trimmed().isEmpty()) { + steamAppId = steamAppIdFromKnownGame(*gameName); + if (steamAppId != 0) { + MOBase::log::debug("spawn: using known-game steam app id '{}' " + "for '{}'", + steamAppId, *gameName); + } + } + } + } + if (resolveOverlaySteamAppId && steamAppId == 0) { + steamAppId = steamAppIdFromFluorineConfig(); + if (steamAppId != 0) { + MOBase::log::debug("spawn: using Fluorine config steam app id '{}' " + "for Proton launch", + steamAppId); + } + } + ProtonLauncher launcher; launcher.setBinary(bin) .setArguments(argList) .setWorkingDir(cwd) - .setSteamAppId(parseSteamAppId(sp.steamAppID)); + .setGameDirectory(MOBase::normalizePathForHost(sp.gameDirectory.absolutePath())) + .setSteamAppId(steamAppId); if (sp.useProton) { // Read per-instance settings from the instance INI (not the global QSettings). diff --git a/src/src/spawn.h b/src/src/spawn.h index 40207c3..c871fcc 100644 --- a/src/src/spawn.h +++ b/src/src/spawn.h @@ -49,6 +49,7 @@ struct SpawnParameters QFileInfo binary;
QString arguments;
QDir currentDirectory;
+ QDir gameDirectory;
QString steamAppID;
bool hooked = false;
bool useProton = true;
|
