2022-10-15 17:18:22 +00:00
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using GameFinder.RegistryUtils;
|
2021-09-27 12:42:46 +00:00
|
|
|
using GameFinder.StoreHandlers.EGS;
|
|
|
|
using GameFinder.StoreHandlers.GOG;
|
|
|
|
using GameFinder.StoreHandlers.Origin;
|
|
|
|
using GameFinder.StoreHandlers.Steam;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
using Wabbajack.DTOs;
|
|
|
|
using Wabbajack.Paths;
|
2022-10-15 17:18:22 +00:00
|
|
|
using Wabbajack.Paths.IO;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Downloaders.GameFile;
|
|
|
|
|
|
|
|
public class GameLocator : IGameLocator
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2022-10-15 17:18:22 +00:00
|
|
|
private readonly SteamHandler _steam;
|
2021-10-24 04:39:57 +00:00
|
|
|
private readonly GOGHandler? _gog;
|
2022-10-15 17:18:22 +00:00
|
|
|
private readonly EGSHandler? _egs;
|
|
|
|
private readonly OriginHandler? _origin;
|
|
|
|
|
|
|
|
private readonly Dictionary<int, AbsolutePath> _steamGames = new();
|
|
|
|
private readonly Dictionary<long, AbsolutePath> _gogGames = new();
|
|
|
|
private readonly Dictionary<string, AbsolutePath> _egsGames = new();
|
|
|
|
private readonly Dictionary<string, AbsolutePath> _originGames = new();
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
private readonly Dictionary<Game, AbsolutePath> _locationCache;
|
|
|
|
private readonly ILogger<GameLocator> _logger;
|
|
|
|
|
|
|
|
public GameLocator(ILogger<GameLocator> logger)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
_logger = logger;
|
|
|
|
|
2022-10-15 17:18:22 +00:00
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
{
|
|
|
|
var windowsRegistry = new WindowsRegistry();
|
|
|
|
|
|
|
|
_steam = new SteamHandler(windowsRegistry);
|
|
|
|
_gog = new GOGHandler(windowsRegistry);
|
|
|
|
_egs = new EGSHandler(windowsRegistry);
|
|
|
|
_origin = new OriginHandler();
|
|
|
|
}
|
|
|
|
else
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2022-10-15 17:18:22 +00:00
|
|
|
_steam = new SteamHandler(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
_locationCache = new Dictionary<Game, AbsolutePath>();
|
|
|
|
|
|
|
|
FindAllGames();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void FindAllGames()
|
|
|
|
{
|
|
|
|
FindStoreGames(_steam.FindAllGames(), _steamGames,
|
|
|
|
steamGame => steamGame.Path,
|
|
|
|
steamGame => steamGame.AppId);
|
2021-10-16 20:51:25 +00:00
|
|
|
|
2022-10-15 17:18:22 +00:00
|
|
|
if (_gog is not null)
|
|
|
|
{
|
|
|
|
FindStoreGames(_gog.FindAllGames(), _gogGames,
|
|
|
|
gogGame => gogGame.Path,
|
|
|
|
gogGame => gogGame.Id);
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2022-10-15 17:18:22 +00:00
|
|
|
if (_egs is not null)
|
|
|
|
{
|
|
|
|
FindStoreGames(_egs.FindAllGames(), _egsGames,
|
|
|
|
egsGame => egsGame.InstallLocation,
|
|
|
|
egsGame => egsGame.CatalogItemId);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2022-10-15 17:18:22 +00:00
|
|
|
if (_origin is not null)
|
|
|
|
{
|
|
|
|
FindStoreGames(_origin.FindAllGames(), _originGames,
|
|
|
|
originGame => originGame.InstallPath,
|
|
|
|
originGame => originGame.Id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void FindStoreGames<TGame, TId>(
|
|
|
|
IEnumerable<(TGame? game, string? error)> games,
|
|
|
|
IDictionary<TId, AbsolutePath> paths,
|
|
|
|
Func<TGame, string> getPath,
|
|
|
|
Func<TGame, TId> getId)
|
|
|
|
where TGame : class
|
|
|
|
{
|
|
|
|
foreach (var (game, error) in games)
|
|
|
|
{
|
2022-10-19 18:28:59 +00:00
|
|
|
try
|
2022-10-15 17:18:22 +00:00
|
|
|
{
|
2022-10-19 18:28:59 +00:00
|
|
|
if (game is not null)
|
2022-10-15 17:18:22 +00:00
|
|
|
{
|
2022-10-19 18:28:59 +00:00
|
|
|
var path = getPath(game).ToAbsolutePath();
|
|
|
|
if (path.DirectoryExists())
|
|
|
|
{
|
|
|
|
paths[getId(game)] = path;
|
|
|
|
_logger.LogDebug("Found Game {} at {}", game, path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_logger.LogError("Game {} does not exist at {}", game, path);
|
|
|
|
}
|
2022-10-15 17:18:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-10-19 18:28:59 +00:00
|
|
|
_logger.LogError("{}", error);
|
2022-10-15 17:18:22 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-19 18:28:59 +00:00
|
|
|
catch (Exception ex)
|
2022-10-15 17:18:22 +00:00
|
|
|
{
|
2022-10-19 18:28:59 +00:00
|
|
|
_logger.LogError(ex, "While locating game {Game}", game);
|
2022-10-15 17:18:22 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public AbsolutePath GameLocation(Game game)
|
|
|
|
{
|
|
|
|
if (TryFindLocation(game, out var path))
|
|
|
|
return path;
|
|
|
|
throw new Exception($"Can't find game {game}");
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsInstalled(Game game)
|
|
|
|
{
|
|
|
|
return TryFindLocation(game, out _);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool TryFindLocation(Game game, out AbsolutePath path)
|
|
|
|
{
|
|
|
|
lock (_locationCache)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
if (_locationCache.TryGetValue(game, out path))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (TryFindLocationInner(game, out path))
|
|
|
|
{
|
|
|
|
_locationCache.Add(game, path);
|
|
|
|
return true;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool TryFindLocationInner(Game game, out AbsolutePath path)
|
|
|
|
{
|
|
|
|
var metaData = game.MetaData();
|
2022-10-15 17:18:22 +00:00
|
|
|
|
2022-10-19 17:28:07 +00:00
|
|
|
try
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2022-10-19 17:28:07 +00:00
|
|
|
foreach (var id in metaData.SteamIDs)
|
|
|
|
{
|
|
|
|
if (!_steamGames.TryGetValue(id, out var found)) continue;
|
|
|
|
path = found;
|
|
|
|
return true;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2022-10-19 17:28:07 +00:00
|
|
|
catch (Exception ex)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2022-10-19 17:28:07 +00:00
|
|
|
_logger.LogInformation(ex, "During Steam detection");
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2022-10-18 04:48:49 +00:00
|
|
|
|
2022-10-19 17:28:07 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
foreach (var id in metaData.GOGIDs)
|
|
|
|
{
|
|
|
|
if (!_gogGames.TryGetValue(id, out var found)) continue;
|
|
|
|
path = found;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2022-10-19 17:28:07 +00:00
|
|
|
_logger.LogInformation(ex, "During GOG detection");
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2022-10-18 04:48:49 +00:00
|
|
|
|
2022-10-19 17:28:07 +00:00
|
|
|
|
|
|
|
try
|
2021-10-24 04:39:57 +00:00
|
|
|
{
|
2022-10-19 17:28:07 +00:00
|
|
|
foreach (var id in metaData.EpicGameStoreIDs)
|
|
|
|
{
|
|
|
|
if (!_egsGames.TryGetValue(id, out var found)) continue;
|
|
|
|
path = found;
|
|
|
|
return true;
|
|
|
|
}
|
2021-10-24 04:39:57 +00:00
|
|
|
}
|
2022-10-19 17:28:07 +00:00
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
_logger.LogInformation(ex, "During Epic detection");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
foreach (var id in metaData.OriginIDs)
|
|
|
|
{
|
|
|
|
if (!_originGames.TryGetValue(id, out var found)) continue;
|
|
|
|
path = found;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
_logger.LogInformation(ex, "During Origin Store detection");
|
|
|
|
}
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
path = default;
|
|
|
|
return false;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
}
|