using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Microsoft.Win32; namespace Wabbajack.Common { [DebuggerDisplay("{Name}")] public class SteamGame { public int AppId; public string Name; public string InstallDir; public Game? Game; } /// /// Class for all Steam operations /// public class SteamHandler { private static readonly Lazy instance = new Lazy( () => new SteamHandler(true), isThreadSafe: true); public static SteamHandler Instance => instance.Value; private const string SteamRegKey = @"Software\Valve\Steam"; /// /// Path to the Steam folder /// public string SteamPath { get; internal set; } /// /// HashSet of all known Steam Libraries /// public HashSet InstallFolders { get; internal set; } /// /// HashSet of all known SteamGames /// public HashSet Games { get; internal set; } private string SteamConfig => Path.Combine(SteamPath, "config", "config.vdf"); public SteamHandler(bool init) { var steamKey = Registry.CurrentUser.OpenSubKey(SteamRegKey); SteamPath = steamKey?.GetValue("SteamPath").ToString(); if(!init) return; LoadInstallFolders(); LoadAllSteamGames(); } /// /// Finds the installation path of a Steam game by ID /// /// ID of the Steam game /// public string GetGamePathById(int id) { return Games.FirstOrDefault(f => f.AppId == id)?.InstallDir; } /// /// Reads the config file and adds all found installation folders to the HashSet /// public void LoadInstallFolders() { var paths = new HashSet(); File.ReadLines(SteamConfig, Encoding.UTF8).Do(l => { if (!l.Contains("BaseInstallFolder_")) return; var s = GetVdfValue(l); s = Path.Combine(s, "steamapps"); paths.Add(s); }); InstallFolders = paths; } /// /// Enumerates through all Steam Libraries to find and read all .afc files, adding the found game /// to the HashSet /// public void LoadAllSteamGames() { var games = new HashSet(); InstallFolders.Do(p => { Directory.EnumerateFiles(p, "*.acf", SearchOption.TopDirectoryOnly).Do(f => { var steamGame = new SteamGame(); File.ReadAllLines(f, Encoding.UTF8).Do(l => { if(l.Contains("\"appid\"")) steamGame.AppId = int.Parse(GetVdfValue(l)); if (l.Contains("\"name\"")) steamGame.Name = GetVdfValue(l); if (l.Contains("\"installdir\"")) steamGame.InstallDir = Path.Combine(p, "common", GetVdfValue(l)); }); steamGame.Game = GameRegistry.Games.Values .FirstOrDefault(g => g.SteamIDs.Contains(steamGame.AppId) && g.RequiredFiles.TrueForAll(s => File.Exists(Path.Combine(steamGame.InstallDir, s))) )?.Game; games.Add(steamGame); }); }); Games = games; } private static string GetVdfValue(string line) { var trim = line.Trim('\t').Replace("\t", ""); string[] s = trim.Split('\"'); return s[3].Replace("\\\\", "\\"); } } }