aboutsummaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-28 16:42:33 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-28 16:42:33 -0500
commit77cd2c8fbff973f6c36386d56fc911f3f86cff9b (patch)
tree0fe3b90677f14d5ae2909b04f5deb541506b5df0 /libs
parent659891db4f26d52ee58e18c470a45522087bee83 (diff)
Search all Steam library folders for game compatdata
Steam can place a game's compatdata in a different library folder than the game itself (e.g. game on SD card, compatdata on internal storage). Previously we only looked in the same steamapps directory as the appmanifest, causing games to have no prefix_path and their Documents/My Games folders to not get symlinked during prefix setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'libs')
-rw-r--r--libs/nak/src/game_finder/steam.rs38
1 files changed, 20 insertions, 18 deletions
diff --git a/libs/nak/src/game_finder/steam.rs b/libs/nak/src/game_finder/steam.rs
index b88a0b0..d403cdf 100644
--- a/libs/nak/src/game_finder/steam.rs
+++ b/libs/nak/src/game_finder/steam.rs
@@ -33,14 +33,17 @@ pub fn detect_steam_games() -> Vec<Game> {
for steam_info in find_steam_installations(&home) {
let libraries = get_library_folders(&steam_info.path);
- for library_path in libraries {
- let steamapps = library_path.join("steamapps");
- if !steamapps.exists() {
- continue;
- }
+ // Collect all steamapps paths so we can search across them for compatdata.
+ // Steam can place compatdata in a different library folder than the game.
+ let all_steamapps: Vec<PathBuf> = libraries
+ .iter()
+ .map(|l| l.join("steamapps"))
+ .filter(|s| s.exists())
+ .collect();
+ for steamapps in &all_steamapps {
// Scan for appmanifest_*.acf files
- let Ok(entries) = fs::read_dir(&steamapps) else {
+ let Ok(entries) = fs::read_dir(steamapps) else {
continue;
};
@@ -51,7 +54,9 @@ pub fn detect_steam_games() -> Vec<Game> {
};
if name.starts_with("appmanifest_") && name.ends_with(".acf") {
- if let Some(game) = parse_appmanifest(&path, &steamapps, &steam_info) {
+ if let Some(game) =
+ parse_appmanifest(&path, steamapps, &all_steamapps, &steam_info)
+ {
games.push(game);
}
}
@@ -143,6 +148,7 @@ fn get_library_folders(steam_path: &Path) -> Vec<PathBuf> {
fn parse_appmanifest(
manifest_path: &Path,
steamapps_path: &Path,
+ all_steamapps: &[PathBuf],
steam_info: &SteamInstallation,
) -> Option<Game> {
let content = fs::read_to_string(manifest_path).ok()?;
@@ -159,17 +165,13 @@ fn parse_appmanifest(
return None;
}
- // Build the prefix path
- let prefix_path = steamapps_path
- .join("compatdata")
- .join(&manifest.app_id)
- .join("pfx");
-
- let prefix_path = if prefix_path.exists() {
- Some(prefix_path)
- } else {
- None
- };
+ // Search ALL library folders for the compatdata — Steam can place it in a
+ // different library than the game itself (e.g. game on SD card, compatdata
+ // on internal storage or vice-versa).
+ let prefix_path = all_steamapps
+ .iter()
+ .map(|sa| sa.join("compatdata").join(&manifest.app_id).join("pfx"))
+ .find(|p| p.exists());
// Look up known game info
let known_game = find_by_steam_id(&manifest.app_id);