aboutsummaryrefslogtreecommitdiff
path: root/libs/nak/src/game_finder/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libs/nak/src/game_finder/mod.rs')
-rw-r--r--libs/nak/src/game_finder/mod.rs218
1 files changed, 0 insertions, 218 deletions
diff --git a/libs/nak/src/game_finder/mod.rs b/libs/nak/src/game_finder/mod.rs
deleted file mode 100644
index 600751a..0000000
--- a/libs/nak/src/game_finder/mod.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-//! Game detection module
-//!
-//! Provides unified game detection across multiple launchers:
-//! - Steam (native, Flatpak, Snap)
-//! - Heroic (GOG, Epic)
-//! - Bottles
-
-// Allow unused items - this is a public API module
-#![allow(dead_code)]
-#![allow(unused_imports)]
-
-mod bottles;
-mod heroic;
-pub mod known_games;
-mod registry;
-mod steam;
-mod vdf;
-
-use std::path::PathBuf;
-
-pub use bottles::detect_bottles_games;
-pub use heroic::detect_heroic_games;
-pub use known_games::{
- find_by_epic_id, find_by_gog_id, find_by_name, find_by_steam_id, find_by_title, KnownGame,
- KNOWN_GAMES,
-};
-pub use registry::{read_registry_value, wine_path_to_linux};
-pub use steam::{detect_steam_games, find_game_install_path, find_game_prefix_path, get_known_game};
-
-// ============================================================================
-// Core Types
-// ============================================================================
-
-/// The launcher/store a game was installed from
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum Launcher {
- Steam { is_flatpak: bool, is_snap: bool },
- Heroic { store: HeroicStore },
- Bottles,
-}
-
-impl Launcher {
- pub fn display_name(&self) -> &'static str {
- match self {
- Launcher::Steam { is_flatpak: true, .. } => "Steam (Flatpak)",
- Launcher::Steam { is_snap: true, .. } => "Steam (Snap)",
- Launcher::Steam { .. } => "Steam",
- Launcher::Heroic { store: HeroicStore::GOG } => "Heroic (GOG)",
- Launcher::Heroic { store: HeroicStore::Epic } => "Heroic (Epic)",
- Launcher::Bottles => "Bottles",
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum HeroicStore {
- GOG,
- Epic,
-}
-
-/// A detected game installation
-#[derive(Debug, Clone)]
-pub struct Game {
- pub name: String,
- pub app_id: String,
- pub install_path: PathBuf,
- pub prefix_path: Option<PathBuf>,
- pub launcher: Launcher,
- pub my_games_folder: Option<String>,
- pub appdata_local_folder: Option<String>,
- pub appdata_roaming_folder: Option<String>,
- pub registry_path: Option<String>,
- pub registry_value: Option<String>,
-}
-
-impl Game {
- pub fn has_prefix(&self) -> bool {
- self.prefix_path.is_some()
- }
-
- pub fn get_prefix_user_path(&self) -> Option<PathBuf> {
- let prefix = self.prefix_path.as_ref()?;
- let users_dir = prefix.join("drive_c/users");
-
- if let Ok(entries) = std::fs::read_dir(&users_dir) {
- for entry in entries.flatten() {
- let name = entry.file_name().to_string_lossy().to_string();
- if name != "Public" && name != "root" {
- return Some(users_dir.join(name));
- }
- }
- }
-
- Some(users_dir.join("steamuser"))
- }
-
- pub fn get_prefix_documents_path(&self) -> Option<PathBuf> {
- self.get_prefix_user_path().map(|p| p.join("Documents"))
- }
-
- pub fn get_prefix_my_games_path(&self) -> Option<PathBuf> {
- let docs = self.get_prefix_documents_path()?;
- let folder = self.my_games_folder.as_ref()?;
- Some(docs.join("My Games").join(folder))
- }
-
- pub fn get_prefix_appdata_local_path(&self) -> Option<PathBuf> {
- let user = self.get_prefix_user_path()?;
- let folder = self.appdata_local_folder.as_ref()?;
- Some(user.join("AppData/Local").join(folder))
- }
-
- pub fn get_prefix_appdata_roaming_path(&self) -> Option<PathBuf> {
- let user = self.get_prefix_user_path()?;
- let folder = self.appdata_roaming_folder.as_ref()?;
- Some(user.join("AppData/Roaming").join(folder))
- }
-}
-
-// ============================================================================
-// Scan Results
-// ============================================================================
-
-#[derive(Debug, Default)]
-pub struct GameScanResult {
- pub games: Vec<Game>,
- pub steam_count: usize,
- pub heroic_count: usize,
- pub bottles_count: usize,
-}
-
-impl GameScanResult {
- pub fn games_with_prefixes(&self) -> impl Iterator<Item = &Game> {
- self.games.iter().filter(|g| g.has_prefix())
- }
-
- pub fn games_by_launcher(&self, launcher_type: &str) -> Vec<&Game> {
- self.games
- .iter()
- .filter(|g| {
- matches!(
- (&g.launcher, launcher_type),
- (Launcher::Steam { .. }, "steam")
- | (Launcher::Heroic { .. }, "heroic")
- | (Launcher::Bottles, "bottles")
- )
- })
- .collect()
- }
-
- pub fn find_by_name(&self, name: &str) -> Option<&Game> {
- let name_lower = name.to_lowercase();
- self.games
- .iter()
- .find(|g| g.name.to_lowercase() == name_lower)
- }
-
- pub fn find_by_app_id(&self, app_id: &str) -> Option<&Game> {
- self.games.iter().find(|g| g.app_id == app_id)
- }
-}
-
-// ============================================================================
-// Public API
-// ============================================================================
-
-/// Detect all installed games from all supported launchers.
-///
-/// Games are detected in priority order: Steam -> Heroic (GOG -> Epic) -> Bottles.
-/// When the same game is found from multiple launchers, the higher-priority
-/// detection is kept and duplicates are skipped. This ensures registry entries
-/// (which are shared across storefronts) prefer Steam paths, then GOG, then Epic.
-pub fn detect_all_games() -> GameScanResult {
- let mut result = GameScanResult::default();
-
- // Detect in priority order: Steam first, then GOG (via Heroic), then Epic, then Bottles.
- let steam_games = detect_steam_games();
- result.steam_count = steam_games.len();
- result.games.extend(steam_games);
-
- let heroic_games = detect_heroic_games();
- result.heroic_count = heroic_games.len();
- result.games.extend(heroic_games);
-
- let bottles_games = detect_bottles_games();
- result.bottles_count = bottles_games.len();
- result.games.extend(bottles_games);
-
- // Deduplicate: keep the first occurrence of each game (by registry_path),
- // which respects the detection order (Steam > GOG > Epic > Bottles).
- deduplicate_games(&mut result);
-
- result
-}
-
-/// Remove duplicate game detections, keeping the first (highest-priority) entry.
-/// Two games are considered duplicates if they have the same registry_path.
-fn deduplicate_games(result: &mut GameScanResult) {
- let mut seen_registry_paths = std::collections::HashSet::new();
- result.games.retain(|game| {
- if let Some(ref reg_path) = game.registry_path {
- seen_registry_paths.insert(reg_path.clone())
- } else {
- // Games without registry paths are always kept (no risk of conflict)
- true
- }
- });
-}
-
-/// Detect only Steam games
-pub fn detect_steam_only() -> GameScanResult {
- let steam_games = detect_steam_games();
- GameScanResult {
- steam_count: steam_games.len(),
- games: steam_games,
- ..Default::default()
- }
-}