mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge pull request #738 from erri120/morrowind-bethnet
StoreHandler Mini-rework
This commit is contained in:
commit
310f680f8f
@ -4,8 +4,6 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Microsoft.Win32;
|
||||
using Wabbajack.Common.StoreHandlers;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
@ -28,28 +26,9 @@ namespace Wabbajack.Common
|
||||
Fallout4,
|
||||
[Description("Skyrim VR")]
|
||||
SkyrimVR,
|
||||
//VORTEX GAMES
|
||||
[Description("Darkest Dungeon")]
|
||||
DarkestDungeon,
|
||||
[Description("Divinity Original Sin 2")]
|
||||
DivinityOriginalSin2,
|
||||
[Description("Divinity Original Sin 2 Definitive Edition")]
|
||||
DivinityOriginalSin2DE, //definitive edition has its own nexus page but same Steam/GOG ids
|
||||
Starbound,
|
||||
[Description("Star Wars: Knights of the Old Republic")]
|
||||
SWKOTOR,
|
||||
[Description("Star Wars: Knights of the Old Republic 2")]
|
||||
SWKOTOR2,
|
||||
Witcher,
|
||||
[Description("Witcher 2")]
|
||||
Witcher2,
|
||||
[Description("Witcher 3")]
|
||||
Witcher3,
|
||||
[Description("Stardew Valley")]
|
||||
StardewValley
|
||||
}
|
||||
|
||||
public static class GameExtentions
|
||||
public static class GameExtensions
|
||||
{
|
||||
public static GameMetaData MetaData(this Game game)
|
||||
{
|
||||
@ -59,30 +38,36 @@ namespace Wabbajack.Common
|
||||
|
||||
public class GameMetaData
|
||||
{
|
||||
public ModManager SupportedModManager { get; internal set; }
|
||||
public string? MO2ArchiveName { get; internal set; }
|
||||
public Game Game { get; internal set; }
|
||||
public ModManager SupportedModManager { get; internal set; }
|
||||
|
||||
public string? MO2ArchiveName { get; internal set; }
|
||||
public string? NexusName { get; internal set; }
|
||||
// Nexus DB id for the game, used in some specific situations
|
||||
public long NexusGameId { get; internal set; }
|
||||
public string? MO2Name { get; internal set; }
|
||||
|
||||
public string HumanFriendlyGameName => Game.GetDescription();
|
||||
|
||||
public string? GameLocationRegistryKey { get; internal set; }
|
||||
// to get steam ids: https://steamdb.info
|
||||
public List<int>? SteamIDs { get; internal set; }
|
||||
|
||||
// to get gog ids: https://www.gogdb.org
|
||||
public List<int>? GOGIDs { get; internal set; }
|
||||
// these are additional folders when a game installs mods outside the game folder
|
||||
public List<string>? AdditionalFolders { get; internal set; }
|
||||
|
||||
// to get BethNet IDs: check the registry
|
||||
public int BethNetID { get; internal set; }
|
||||
//for BethNet games only!
|
||||
public string RegString { get; internal set; } = string.Empty;
|
||||
|
||||
// file to check if the game is present, useful when steamIds and gogIds dont help
|
||||
public List<string>? RequiredFiles { get; internal set; }
|
||||
public bool Disabled { get; internal set; }
|
||||
|
||||
public string? MainExecutable { get; internal set; }
|
||||
|
||||
// Games that this game are commonly confused with, for example Skyrim SE vs Skyrim LE
|
||||
public Game[] CommonlyConfusedWith { get; set; } = Array.Empty<Game>();
|
||||
|
||||
|
||||
public string HumanFriendlyGameName => Game.GetDescription();
|
||||
|
||||
public string InstalledVersion
|
||||
{
|
||||
get
|
||||
@ -98,8 +83,6 @@ namespace Wabbajack.Common
|
||||
|
||||
public bool IsInstalled => TryGetGameLocation() != null;
|
||||
|
||||
public string? MainExecutable { get; internal set; }
|
||||
|
||||
public AbsolutePath? TryGetGameLocation()
|
||||
{
|
||||
return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.TryGetGamePath(Game);
|
||||
@ -113,11 +96,9 @@ namespace Wabbajack.Common
|
||||
path = ret.Value;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
path = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public AbsolutePath GameLocation()
|
||||
@ -146,16 +127,12 @@ namespace Wabbajack.Common
|
||||
throw new ArgumentException($"{nameof(enumerationValue)} must be of Enum type", nameof(enumerationValue));
|
||||
}
|
||||
var memberInfo = type.GetMember(enumerationValue.ToString()!);
|
||||
if(memberInfo.Length > 0)
|
||||
{
|
||||
var attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
if (memberInfo.Length <= 0)
|
||||
return enumerationValue.ToString()!;
|
||||
|
||||
if(attrs.Length > 0)
|
||||
{
|
||||
return ((DescriptionAttribute)attrs[0]).Description;
|
||||
}
|
||||
}
|
||||
return enumerationValue.ToString()!;
|
||||
var attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
|
||||
return attrs.Length > 0 ? ((DescriptionAttribute)attrs[0]).Description : enumerationValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,8 +140,8 @@ namespace Wabbajack.Common
|
||||
{
|
||||
public static GameMetaData GetByMO2ArchiveName(string gameName)
|
||||
{
|
||||
var gamename = gameName.ToLower();
|
||||
return Games.Values.FirstOrDefault(g => g.MO2ArchiveName?.ToLower() == gamename);
|
||||
gameName = gameName.ToLower();
|
||||
return Games.Values.FirstOrDefault(g => g.MO2ArchiveName?.ToLower() == gameName);
|
||||
}
|
||||
|
||||
public static GameMetaData GetByNexusName(string gameName)
|
||||
@ -183,6 +160,7 @@ namespace Wabbajack.Common
|
||||
/// <param nambe="someName">Name to query</param>
|
||||
/// <returns>GameMetaData found</returns>
|
||||
/// <exception cref="ArgumentNullException">If string could not be translated to a game</exception>
|
||||
/// </summary>
|
||||
public static GameMetaData GetByFuzzyName(string someName)
|
||||
{
|
||||
return TryGetByFuzzyName(someName) ?? throw new ArgumentNullException($"{someName} could not be translated to a game");
|
||||
@ -192,6 +170,7 @@ namespace Wabbajack.Common
|
||||
/// Tries to parse game data from an arbitrary string. Tries first via parsing as a game Enum, then by Nexus name.
|
||||
/// <param nambe="someName">Name to query</param>
|
||||
/// <returns>GameMetaData if found, otherwise null</returns>
|
||||
/// </summary>
|
||||
public static GameMetaData? TryGetByFuzzyName(string someName)
|
||||
{
|
||||
if (Enum.TryParse(typeof(Game), someName, true, out var metadata)) return ((Game)metadata!).MetaData();
|
||||
@ -225,13 +204,14 @@ namespace Wabbajack.Common
|
||||
{
|
||||
SupportedModManager = ModManager.MO2,
|
||||
Game = Game.Morrowind,
|
||||
Disabled = false,
|
||||
SteamIDs = new List<int>{22320},
|
||||
GOGIDs = new List<int>{1440163901, 1435828767},
|
||||
NexusName = "morrowind",
|
||||
NexusGameId = 100,
|
||||
MO2Name = "Morrowind",
|
||||
MO2ArchiveName = "morrowind",
|
||||
BethNetID = 31,
|
||||
RegString = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\The Elder Scrolls III: Morrowind Game of the Year Edition",
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"Morrowind.exe"
|
||||
@ -248,7 +228,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 101,
|
||||
MO2Name = "Oblivion",
|
||||
MO2ArchiveName = "oblivion",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Oblivion",
|
||||
SteamIDs = new List<int> {22330},
|
||||
GOGIDs = new List<int>{1458058109},
|
||||
RequiredFiles = new List<string>
|
||||
@ -268,7 +247,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 120,
|
||||
MO2Name = "fallout3",
|
||||
MO2ArchiveName = "fallout3",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Fallout3",
|
||||
SteamIDs = new List<int> {22300, 22370}, // base game and GotY
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
@ -287,7 +265,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 130,
|
||||
MO2Name = "New Vegas",
|
||||
MO2ArchiveName = "falloutnv",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\falloutnv",
|
||||
SteamIDs = new List<int> {22380, 22490}, // normal and RU version
|
||||
GOGIDs = new List<int>{1454587428},
|
||||
RequiredFiles = new List<string>
|
||||
@ -306,7 +283,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 110,
|
||||
MO2Name = "Skyrim",
|
||||
MO2ArchiveName = "skyrim",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\skyrim",
|
||||
SteamIDs = new List<int> {72850},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
@ -325,7 +301,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 1704,
|
||||
MO2Name = "Skyrim Special Edition",
|
||||
MO2ArchiveName = "skyrimse",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Skyrim Special Edition",
|
||||
SteamIDs = new List<int> {489830},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
@ -344,7 +319,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 1151,
|
||||
MO2Name = "Fallout 4",
|
||||
MO2ArchiveName = "fallout4",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Fallout4",
|
||||
SteamIDs = new List<int> {377160},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
@ -353,17 +327,6 @@ namespace Wabbajack.Common
|
||||
MainExecutable = "Fallout4.exe"
|
||||
}
|
||||
},
|
||||
/*{
|
||||
Game.Fallout4VR, new GameMetaData
|
||||
{
|
||||
SupportedModManager = ModManager.MO2,
|
||||
Game = Game.Fallout4VR,
|
||||
NexusName = "fallout4",
|
||||
MO2Name = "Fallout 4",
|
||||
MO2ArchiveName = "fallout4",
|
||||
SteamIDs = new List<int>{611660}
|
||||
}
|
||||
},*/
|
||||
{
|
||||
Game.SkyrimVR, new GameMetaData
|
||||
{
|
||||
@ -373,7 +336,6 @@ namespace Wabbajack.Common
|
||||
NexusGameId = 1704,
|
||||
MO2Name = "Skyrim VR",
|
||||
MO2ArchiveName = "skyrimse",
|
||||
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Skyrim VR",
|
||||
SteamIDs = new List<int> {611670},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
@ -383,155 +345,6 @@ namespace Wabbajack.Common
|
||||
CommonlyConfusedWith = new []{Game.Skyrim, Game.SkyrimSpecialEdition}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.DarkestDungeon, new GameMetaData
|
||||
{
|
||||
Game = Game.DarkestDungeon,
|
||||
NexusName = "darkestdungeon",
|
||||
NexusGameId = 804,
|
||||
SteamIDs = new List<int> {262060},
|
||||
GOGIDs = new List<int>{1450711444},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"_windows\\Darkest.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.DivinityOriginalSin2DE, new GameMetaData
|
||||
{
|
||||
Game = Game.DivinityOriginalSin2DE,
|
||||
NexusName = "divinityoriginalsin2definitiveedition",
|
||||
NexusGameId = 2569,
|
||||
SteamIDs = new List<int> {435150},
|
||||
GOGIDs = new List<int>{1584823040},
|
||||
AdditionalFolders = new List<string>
|
||||
{
|
||||
"%documents%\\Larian Studios\\Divinity Original Sin 2 Definitive Edition\\Mods\\"
|
||||
},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"DefEd\\bin\\SupportTool.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.DivinityOriginalSin2, new GameMetaData
|
||||
{
|
||||
Game = Game.DivinityOriginalSin2,
|
||||
NexusName = "divinityoriginalsin2",
|
||||
NexusGameId = 1661,
|
||||
SteamIDs = new List<int> {435150},
|
||||
GOGIDs = new List<int>{1584823040},
|
||||
AdditionalFolders = new List<string>
|
||||
{
|
||||
"%documents%\\Larian Studios\\Divinity Original Sin 2\\Mods\\",
|
||||
},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"bin\\SupportTool.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.Starbound, new GameMetaData
|
||||
{
|
||||
Game = Game.Starbound,
|
||||
NexusName = "starbound",
|
||||
NexusGameId = 242,
|
||||
SteamIDs = new List<int>{211820},
|
||||
GOGIDs = new List<int>{1452598881},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"win64\\starbound.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.SWKOTOR, new GameMetaData
|
||||
{
|
||||
Game = Game.SWKOTOR,
|
||||
NexusName = "kotor",
|
||||
NexusGameId = 234,
|
||||
SteamIDs = new List<int>{32370},
|
||||
GOGIDs = new List<int>{1207666283},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"swkotor.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.SWKOTOR2, new GameMetaData
|
||||
{
|
||||
Game = Game.SWKOTOR2,
|
||||
NexusName = "kotor2",
|
||||
NexusGameId = 198,
|
||||
SteamIDs = new List<int>{208580},
|
||||
GOGIDs = new List<int>{1421404581},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"swkotor2.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.Witcher, new GameMetaData
|
||||
{
|
||||
Game = Game.Witcher,
|
||||
NexusName = "witcher",
|
||||
NexusGameId = 150,
|
||||
SteamIDs = new List<int>{20900},
|
||||
GOGIDs = new List<int>{1207658924},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"system\\witcher.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.Witcher2, new GameMetaData
|
||||
{
|
||||
Game = Game.Witcher2,
|
||||
NexusName = "witcher2",
|
||||
NexusGameId = 153,
|
||||
SteamIDs = new List<int>{20920},
|
||||
GOGIDs = new List<int>{1207658930},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"bin\\witcher2.exe",
|
||||
"bin\\userContentManager.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.Witcher3, new GameMetaData
|
||||
{
|
||||
Game = Game.Witcher3,
|
||||
NexusName = "witcher3",
|
||||
NexusGameId = 952,
|
||||
SteamIDs = new List<int>{292030, 499450}, // normal and GotY
|
||||
GOGIDs = new List<int>{1207664643, 1495134320, 1207664663, 1640424747}, // normal, GotY and both in packages
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"bin\\x64\\witcher2.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.StardewValley, new GameMetaData
|
||||
{
|
||||
Game = Game.StardewValley,
|
||||
NexusName = "stardewvalley",
|
||||
NexusGameId = 1303,
|
||||
SteamIDs = new List<int>{413150},
|
||||
GOGIDs = new List<int>{1453375253},
|
||||
RequiredFiles = new List<string>
|
||||
{
|
||||
"Stardew Valley.exe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Game.Enderal, new GameMetaData
|
||||
{
|
||||
|
@ -220,12 +220,13 @@ namespace Wabbajack.Common
|
||||
/// Assuming the path is a folder, enumerate all the files in the folder
|
||||
/// </summary>
|
||||
/// <param name="recursive">if true, also returns files in sub-folders</param>
|
||||
/// <param name="pattern">pattern to match against</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<AbsolutePath> EnumerateFiles(bool recursive = true)
|
||||
public IEnumerable<AbsolutePath> EnumerateFiles(bool recursive = true, string pattern = "*")
|
||||
{
|
||||
if (!IsDirectory) return new AbsolutePath[0];
|
||||
return Directory
|
||||
.EnumerateFiles(_path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
|
||||
.EnumerateFiles(_path, pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
|
||||
.Select(path => new AbsolutePath(path, true));
|
||||
}
|
||||
|
||||
|
210
Wabbajack.Common/StoreHandlers/BethNetHandler.cs
Normal file
210
Wabbajack.Common/StoreHandlers/BethNetHandler.cs
Normal file
@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using Microsoft.Win32;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
public class BethNetGame : AStoreGame
|
||||
{
|
||||
public override Game Game { get; internal set; }
|
||||
public override StoreType Type { get; internal set; } = StoreType.BethNet;
|
||||
}
|
||||
|
||||
public class BethNetHandler : AStoreHandler
|
||||
{
|
||||
public override StoreType Type { get; internal set; } = StoreType.BethNet;
|
||||
|
||||
private const string RegKey = @"SOFTWARE\WOW6432Node\bethesda softworks\Bethesda.net";
|
||||
|
||||
public AbsolutePath BethPath { get; set; }
|
||||
private AbsolutePath Launcher => new RelativePath("BethesdaNetLauncher.exe").RelativeTo(BethPath);
|
||||
private AbsolutePath GamesFolder => new RelativePath("games").RelativeTo(BethPath);
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = Registry.LocalMachine.OpenSubKey(RegKey);
|
||||
|
||||
var pathKey = key?.GetValue("installLocation");
|
||||
if (pathKey == null)
|
||||
{
|
||||
Utils.Error(new StoreException("Could not open the BethNetPath registry key!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
var bethPath = pathKey.ToString() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(bethPath))
|
||||
{
|
||||
Utils.Error(new StoreException("Path to the BethNet Directory from registry is Null or Empty!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
BethPath = (AbsolutePath)bethPath;
|
||||
|
||||
if (!BethPath.IsDirectory || !BethPath.Exists)
|
||||
{
|
||||
Utils.Error(new StoreException($"Path to the BethNet Directory from registry does not exists: {BethPath}"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Launcher.Exists && Launcher.IsFile)
|
||||
return true;
|
||||
|
||||
Utils.Error(new StoreException($"The BethNet Launcher could not be located: {Launcher}"));
|
||||
return false;
|
||||
}
|
||||
catch (SecurityException se)
|
||||
{
|
||||
Utils.Error(se, "BethNetHandler could not read from registry!");
|
||||
}
|
||||
catch (UnauthorizedAccessException uae)
|
||||
{
|
||||
Utils.Error(uae, "BethNetHandler could not read from registry!");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool LoadAllGames()
|
||||
{
|
||||
List<BethNetGame> possibleGames = new List<BethNetGame>();
|
||||
// games folder
|
||||
|
||||
if (!GamesFolder.Exists)
|
||||
{
|
||||
Utils.Error(new StoreException($"The GamesFolder for BethNet at {GamesFolder} does not exist!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GamesFolder.Exists && GamesFolder.IsDirectory)
|
||||
{
|
||||
GamesFolder.EnumerateDirectories(false).Do(d =>
|
||||
{
|
||||
var files = d.EnumerateFiles();
|
||||
var game = GameRegistry.Games.Values
|
||||
.FirstOrDefault(g => g.RequiredFiles.All(f =>
|
||||
{
|
||||
var absPath = new RelativePath(f).RelativeTo(d);
|
||||
return files.Contains(absPath);
|
||||
}));
|
||||
|
||||
if (game != null)
|
||||
{
|
||||
possibleGames.Add(new BethNetGame
|
||||
{
|
||||
Game = game.Game,
|
||||
ID = game.BethNetID,
|
||||
Name = game.Game.ToString(),
|
||||
Path = d,
|
||||
Type = StoreType.BethNet
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.Log($"BethNet Game at {d} is not supported!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
possibleGames.Do(g =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var regString = g.Game.MetaData().RegString;
|
||||
var regKey = Registry.LocalMachine.OpenSubKey(regString);
|
||||
regString = @"HKEY_LOCAL_MACHINE\" + regString;
|
||||
if (regKey == null)
|
||||
{
|
||||
Utils.Error(new StoreException($@"Could not open registry key at {regString}"));
|
||||
return;
|
||||
}
|
||||
|
||||
var pathValue = regKey.GetValue("Path");
|
||||
var uninstallStringValue = regKey.GetValue("UninstallString");
|
||||
|
||||
if (pathValue == null || uninstallStringValue == null)
|
||||
{
|
||||
Utils.Error(new StoreException($@"Could not get Value from either {regString}\Path or UninstallString"));
|
||||
return;
|
||||
}
|
||||
|
||||
var path = pathValue.ToString() ?? string.Empty;
|
||||
var uninstallString = uninstallStringValue.ToString() ?? string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(uninstallString))
|
||||
{
|
||||
Utils.Error(new StoreException($@"Path or UninstallString is null or empty for {regString}!"));
|
||||
return;
|
||||
}
|
||||
|
||||
path = FixRegistryValue(path);
|
||||
|
||||
if ((AbsolutePath)path != g.Path)
|
||||
{
|
||||
Utils.Error(new StoreException($"Path from registry does not equal game path: {path} != {g.Path} at {regString}"));
|
||||
return;
|
||||
}
|
||||
|
||||
var split = uninstallString.Split("\"");
|
||||
if (split.Length != 3)
|
||||
{
|
||||
Utils.Error(new StoreException($"UninstallString at {regString} can not be split into 3 parts!"));
|
||||
return;
|
||||
}
|
||||
|
||||
var updaterPath = (AbsolutePath)split[1];
|
||||
var args = split[2].Trim();
|
||||
|
||||
if (!updaterPath.Exists)
|
||||
{
|
||||
Utils.Error(new StoreException($"UpdaterPath from {regString} does not exist at {updaterPath}"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (updaterPath.Parent != BethPath)
|
||||
{
|
||||
Utils.Error(new StoreException($"Parent of UpdatePath from {regString} is not BethPath: {updaterPath.Parent} != {BethPath}"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.Equals($"bethesdanet://uninstall/{g.ID}", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
Utils.Error(new StoreException($"Uninstall arguments from {regString} is not valid: {args}"));
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.Log($"Found BethNet game \"{g.Game}\" ({g.ID}) at {g.Path}");
|
||||
|
||||
Games.Add(g);
|
||||
}
|
||||
catch (SecurityException se)
|
||||
{
|
||||
Utils.Error(se, "BethNetHandler could not read from registry!");
|
||||
}
|
||||
catch (UnauthorizedAccessException uae)
|
||||
{
|
||||
Utils.Error(uae, "BethNetHandler could not read from registry!");
|
||||
}
|
||||
});
|
||||
|
||||
Utils.Log($"Total number of BethNet Games found: {Games.Count}");
|
||||
|
||||
return Games.Count != 0;
|
||||
}
|
||||
|
||||
private static string FixRegistryValue(string value)
|
||||
{
|
||||
var s = value;
|
||||
if (s.StartsWith("\""))
|
||||
s = s[1..];
|
||||
if (s.EndsWith("\""))
|
||||
s = s[..^1];
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using Microsoft.Win32;
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using DynamicData;
|
||||
using Microsoft.Win32;
|
||||
#nullable enable
|
||||
|
||||
@ -14,7 +12,7 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
public override Game Game { get; internal set; }
|
||||
public override StoreType Type { get; internal set; } = StoreType.STEAM;
|
||||
|
||||
public string Universe = string.Empty;
|
||||
public AbsolutePath Universe;
|
||||
|
||||
public readonly List<SteamWorkshopItem> WorkshopItems = new List<SteamWorkshopItem>();
|
||||
public int WorkshopItemsSizeOnDisk;
|
||||
@ -38,10 +36,9 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
|
||||
private const string SteamRegKey = @"Software\Valve\Steam";
|
||||
|
||||
public string SteamPath { get; set; } = string.Empty;
|
||||
private List<string>? SteamUniverses { get; set; }
|
||||
|
||||
private string SteamConfig => Path.Combine(SteamPath, "config", "config.vdf");
|
||||
public AbsolutePath SteamPath { get; set; }
|
||||
private AbsolutePath SteamConfig => new RelativePath("config//config.vdf").RelativeTo(SteamPath);
|
||||
private List<AbsolutePath>? SteamUniverses { get; set; }
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
@ -56,20 +53,22 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
return false;
|
||||
}
|
||||
|
||||
SteamPath = steamPathKey.ToString() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(SteamPath))
|
||||
var steamPath = steamPathKey.ToString() ?? string.Empty;
|
||||
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))
|
||||
SteamPath = new AbsolutePath(steamPath);
|
||||
|
||||
if (!SteamPath.Exists)
|
||||
{
|
||||
Utils.Error(new StoreException($"Path to the Steam Directory from registry does not exists: {SteamPath}"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (File.Exists(SteamConfig))
|
||||
if (SteamConfig.Exists)
|
||||
return true;
|
||||
|
||||
Utils.Error(new StoreException($"The Steam config file could not be read: {SteamConfig}"));
|
||||
@ -88,38 +87,39 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<string> LoadUniverses()
|
||||
private List<AbsolutePath> LoadUniverses()
|
||||
{
|
||||
var ret = new List<string>();
|
||||
var ret = new List<AbsolutePath>();
|
||||
|
||||
File.ReadAllLines(SteamConfig).Do(l =>
|
||||
SteamConfig.ReadAllLines().Do(l =>
|
||||
{
|
||||
if (!l.ContainsCaseInsensitive("BaseInstallFolder_")) return;
|
||||
var s = GetVdfValue(l);
|
||||
s = Path.Combine(s, "steamapps");
|
||||
if (!Directory.Exists(s))
|
||||
var s = new AbsolutePath(GetVdfValue(l));
|
||||
var path = new RelativePath("steamapps").RelativeTo(s);
|
||||
|
||||
if (!path.Exists)
|
||||
{
|
||||
Utils.Log($"Directory {s} does not exist, skipping");
|
||||
Utils.Log($"Directory {path} does not exist, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
ret.Add(s);
|
||||
Utils.Log($"Steam Library found at {s}");
|
||||
ret.Add(path);
|
||||
Utils.Log($"Steam Library found at {path}");
|
||||
});
|
||||
|
||||
Utils.Log($"Total number of Steam Libraries found: {ret.Count}");
|
||||
|
||||
// Default path in the Steam folder isn't in the configs
|
||||
if (Directory.Exists(Path.Combine(SteamPath, "steamapps")))
|
||||
ret.Add(Path.Combine(SteamPath, "steamapps"));
|
||||
var defaultPath = new RelativePath("steamapps").RelativeTo(SteamPath);
|
||||
if(defaultPath.Exists)
|
||||
ret.Add(defaultPath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override bool LoadAllGames()
|
||||
{
|
||||
if (SteamUniverses == null)
|
||||
SteamUniverses = LoadUniverses();
|
||||
SteamUniverses ??= LoadUniverses();
|
||||
|
||||
if (SteamUniverses.Count == 0)
|
||||
{
|
||||
@ -131,12 +131,15 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
Utils.Log($"Searching for Steam Games in {u}");
|
||||
|
||||
Directory.EnumerateFiles(u, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f =>
|
||||
u.EnumerateFiles(false, "*.acf")
|
||||
.Where(a => a.Exists)
|
||||
.Where(a => a.IsFile)
|
||||
.Do(f =>
|
||||
{
|
||||
var game = new SteamGame();
|
||||
var gotID = false;
|
||||
|
||||
File.ReadAllLines(f).Do(l =>
|
||||
f.ReadAllLines().Do(l =>
|
||||
{
|
||||
if (l.ContainsCaseInsensitive("\"appid\""))
|
||||
{
|
||||
@ -152,9 +155,9 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
if (!l.ContainsCaseInsensitive("\"installdir\""))
|
||||
return;
|
||||
|
||||
var path = Path.Combine(u, "common", GetVdfValue(l));
|
||||
if (Directory.Exists(path))
|
||||
game.Path = (AbsolutePath)path;
|
||||
var path = new RelativePath($"common//{GetVdfValue(l)}").RelativeTo(u);
|
||||
if (path.Exists)
|
||||
game.Path = path;
|
||||
});
|
||||
|
||||
if (!gotID || !game.Path.IsDirectory) return;
|
||||
@ -189,18 +192,21 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
|
||||
private static void LoadWorkshopItems(SteamGame game)
|
||||
{
|
||||
var workshop = Path.Combine(game.Universe, "workshop");
|
||||
if (!Directory.Exists(workshop))
|
||||
var workshop = new RelativePath("workshop").RelativeTo(game.Universe);
|
||||
if (!workshop.Exists)
|
||||
return;
|
||||
|
||||
Directory.EnumerateFiles(workshop, "*.acf", SearchOption.TopDirectoryOnly).Where(File.Exists).Do(f =>
|
||||
workshop.EnumerateFiles(false, "*.acf")
|
||||
.Where(f => f.Exists)
|
||||
.Where(f => f.IsFile)
|
||||
.Do(f =>
|
||||
{
|
||||
if (Path.GetFileName(f) != $"appworkshop{game.ID}.acf")
|
||||
if (f.FileName.ToString() != $"appworkshop{game.ID}.acf")
|
||||
return;
|
||||
|
||||
Utils.Log($"Found Steam Workshop item file {f} for \"{game.Name}\"");
|
||||
|
||||
var lines = File.ReadAllLines(f);
|
||||
var lines = f.ReadAllLines().ToList();
|
||||
var end = false;
|
||||
var foundAppID = false;
|
||||
var workshopItemsInstalled = 0;
|
||||
@ -214,8 +220,8 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
if (end)
|
||||
return;
|
||||
if (currentItem == null)
|
||||
currentItem = new SteamWorkshopItem(game);
|
||||
|
||||
currentItem ??= new SteamWorkshopItem(game);
|
||||
|
||||
var currentLine = lines.IndexOf(l);
|
||||
if (l.ContainsCaseInsensitive("\"appid\"") && !foundAppID)
|
||||
|
@ -7,13 +7,14 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
public enum StoreType
|
||||
{
|
||||
STEAM,
|
||||
GOG
|
||||
GOG,
|
||||
BethNet
|
||||
}
|
||||
|
||||
public class StoreHandler
|
||||
{
|
||||
private static readonly Lazy<StoreHandler> instance = new Lazy<StoreHandler>(() => new StoreHandler(), true);
|
||||
public static StoreHandler Instance => instance.Value;
|
||||
private static readonly Lazy<StoreHandler> _instance = new Lazy<StoreHandler>(() => new StoreHandler(), true);
|
||||
public static StoreHandler Instance => _instance.Value;
|
||||
|
||||
private static readonly Lazy<SteamHandler> _steamHandler = new Lazy<SteamHandler>(() => new SteamHandler());
|
||||
public SteamHandler SteamHandler = _steamHandler.Value;
|
||||
@ -21,6 +22,9 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
private static readonly Lazy<GOGHandler> _gogHandler = new Lazy<GOGHandler>(() => new GOGHandler());
|
||||
public GOGHandler GOGHandler = _gogHandler.Value;
|
||||
|
||||
private static readonly Lazy<BethNetHandler> _bethNetHandler = new Lazy<BethNetHandler>(() => new BethNetHandler());
|
||||
public BethNetHandler BethNetHandler = _bethNetHandler.Value;
|
||||
|
||||
public List<AStoreGame> StoreGames;
|
||||
|
||||
public StoreHandler()
|
||||
@ -50,6 +54,18 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
Utils.Error(new StoreException("Could not Init the GOGHandler, check previous error messages!"));
|
||||
}
|
||||
|
||||
if (BethNetHandler.Init())
|
||||
{
|
||||
if (BethNetHandler.LoadAllGames())
|
||||
StoreGames.AddRange(BethNetHandler.Games);
|
||||
else
|
||||
Utils.Error(new StoreException("Could not load all Games from the BethNetHandler, check previous error messages!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.Error(new StoreException("Could not Init the BethNetHandler, check previous error messages!"));
|
||||
}
|
||||
}
|
||||
|
||||
public AbsolutePath? TryGetGamePath(Game game)
|
||||
|
@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
@ -60,13 +57,13 @@ namespace Wabbajack.Lib.Downloaders
|
||||
{
|
||||
var currentLib = Item.Game.Universe;
|
||||
|
||||
var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", Item.Game.ID.ToString());
|
||||
var contentFolder = Path.Combine(currentLib, "workshop", "content", Item.Game.ID.ToString());
|
||||
var downloadFolder = new RelativePath($"workshop//downloads//{Item.Game.ID}").RelativeTo(currentLib);
|
||||
var contentFolder = new RelativePath($"workshop//content//{Item.Game.ID}").RelativeTo(currentLib);
|
||||
var p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(StoreHandler.Instance.SteamHandler.SteamPath, "steam.exe"),
|
||||
FileName = new RelativePath("steam.exe").RelativeTo(StoreHandler.Instance.SteamHandler.SteamPath).ToString(),
|
||||
CreateNoWindow = true,
|
||||
Arguments = $"console +workshop_download_item {Item.Game.ID} {Item.ItemID}"
|
||||
}
|
||||
@ -76,10 +73,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
//TODO: async
|
||||
var finished = false;
|
||||
var itemDownloadPath = new RelativePath(Item.ItemID.ToString()).RelativeTo(downloadFolder);
|
||||
var itemContentPath = new RelativePath(Item.ItemID.ToString()).RelativeTo(contentFolder);
|
||||
while (!finished)
|
||||
{
|
||||
if(!Directory.Exists(Path.Combine(downloadFolder, Item.ItemID.ToString())))
|
||||
if (Directory.Exists(Path.Combine(contentFolder, Item.ItemID.ToString())))
|
||||
if(!itemDownloadPath.Exists)
|
||||
if(itemContentPath.Exists)
|
||||
finished = true;
|
||||
|
||||
Thread.Sleep(1000);
|
||||
|
@ -8,6 +8,7 @@ using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StoreHandlers;
|
||||
using Wabbajack.Util;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -24,6 +25,7 @@ namespace Wabbajack
|
||||
CLIOld.ParseOptions(Environment.GetCommandLineArgs());
|
||||
if (CLIArguments.Help)
|
||||
CLIOld.DisplayHelpText();
|
||||
var storeHandler = new StoreHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user