From 62c3178ff259bdf0dcc1c70e06f34a8d72ecc5f7 Mon Sep 17 00:00:00 2001 From: erri120 Date: Fri, 3 Jan 2020 18:03:09 +0100 Subject: [PATCH 1/4] Overhauled the StoreHandlers --- Wabbajack.Common/StoreHandlers/GOGHandler.cs | 133 ++++++++ .../StoreHandlers/SteamHandler.cs | 301 ++++++++++++++++++ .../StoreHandlers/StoreHandler.cs | 93 ++++++ 3 files changed, 527 insertions(+) create mode 100644 Wabbajack.Common/StoreHandlers/GOGHandler.cs create mode 100644 Wabbajack.Common/StoreHandlers/SteamHandler.cs create mode 100644 Wabbajack.Common/StoreHandlers/StoreHandler.cs diff --git a/Wabbajack.Common/StoreHandlers/GOGHandler.cs b/Wabbajack.Common/StoreHandlers/GOGHandler.cs new file mode 100644 index 00000000..70d9e9e2 --- /dev/null +++ b/Wabbajack.Common/StoreHandlers/GOGHandler.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security; +using Microsoft.Win32; + +namespace Wabbajack.Common.StoreHandlers +{ + public class GOGGame : AStoreGame + { + public override Game Game { get; internal set; } + public override string Name { get; internal set; } + public override string Path { get; internal set; } + public override int ID { get; internal set; } + public override StoreType Type { get; internal set; } = StoreType.GOG; + } + + public class GOGHandler : AStoreHandler + { + public override List Games { get; set; } + public override StoreType Type { get; internal set; } + + private const string GOGRegKey = @"Software\GOG.com\Games"; + private const string GOG64RegKey = @"Software\WOW6432Node\GOG.com\Games"; + + private RegistryKey GOGKey { get; set; } + + public override bool Init() + { + try + { + var gogKey = Registry.LocalMachine.OpenSubKey(GOGRegKey) ?? + Registry.LocalMachine.OpenSubKey(GOG64RegKey); + + if (gogKey == null) + { + Utils.Error(new StoreException("Could not open the GOG registry key!")); + return false; + } + + GOGKey = gogKey; + return true; + } + catch (SecurityException se) + { + Utils.Error(se, "GOGHandler could not read from registry!"); + } + catch (UnauthorizedAccessException uae) + { + Utils.Error(uae, "GOGHandler could not read from registry!"); + } + + return false; + } + + public override bool LoadAllGames() + { + try + { + string[] keys = GOGKey.GetSubKeyNames(); + Utils.Log($"Found {keys.Length} SubKeys for GOG"); + + keys.Do(key => + { + if (!int.TryParse(key, out var gameID)) + { + Utils.Error(new StoreException($"Could not read gameID for key {key}")); + return; + } + + var subKey = GOGKey.OpenSubKey(key); + if (subKey == null) + { + Utils.Error(new StoreException($"Could not open SubKey for {key}")); + return; + } + + var gameNameValue = subKey.GetValue("GAMENAME"); + if (gameNameValue == null) + { + Utils.Error(new StoreException($"Could not get GAMENAME for {gameID} at {key}")); + return; + } + + var gameName = gameNameValue.ToString(); + + var pathValue = subKey.GetValue("PATH"); + if (pathValue == null) + { + Utils.Error(new StoreException($"Could not get PATH for {gameID} at {key}")); + return; + } + + var path = pathValue.ToString(); + + var game = new GOGGame() {ID = gameID, Name = gameName, Path = path}; + + var gameMeta = GameRegistry.Games.Values.FirstOrDefault(g => + g.GOGIDs.Contains(game.ID) + && + g.RequiredFiles.TrueForAll(file => + File.Exists(Path.Combine(game.Path, file)))); + + if (gameMeta == null) + return; + + game.Game = gameMeta.Game; + + Utils.Log($"Found GOG Game: \"{game.Name}\"({game.ID}) at {game.Path}"); + + Games.Add(game); + }); + } + catch (SecurityException se) + { + Utils.Error(se, "GOGHandler could not read from registry!"); + } + catch (UnauthorizedAccessException uae) + { + Utils.Error(uae, "GOGHandler could not read from registry!"); + } + catch (Exception e) + { + Utils.ErrorThrow(e); + } + + Utils.Log($"Total number of GOG Games found: {Games.Count}"); + + return true; + } + } +} diff --git a/Wabbajack.Common/StoreHandlers/SteamHandler.cs b/Wabbajack.Common/StoreHandlers/SteamHandler.cs new file mode 100644 index 00000000..f7bbb2e5 --- /dev/null +++ b/Wabbajack.Common/StoreHandlers/SteamHandler.cs @@ -0,0 +1,301 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Security; +using DynamicData; +using Microsoft.Win32; + +namespace Wabbajack.Common.StoreHandlers +{ + public class SteamGame : AStoreGame + { + public override Game Game { get; internal set; } + public override string Name { get; internal set; } + public override string Path { get; internal set; } + public override int ID { get; internal set; } + public override StoreType Type { get; internal set; } = StoreType.STEAM; + + public string Universe; + + public List WorkshopItems; + public int WorkshopItemsSize; + } + + public class SteamWorkshopItem + { + public SteamGame Game; + public int ItemID; + public int Size; + } + + public class SteamHandler : AStoreHandler + { + public override List Games { get; set; } + public override StoreType Type { get; internal set; } = StoreType.STEAM; + + private const string SteamRegKey = @"Software\Valve\Steam"; + + private string SteamPath { get; set; } + private List SteamUniverses { get; set; } + + private string SteamConfig => Path.Combine(SteamPath, "config", "config.vdf"); + + public override bool Init() + { + try + { + var steamKey = Registry.CurrentUser.OpenSubKey(SteamRegKey); + + var steamPathKey = steamKey?.GetValue("SteamPath"); + if (steamPathKey == null) + { + Utils.Error(new StoreException("Could not open the SteamPath registry key!")); + return false; + } + + SteamPath = steamPathKey.ToString(); + if (string.IsNullOrWhiteSpace(SteamPath)) + { + Utils.Error(new StoreException("Path to the Steam Directory from registry is Null or Empty!")); + return false; + } + + if (!Directory.Exists(SteamPath)) + { + Utils.Error(new StoreException($"Path to the Steam Directory from registry does not exists: {SteamPath}")); + return false; + } + + if (File.Exists(SteamConfig)) + return true; + + Utils.Error(new StoreException($"The Steam config file could not be read: {SteamConfig}")); + return false; + + } + catch (SecurityException se) + { + Utils.Error(se, "SteamHandler could not read from registry!"); + } + catch (UnauthorizedAccessException uae) + { + Utils.Error(uae, "SteamHandler could not read from registry!"); + } + + return false; + } + + private void LoadUniverses() + { + SteamUniverses = new List(); + + File.ReadAllLines(SteamConfig).Do(l => + { + if (!l.Contains("BaseInstallFolder_")) return; + var s = GetVdfValue(l); + s = Path.Combine(s, "steamapps"); + if (!Directory.Exists(s)) + { + Utils.Log($"Directory {s} does not exist, skipping"); + return; + } + + SteamUniverses.Add(s); + Utils.Log($"Steam Library found at {s}"); + }); + + Utils.Log($"Total number of Steam Libraries found: {SteamUniverses.Count}"); + + // Default path in the Steam folder isn't in the configs + if(Directory.Exists(Path.Combine(SteamPath, "steamapps"))) + SteamUniverses.Add(Path.Combine(SteamPath, "steamapps")); + } + + public override bool LoadAllGames() + { + if(SteamUniverses == null) + LoadUniverses(); + + if (SteamUniverses.Count == 0) + { + Utils.Log("Could not find any Steam Libraries!"); + return false; + } + + SteamUniverses.Do(u => + { + Directory.EnumerateFiles(u, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f => + { + var game = new SteamGame(); + var valid = false; + + File.ReadAllLines(f).Do(l => + { + if (l.Contains("\"appid\"")) + { + if (!int.TryParse(GetVdfValue(l), out var id)) + return; + game.ID = id; + } + + if (l.Contains("\"name\"")) + game.Name = GetVdfValue(l); + + if (l.Contains("\"installdir\"")) + { + var path = Path.Combine(u, "common", GetVdfValue(l)); + if (Directory.Exists(path)) + game.Path = path; + else + return; + } + + valid = true; + }); + + if (!valid) return; + + var gameMeta = GameRegistry.Games.Values.FirstOrDefault(g => + g.SteamIDs.Contains(game.ID) + && + g.RequiredFiles.TrueForAll(file => + File.Exists(Path.Combine(game.Path, file)))); + + if (gameMeta == null) + return; + + game.Game = gameMeta.Game; + game.Universe = u; + + Utils.Log($"Found Steam Game: \"{game.Name}\"({game.ID}) at {game.Path}"); + + LoadWorkshopItems(game); + + Games.Add(game); + }); + }); + + Utils.Log($"Total number of Steam Games found: {Games.Count}"); + + return true; + } + + private void LoadWorkshopItems(SteamGame game) + { + if(game.WorkshopItems == null) + game.WorkshopItems = new List(); + + var workshop = Path.Combine(game.Universe, "workshop"); + if (!Directory.Exists(workshop)) + return; + + Directory.EnumerateFiles(workshop, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f => + { + if (Path.GetFileName(f) != $"appworkshop{game.ID}.acf") + return; + + Utils.Log($"Found workshop item file {f} for \"{game.Name}\""); + + var lines = File.ReadAllLines(f); + var end = false; + var foundAppID = false; + var workshopItemsInstalled = 0; + var workshopItemDetails = 0; + var bracketStart = 0; + var bracketEnd = 0; + + var currentItem = new SteamWorkshopItem(); + + lines.Do(l => + { + if (end) + return; + if(currentItem == null) + currentItem = new SteamWorkshopItem(); + + var currentLine = lines.IndexOf(l); + if (l.Contains("\"appid\"") && !foundAppID) + { + if (!int.TryParse(GetVdfValue(l), out var appID)) + return; + + foundAppID = true; + + if (appID != game.ID) + return; + } + + if (!foundAppID) + return; + + if (l.Contains("\"SizeOnDisk\"")) + { + if (!int.TryParse(GetVdfValue(l), out var sizeOnDisk)) + return; + + game.WorkshopItemsSize += sizeOnDisk; + } + + if (l.Contains("\"WorkshopItemsInstalled\"")) + workshopItemsInstalled = currentLine; + + if (l.Contains("\"WorkshopItemDetails\"")) + workshopItemDetails = currentLine; + + if (workshopItemsInstalled == 0) + return; + + if (currentLine <= workshopItemsInstalled + 1 && currentLine >= workshopItemDetails - 1) + return; + + if (currentItem.ItemID == 0) + if (!int.TryParse(GetSingleVdfValue(l), out currentItem.ItemID)) + return; + + if (currentItem.ItemID == 0) + return; + + if (bracketStart == 0 && l.Contains("{")) + bracketStart = currentLine; + + if (bracketEnd == 0 && l.Contains("}")) + bracketEnd = currentLine; + + if (bracketStart == 0) + return; + + if (currentLine == bracketStart + 1) + if (!int.TryParse(GetVdfValue(l), out currentItem.Size)) + return; + + if (bracketStart == 0 || bracketEnd == 0 || currentItem.ItemID == 0 || currentItem.Size == 0) + return; + + bracketStart = 0; + bracketEnd = 0; + currentItem.Game = game; + game.WorkshopItems.Add(currentItem); + + Utils.Log($"Found WorkshopItem {currentItem.ItemID}"); + + currentItem = null; + end = true; + }); + }); + } + + private static string GetVdfValue(string line) + { + var trim = line.Trim('\t').Replace("\t", ""); + string[] s = trim.Split('\"'); + return s[3].Replace("\\\\", "\\"); + } + + private static string GetSingleVdfValue(string line) + { + var trim = line.Trim('\t').Replace("\t", ""); + return trim.Split('\"')[1]; + } + } +} diff --git a/Wabbajack.Common/StoreHandlers/StoreHandler.cs b/Wabbajack.Common/StoreHandlers/StoreHandler.cs new file mode 100644 index 00000000..b303553e --- /dev/null +++ b/Wabbajack.Common/StoreHandlers/StoreHandler.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Wabbajack.Common.StoreHandlers +{ + public enum StoreType + { + STEAM, + GOG + } + + public class StoreHandler + { + private static readonly Lazy instance = new Lazy(() => new StoreHandler(), true); + public static StoreHandler Instance => instance.Value; + + private static readonly Lazy _steamHandler = new Lazy(() => new SteamHandler()); + public SteamHandler SteamHandler = _steamHandler.Value; + + private static readonly Lazy _gogHandler = new Lazy(() => new GOGHandler()); + public GOGHandler GOGHandler = _gogHandler.Value; + + public List StoreGames; + + public StoreHandler() + { + StoreGames = new List(); + + if (SteamHandler.Init()) + { + if(SteamHandler.LoadAllGames()) + StoreGames.AddRange(SteamHandler.Games); + else + Utils.Error(new StoreException("Could not load all Games from the SteamHandler, check previous error messages!")); + } + else + { + Utils.Error(new StoreException("Could not Init the SteamHandler, check previous error messages!")); + } + + if (GOGHandler.Init()) + { + if(GOGHandler.LoadAllGames()) + StoreGames.AddRange(GOGHandler.Games); + else + Utils.Error(new StoreException("Could not load all Games from the GOGHandler, check previous error messages!")); + } + else + { + Utils.Error(new StoreException("Could not Init the GOGHandler, check previous error messages!")); + } + } + + public string GetGamePath(Game game) + { + return StoreGames.FirstOrDefault(g => g.Game == game)?.Path; + } + + public string GetGamePath(int id) + { + return StoreGames.FirstOrDefault(g => g.ID == id)?.Path; + } + } + + public abstract class AStoreGame + { + public abstract Game Game { get; internal set; } + public abstract string Name { get; internal set; } + public abstract string Path { get; internal set; } + public abstract int ID { get; internal set; } + public abstract StoreType Type { get; internal set; } + } + + public abstract class AStoreHandler + { + public abstract List Games { get; set; } + + public abstract StoreType Type { get; internal set; } + + public abstract bool Init(); + + public abstract bool LoadAllGames(); + } + + public class StoreException : Exception + { + public StoreException(string msg) : base(msg) + { + + } + } +} From 259863458dccda14e08b03d74ee7eafae2244f00 Mon Sep 17 00:00:00 2001 From: erri120 Date: Fri, 3 Jan 2020 18:22:30 +0100 Subject: [PATCH 2/4] Bug fixes --- Wabbajack.Common/StoreHandlers/GOGHandler.cs | 12 +++++++++++- Wabbajack.Common/StoreHandlers/SteamHandler.cs | 5 ++++- Wabbajack.Common/StoreHandlers/StoreHandler.cs | 5 +++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Wabbajack.Common/StoreHandlers/GOGHandler.cs b/Wabbajack.Common/StoreHandlers/GOGHandler.cs index 70d9e9e2..2bebd135 100644 --- a/Wabbajack.Common/StoreHandlers/GOGHandler.cs +++ b/Wabbajack.Common/StoreHandlers/GOGHandler.cs @@ -56,6 +56,9 @@ namespace Wabbajack.Common.StoreHandlers public override bool LoadAllGames() { + if(Games == null) + Games = new List(); + try { string[] keys = GOGKey.GetSubKeyNames(); @@ -94,9 +97,16 @@ namespace Wabbajack.Common.StoreHandlers var path = pathValue.ToString(); - var game = new GOGGame() {ID = gameID, Name = gameName, Path = path}; + var game = new GOGGame + { + ID = gameID, + Name = gameName, + Path = path + }; var gameMeta = GameRegistry.Games.Values.FirstOrDefault(g => + g.GOGIDs != null + && g.GOGIDs.Contains(game.ID) && g.RequiredFiles.TrueForAll(file => diff --git a/Wabbajack.Common/StoreHandlers/SteamHandler.cs b/Wabbajack.Common/StoreHandlers/SteamHandler.cs index f7bbb2e5..e412f552 100644 --- a/Wabbajack.Common/StoreHandlers/SteamHandler.cs +++ b/Wabbajack.Common/StoreHandlers/SteamHandler.cs @@ -36,7 +36,7 @@ namespace Wabbajack.Common.StoreHandlers private const string SteamRegKey = @"Software\Valve\Steam"; - private string SteamPath { get; set; } + public string SteamPath { get; set; } private List SteamUniverses { get; set; } private string SteamConfig => Path.Combine(SteamPath, "config", "config.vdf"); @@ -123,6 +123,9 @@ namespace Wabbajack.Common.StoreHandlers return false; } + if(Games == null) + Games = new List(); + SteamUniverses.Do(u => { Directory.EnumerateFiles(u, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f => diff --git a/Wabbajack.Common/StoreHandlers/StoreHandler.cs b/Wabbajack.Common/StoreHandlers/StoreHandler.cs index b303553e..a644bb4b 100644 --- a/Wabbajack.Common/StoreHandlers/StoreHandler.cs +++ b/Wabbajack.Common/StoreHandlers/StoreHandler.cs @@ -57,6 +57,11 @@ namespace Wabbajack.Common.StoreHandlers return StoreGames.FirstOrDefault(g => g.Game == game)?.Path; } + public string GetGamePath(Game game, StoreType type) + { + return StoreGames.FirstOrDefault(g => g.Type == type && g.Game == game)?.Path; + } + public string GetGamePath(int id) { return StoreGames.FirstOrDefault(g => g.ID == id)?.Path; From 2643c499c247d241fe641b44b58efe8953ea111d Mon Sep 17 00:00:00 2001 From: erri120 Date: Fri, 3 Jan 2020 18:22:50 +0100 Subject: [PATCH 3/4] Replaced old Steam/GOG Handlers with the new StoreHandler system --- Wabbajack.Common/GOGHandler.cs | 124 -------- Wabbajack.Common/GameMetaData.cs | 7 +- Wabbajack.Common/SteamHandler.cs | 278 ------------------ .../IncludeSteamWorkshopItems.cs | 1 + .../Downloaders/SteamWorkshopDownloader.cs | 12 +- Wabbajack.Lib/VortexCompiler.cs | 8 +- Wabbajack.Lib/VortexInstaller.cs | 7 +- .../View Models/Compilers/VortexCompilerVM.cs | 8 +- 8 files changed, 21 insertions(+), 424 deletions(-) delete mode 100644 Wabbajack.Common/GOGHandler.cs delete mode 100644 Wabbajack.Common/SteamHandler.cs diff --git a/Wabbajack.Common/GOGHandler.cs b/Wabbajack.Common/GOGHandler.cs deleted file mode 100644 index 4a3a4f57..00000000 --- a/Wabbajack.Common/GOGHandler.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Win32; - -namespace Wabbajack.Common -{ - public class GOGGame - { - public int GameID; - public string Path; - public string GameName; - public Game? Game; - } - - /// - /// Class for all GOG operations - /// - public class GOGHandler - { - private static readonly Lazy instance = new Lazy( - () => new GOGHandler(true), - isThreadSafe: true); - public static GOGHandler Instance => instance.Value; - - private const string GOGRegKey = @"Software\GOG.com\Games"; - private const string GOG64RegKey = @"Software\WOW6432Node\GOG.com\Games"; - - public HashSet Games { get; internal set; } - public RegistryKey GOGKey { get; internal set; } - - public GOGHandler(bool init) - { - var gogKey = Registry.LocalMachine.OpenSubKey(GOGRegKey) ?? Registry.LocalMachine.OpenSubKey(GOG64RegKey); - if (gogKey == null) - { - Utils.ErrorThrow(new Exception("Could not find GOG in registry!")); - } - else - { - Utils.Log($"GOG registry key is ${gogKey}"); - GOGKey = gogKey; - if (!init) return; - LoadAllGames(); - } - } - - /// - /// Finds the installation path of a GOG game by ID - /// - /// ID of the GOG game - /// - public string GetGamePathById(int id) - { - return Games.FirstOrDefault(f => f.GameID == id)?.Path; - } - - /// - /// Enumerates through all subkeys found in the GOG registry entry to get all - /// GOG games - /// - public void LoadAllGames() - { - Games = new HashSet(); - if (GOGKey == null) return; - string[] keys = GOGKey.GetSubKeyNames(); - Utils.Log($"Found {keys.Length} SubKeys for GOG"); - foreach (var key in keys) - { - if (!int.TryParse(key, out var gameID)) - { - Utils.ErrorThrow(new Exception($"Could not read gameID for key {key}")); - } - - var subKey = GOGKey.OpenSubKey(key); - if (subKey == null) - { - Utils.ErrorThrow(new Exception($"Could not open SubKey for {key}")); - return; - } - - var gameNameValue = subKey.GetValue("GAMENAME"); - if (gameNameValue == null) - { - Utils.ErrorThrow(new Exception($"Could not get GAMENAME for {gameID} at {key}")); - return; - } - - var gameName = gameNameValue.ToString(); - - var pathValue = subKey.GetValue("PATH"); - if (pathValue == null) - { - Utils.ErrorThrow(new Exception($"Could not get PATH for {gameID} at {key}")); - return; - } - - var path = pathValue.ToString(); - - - var game = new GOGGame - { - GameID = gameID, - GameName = gameName, - Path = path - }; - - Utils.Log($"Found GOG Game: {gameName}({gameID}) at {path}"); - - game.Game = GameRegistry.Games.Values - .FirstOrDefault(g => g.GOGIDs != null && g.GOGIDs.Contains(game.GameID) - && - g.RequiredFiles.TrueForAll(s => File.Exists(Path.Combine(game.Path, s))))?.Game; - - if (game.Game == null) - { - Utils.Log("Found no matching game, continuing"); - } - Games.Add(game); - } - } - } -} diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index b89f50ac..fb09fb3e 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Linq; using Alphaleonis.Win32.Filesystem; using Microsoft.Win32; +using Wabbajack.Common.StoreHandlers; namespace Wabbajack.Common { @@ -71,11 +72,7 @@ namespace Wabbajack.Common public string GameLocation() { - if (Consts.TestMode) - return Directory.GetCurrentDirectory(); - - return SteamHandler.Instance.Games.FirstOrDefault(g => g.Game == Game)?.InstallDir ?? - GOGHandler.Instance.Games.FirstOrDefault(g => g.Game == Game)?.Path; + return Consts.TestMode ? Directory.GetCurrentDirectory() : StoreHandler.Instance.GetGamePath(Game); } } diff --git a/Wabbajack.Common/SteamHandler.cs b/Wabbajack.Common/SteamHandler.cs deleted file mode 100644 index 86c60e31..00000000 --- a/Wabbajack.Common/SteamHandler.cs +++ /dev/null @@ -1,278 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using DynamicData; -using Microsoft.Win32; - -namespace Wabbajack.Common -{ - [DebuggerDisplay("{" + nameof(Name) + "}")] - public class SteamGame - { - public int AppId; - public string Name; - public string InstallDir; - public Game? Game; - - public HashSet WorkshopItems; - /// - /// Combined size of all installed workshop items on disk in bytes - /// - public int WorkshopItemsSize; - } - - public class SteamWorkshopItem - { - public SteamGame Game; - public int ItemID; - /// - /// Size is in bytes - /// - public int Size; - } - - /// - /// 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(string.IsNullOrWhiteSpace(SteamPath) || steamKey == null || !Directory.Exists(SteamPath)) - Utils.ErrorThrow(new Exception("Could not find the Steam folder!")); - 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"); - if (!Directory.Exists(s)) - return; - - paths.Add(s); - Utils.Log($"Steam Library found at {s}"); - }); - - Utils.Log($"Total number of Steam Libraries found: {paths.Count}"); - - // Default path in the Steam folder isn't in the configs - if(Directory.Exists(Path.Combine(SteamPath, "steamapps"))) - paths.Add(Path.Combine(SteamPath, "steamapps")); - - 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).Where(File.Exists).Do(f => - { - var steamGame = new SteamGame(); - var valid = false; - File.ReadAllLines(f, Encoding.UTF8).Do(l => - { - if(l.Contains("\"appid\"")) - if (!int.TryParse(GetVdfValue(l), out steamGame.AppId)) - return; - if(l.Contains("\"name\"")) - steamGame.Name = GetVdfValue(l); - if (l.Contains("\"installdir\"")) - { - var path = Path.Combine(p, "common", GetVdfValue(l)); - steamGame.InstallDir = Directory.Exists(path) ? path : null; - } - - if (steamGame.AppId != 0 && !string.IsNullOrWhiteSpace(steamGame.Name) && - !string.IsNullOrWhiteSpace(steamGame.InstallDir)) - valid = true; - }); - - if (!valid) - return; - - 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); - - Utils.Log($"Found Game: {steamGame.Name} ({steamGame.AppId}) at {steamGame.InstallDir}"); - }); - }); - - Utils.Log($"Total number of Steam Games found: {games.Count}"); - - Games = games; - } - - public void LoadWorkshopItems(SteamGame game) - { - if(game.WorkshopItems == null) - game.WorkshopItems = new HashSet(); - - InstallFolders.Do(p => - { - var workshop = Path.Combine(p, "workshop"); - if(!Directory.Exists(workshop)) - return; - - Directory.EnumerateFiles(workshop, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f => - { - if (Path.GetFileName(f) != $"appworkshop_{game.AppId}.acf") - return; - - var foundAppID = false; - var workshopItemsInstalled = 0; - var workshopItemDetails = 0; - var currentItem = new SteamWorkshopItem(); - var bracketStart = 0; - var bracketEnd = 0; - var lines = File.ReadAllLines(f, Encoding.UTF8); - var end = false; - lines.Do(l => - { - if (end) - return; - if(currentItem == null) - currentItem = new SteamWorkshopItem(); - - var currentLine = lines.IndexOf(l); - if (l.Contains("\"appid\"") && !foundAppID) - { - if (!int.TryParse(GetVdfValue(l), out var appID)) - return; - - foundAppID = true; - - if (appID != game.AppId) - return; - } - - if (!foundAppID) - return; - - if (l.Contains("\"SizeOnDisk\"")) - { - if (!int.TryParse(GetVdfValue(l), out var sizeOnDisk)) - return; - - game.WorkshopItemsSize = sizeOnDisk; - } - - if (l.Contains("\"WorkshopItemsInstalled\"")) - workshopItemsInstalled = currentLine; - - if (l.Contains("\"WorkshopItemDetails\"")) - workshopItemDetails = currentLine; - - if (workshopItemsInstalled == 0) - return; - - if (currentLine <= workshopItemsInstalled + 1 && currentLine >= workshopItemDetails - 1) - return; - - if (currentItem.ItemID == 0) - if (!int.TryParse(GetSingleVdfValue(l), out currentItem.ItemID)) - return; - - if (currentItem.ItemID == 0) - return; - - if (bracketStart == 0 && l.Contains("{")) - bracketStart = currentLine; - - if (bracketEnd == 0 && l.Contains("}")) - bracketEnd = currentLine; - - if (bracketStart == 0) - return; - - if (currentLine == bracketStart + 1) - if (!int.TryParse(GetVdfValue(l), out currentItem.Size)) - return; - - if (bracketStart == 0 || bracketEnd == 0 || currentItem.ItemID == 0 || currentItem.Size == 0) - return; - - bracketStart = 0; - bracketEnd = 0; - currentItem.Game = game; - game.WorkshopItems.Add(currentItem); - currentItem = null; - end = true; - }); - }); - }); - } - - private static string GetVdfValue(string line) - { - var trim = line.Trim('\t').Replace("\t", ""); - string[] s = trim.Split('\"'); - return s[3].Replace("\\\\", "\\"); - } - - private static string GetSingleVdfValue(string line) - { - var trim = line.Trim('\t').Replace("\t", ""); - return trim.Split('\"')[1]; - } - } -} diff --git a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs index 1e891328..5b2a15c4 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; +using Wabbajack.Common.StoreHandlers; namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs b/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs index dc871383..73ebf912 100644 --- a/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs +++ b/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Wabbajack.Common; +using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib.Validation; namespace Wabbajack.Lib.Downloaders @@ -50,18 +51,17 @@ namespace Wabbajack.Lib.Downloaders public override async Task Download(Archive a, string destination) { - var currentLib = ""; - SteamHandler.Instance.InstallFolders.Where(f => f.Contains(Item.Game.InstallDir)).Do(s => currentLib = s); + var currentLib = Item.Game.Universe; - var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", Item.Game.AppId.ToString()); - var contentFolder = Path.Combine(currentLib, "workshop", "content", Item.Game.AppId.ToString()); + var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", Item.Game.ID.ToString()); + var contentFolder = Path.Combine(currentLib, "workshop", "content", Item.Game.ID.ToString()); var p = new Process { StartInfo = new ProcessStartInfo { - FileName = Path.Combine(SteamHandler.Instance.SteamPath, "steam.exe"), + FileName = Path.Combine(StoreHandler.Instance.SteamHandler.SteamPath, "steam.exe"), CreateNoWindow = true, - Arguments = $"console +workshop_download_item {Item.Game.AppId} {Item.ItemID}" + Arguments = $"console +workshop_download_item {Item.Game.ID} {Item.ItemID}" } }; diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index ac7e9f6a..833510e2 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -9,6 +9,7 @@ using System.Threading; using Microsoft.WindowsAPICodePack.Shell; using Newtonsoft.Json; using Wabbajack.Common; +using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib.CompilationSteps; using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; @@ -70,11 +71,10 @@ namespace Wabbajack.Lib ActiveArchives = new List(); // there can be max one game after filtering - SteamHandler.Instance.Games.Where(g => g.Game != null && g.Game == game).Do(g => + StoreHandler.Instance.StoreGames.Where(g => g.Game == game && g.Type == StoreType.STEAM).Do(g => { _isSteamGame = true; - _steamGame = g; - SteamHandler.Instance.LoadWorkshopItems(_steamGame); + _steamGame = (SteamGame)g; _hasSteamWorkshopItems = _steamGame.WorkshopItems.Count > 0; }); } @@ -431,7 +431,7 @@ namespace Wabbajack.Lib var metaString = "[General]\n" + "repository=Steam\n" + $"gameName={GameName}\n" + - $"steamID={_steamGame.AppId}\n" + + $"steamID={_steamGame.ID}\n" + $"itemID={item.ItemID}\n" + $"itemSize={item.Size}\n"; try diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index 438bd44a..fad6aeeb 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System.Threading; using System.Windows; using Wabbajack.Common; +using Wabbajack.Common.StoreHandlers; using Directory = Alphaleonis.Win32.Filesystem.Directory; using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; using File = Alphaleonis.Win32.Filesystem.File; @@ -157,7 +158,7 @@ namespace Wabbajack.Lib { //var currentLib = ""; SteamGame currentSteamGame = null; - SteamHandler.Instance.Games.Where(g => g.Game == GameInfo.Game).Do(s => currentSteamGame = s); + StoreHandler.Instance.SteamHandler.Games.Where(g => g.Game == GameInfo.Game).Do(s => currentSteamGame = (SteamGame)s); /*SteamHandler.Instance.InstallFolders.Where(f => f.Contains(currentSteamGame.InstallDir)).Do(s => currentLib = s); var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", currentSteamGame.AppId.ToString()); @@ -188,9 +189,9 @@ namespace Wabbajack.Lib { StartInfo = new ProcessStartInfo { - FileName = System.IO.Path.Combine(SteamHandler.Instance.SteamPath, "steam.exe"), + FileName = Path.Combine(StoreHandler.Instance.SteamHandler.SteamPath, "steam.exe"), CreateNoWindow = true, - Arguments = $"console +workshop_download_item {currentSteamGame.AppId} {item.ItemID}" + Arguments = $"console +workshop_download_item {currentSteamGame.ID} {currentSteamGame.ID}" } }; diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs index 2e9136d2..848706c5 100644 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs @@ -9,7 +9,9 @@ using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Wabbajack.Common; +using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib; +using GOGHandler = Wabbajack.Common.GOGHandler; namespace Wabbajack { @@ -172,14 +174,12 @@ namespace Wabbajack private void SetGameToSteamLocation() { - var steamGame = SteamHandler.Instance.Games.FirstOrDefault(g => g.Game.HasValue && g.Game == SelectedGame.Game); - GameLocation.TargetPath = steamGame?.InstallDir; + GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.STEAM); } private void SetGameToGogLocation() { - var gogGame = GOGHandler.Instance.Games.FirstOrDefault(g => g.Game.HasValue && g.Game == SelectedGame.Game); - GameLocation.TargetPath = gogGame?.Path; + GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.GOG); } public async Task Compile() From b6ed45945e05edcce7953aa85260df9345d1120c Mon Sep 17 00:00:00 2001 From: erri120 Date: Fri, 3 Jan 2020 18:27:09 +0100 Subject: [PATCH 4/4] Fixed unused import --- Wabbajack/View Models/Compilers/VortexCompilerVM.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs index 848706c5..30718b10 100644 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs @@ -11,7 +11,6 @@ using ReactiveUI.Fody.Helpers; using Wabbajack.Common; using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib; -using GOGHandler = Wabbajack.Common.GOGHandler; namespace Wabbajack {