Replaced old Steam/GOG Handlers with the new StoreHandler system

This commit is contained in:
erri120 2020-01-03 18:22:50 +01:00
parent 259863458d
commit 2643c499c2
No known key found for this signature in database
GPG Key ID: A8C0A18D8D4D3135
8 changed files with 21 additions and 424 deletions

View File

@ -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;
}
/// <summary>
/// Class for all GOG operations
/// </summary>
public class GOGHandler
{
private static readonly Lazy<GOGHandler> instance = new Lazy<GOGHandler>(
() => 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<GOGGame> 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();
}
}
/// <summary>
/// Finds the installation path of a GOG game by ID
/// </summary>
/// <param name="id">ID of the GOG game</param>
/// <returns></returns>
public string GetGamePathById(int id)
{
return Games.FirstOrDefault(f => f.GameID == id)?.Path;
}
/// <summary>
/// Enumerates through all subkeys found in the GOG registry entry to get all
/// GOG games
/// </summary>
public void LoadAllGames()
{
Games = new HashSet<GOGGame>();
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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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<SteamWorkshopItem> WorkshopItems;
/// <summary>
/// Combined size of all installed workshop items on disk in bytes
/// </summary>
public int WorkshopItemsSize;
}
public class SteamWorkshopItem
{
public SteamGame Game;
public int ItemID;
/// <summary>
/// Size is in bytes
/// </summary>
public int Size;
}
/// <summary>
/// Class for all Steam operations
/// </summary>
public class SteamHandler
{
private static readonly Lazy<SteamHandler> instance = new Lazy<SteamHandler>(
() => new SteamHandler(true),
isThreadSafe: true);
public static SteamHandler Instance => instance.Value;
private const string SteamRegKey = @"Software\Valve\Steam";
/// <summary>
/// Path to the Steam folder
/// </summary>
public string SteamPath { get; internal set; }
/// <summary>
/// HashSet of all known Steam Libraries
/// </summary>
public HashSet<string> InstallFolders { get; internal set; }
/// <summary>
/// HashSet of all known SteamGames
/// </summary>
public HashSet<SteamGame> 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();
}
/// <summary>
/// Finds the installation path of a Steam game by ID
/// </summary>
/// <param name="id">ID of the Steam game</param>
/// <returns></returns>
public string GetGamePathById(int id)
{
return Games.FirstOrDefault(f => f.AppId == id)?.InstallDir;
}
/// <summary>
/// Reads the config file and adds all found installation folders to the HashSet
/// </summary>
public void LoadInstallFolders()
{
var paths = new HashSet<string>();
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;
}
/// <summary>
/// Enumerates through all Steam Libraries to find and read all .afc files, adding the found game
/// to the HashSet
/// </summary>
public void LoadAllSteamGames()
{
var games = new HashSet<SteamGame>();
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<SteamWorkshopItem>();
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];
}
}
}

View File

@ -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
{

View File

@ -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}"
}
};

View File

@ -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<string>();
// 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

View File

@ -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}"
}
};

View File

@ -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()