mirror of
https://github.com/lutris/lutris.git
synced 2026-07-30 23:26:15 -04:00
Steam games launch via non-blocking URI handlers (steam://rungameid/ or steam -applaunch) that exit almost immediately, and the real game runs under Steam's PID tree without inheriting LUTRIS_GAME_UUID. The default PID tracking therefore sees no processes and Game.beat() calls on_game_quit() within a couple of seconds, firing post-exit scripts while the game is still launching (#2926). Detect Steam's per-game "reaper" process instead, whose command line contains "SteamLaunch AppId=<appid>". The reaper exists for the entire lifetime of the game (through shader pre-caching and play) and exits when it stops, for native, Proton/Wine and Flatpak Steam alike. An earlier revision read the appmanifest "AppRunning" StateFlag, but that flag is not updated for Flatpak Steam (verified live: it stays "Fully Installed" through a whole session), nor for native Steam, so it was inert on both. Changes: - get_steam_game_pids(appid): find the reaper PID(s) by scanning /proc cmdlines. The appid match is anchored (followed by a space or end of string) so 440 does not also match 4400 / 44012. - steam.filter_game_pids(): track the reaper PID (primary), keeping the appmanifest AppRunning flag as a secondary signal where Steam updates it. - Runner.keep_game_alive() hook (default False): lets a runner tell Game.beat() to keep monitoring even though Lutris's launch thread has exited. Steam overrides it to bridge the launch window (grace period, so a failed launch still ends) and the whole game lifetime. Without this, beat() treated the live game's PIDs as orphans and SIGTERM'd them ~2s in. - steam.force_stop_game(): SIGTERM the game's reaper (stops just this game), never the Steam client. - Per-beat caching of the reaper scan so filter_game_pids() and keep_game_alive() share one /proc walk per heartbeat; plus per-appid caching of the resolved appmanifest path. - The launch grace period defaults to 120s (DEFAULT_LAUNCH_GRACE_SECONDS) and is overridable per game via the advanced "launch_grace_seconds" option. - get_steam_pid() now narrows system.get_pid()'s str | list | None return to Optional[str] at the source, so callers don't each re-handle the union. - STEAM_DATA_DIRS: add the current Flatpak Steam layout so Flatpak libraries are found. - Tests (built through the real runner __init__) for the reaper helper (including the prefix-collision guard), filter_game_pids, keep_game_alive (launcher-alive / reaper-alive / launch grace / configured grace / post- quit), force_stop_game sparing Steam, get_steam_pid narrowing and the appmanifest caching. Verified end-to-end through the Lutris GUI with Team Fortress 2 on both Flatpak Steam (~4 min session, clean quit) and native Steam (multiple sessions, e.g. "has run for 66 seconds", clean quit), replacing the previous "ran for 2 seconds, did it crash?". Fixes: #2926 Warn consistently on any invalid launch_grace_seconds: a non-positive numeric value now logs the same warning as a non-numeric one instead of silently falling back to the default.