From d22d8c267b012729b6b84142def2a30ca4691d7a Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Fri, 20 Feb 2026 23:53:26 -0600 Subject: Fix AppImage plugin loading, save timestamps, and INI corruption - Add AppConfig::pluginsPath()/dllsPath() that respect MO2_PLUGINS_DIR and MO2_DLLS_DIR env vars, fixing plugin discovery when plugins live inside read-only AppImage squashfs (#22, game plugin not found errors) - Preserve file modification times in save deploy/sync so games display correct save timestamps instead of all showing the same time (#17) - Replace QSettings INI reader in saves tab with direct line-by-line parser to avoid backslash-as-line-continuation corruption of sLocalSavePath=__MO_Saves\ (#22, saves tab showing wrong directory) - Add diagnostic logging to plugin symlink creation, save backup/restore operations to help diagnose silent failures through prefix symlinks - Fix Python SONAME mismatch in AppImage build (patch portable Python SONAME to match librunner.so DT_NEEDED, preventing dual libpython load) - Bundle PyQt6 Qt dependencies, improve RPATH for lib/ and plugins/ Co-Authored-By: Claude Opus 4.6 --- libs/nak/src/game_finder/mod.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'libs/nak/src/game_finder/mod.rs') diff --git a/libs/nak/src/game_finder/mod.rs b/libs/nak/src/game_finder/mod.rs index c383c8a..600751a 100644 --- a/libs/nak/src/game_finder/mod.rs +++ b/libs/nak/src/game_finder/mod.rs @@ -20,7 +20,10 @@ use std::path::PathBuf; pub use bottles::detect_bottles_games; pub use heroic::detect_heroic_games; -pub use known_games::{find_by_gog_id, find_by_name, find_by_steam_id, KnownGame, KNOWN_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}; @@ -161,10 +164,16 @@ impl GameScanResult { // Public API // ============================================================================ -/// Detect all installed games from all supported launchers +/// 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); @@ -177,9 +186,27 @@ pub fn detect_all_games() -> GameScanResult { 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(); -- cgit v1.3.1