[WIP] Refactor Gamelibraries singleton pattern

Moved from basic static class to proper thread
safe singleton pattern for the GameLibrary to
simplify the code in ShortcutRepository.

Still only halfway through that ShortcutRepository
code refactor :(
This commit is contained in:
Terry MacDonald 2021-04-18 21:44:52 +12:00
parent 1e4ed0c546
commit 4c46c6315d
7 changed files with 547 additions and 179 deletions

View File

@ -95,6 +95,7 @@
<Compile Include="DesktopNotificationActivator.cs" />
<Compile Include="DesktopNotificationManagerCompat.cs" />
<Compile Include="GameLibraries\Game.cs" />
<Compile Include="GameLibraries\GameLibrary.cs" />
<Compile Include="GameLibraries\GameUtils.cs" />
<Compile Include="GameLibraries\SteamAppInfoParser\AppInfo.cs" />
<Compile Include="GameLibraries\SteamAppInfoParser\EUniverse.cs" />

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DisplayMagician.GameLibraries
{
public class GameLibrary
{
public enum SupportedGameLibraryType
{
Unknown,
Origin,
Steam,
Ubiconnect
}
public struct GameAppInfo
{
public string GameID;
public string GameName;
public string GameExePath;
public string GameInstallDir;
public string GameIconPath;
}
#region Class Properties
public virtual List<Game> AllInstalledGames { get; set; }
public virtual int InstalledGameCount { get; set; }
public virtual string GameLibraryName { get; set; }
public virtual SupportedGameLibraryType GameLibraryType { get; set; }
public virtual string GameLibraryExe { get; set; }
public virtual string GameLibraryPath { get; set; }
public virtual bool IsGameLibraryInstalled { get; set; }
#endregion
#region Class Methods
public virtual bool AddGame(Game game)
{
return false;
}
public virtual bool RemoveGame(Game game)
{
return false;
}
public virtual bool RemoveGameById(string gameId)
{
return false;
}
public virtual bool RemoveGame(string gameNameOrId)
{
return false;
}
public virtual bool ContainsGame(Game game)
{
return false;
}
public virtual bool ContainsGameById(string gameId)
{
return false;
}
public virtual bool ContainsGame(string gameNameOrId)
{
return false;
}
public virtual Game GetGame(string gameNameOrId)
{
return null;
}
public virtual Game GetGameById(string gameId)
{
return null;
}
public virtual bool LoadInstalledGames()
{
return false;
}
#endregion
}
[global::System.Serializable]
public class GameLibraryException : Exception
{
public GameLibraryException() { }
public GameLibraryException(string message) : base(message) { }
public GameLibraryException(string message, Exception inner) : base(message, inner) { }
protected GameLibraryException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@ -12,38 +12,35 @@ using System.Web;
namespace DisplayMagician.GameLibraries
{
public static class OriginLibrary
public sealed class OriginLibrary : GameLibrary
{
#region Class Variables
// Common items to the class
private static List<Game> _allOriginGames = new List<Game>();
private static string OriginAppIdRegex = @"/^[0-9A-F]{1,10}$";
private static string _originExe;
private static string _originPath;
private static string _originLocalContent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Origin");
private static bool _isOriginInstalled = false;
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static readonly OriginLibrary _instance = new OriginLibrary();
//private static string _originConfigVdfFile;
internal static string registryOriginLauncherKey = @"SOFTWARE\WOW6432Node\Origin";
//internal static string registryOriginInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
//internal static string registryOriginOpenCmdKey = @"SOFTWARE\Classes\Origin\Shell\Open\Command";
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Common items to the class
private List<Game> _allOriginGames = new List<Game>();
private string OriginAppIdRegex = @"/^[0-9A-F]{1,10}$";
private string _originExe;
private string _originPath;
private string _originLocalContent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Origin");
private bool _isOriginInstalled = false;
//private string _originConfigVdfFile;
internal string registryOriginLauncherKey = @"SOFTWARE\WOW6432Node\Origin";
//internal string registryOriginInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
//internal string registryOriginOpenCmdKey = @"SOFTWARE\Classes\Origin\Shell\Open\Command";
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
private struct OriginAppInfo
{
public string GameID;
public string GameName;
public string GameExePath;
public string GameInstallDir;
public string GameOriginIconPath;
}
#endregion
#region Class Constructors
static OriginLibrary()
private OriginLibrary()
{
try
{
@ -86,7 +83,7 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Properties
public static List<Game> AllInstalledGames
public override List<Game> AllInstalledGames
{
get
{
@ -98,7 +95,7 @@ namespace DisplayMagician.GameLibraries
}
public static int InstalledOriginGameCount
public override int InstalledGameCount
{
get
{
@ -106,7 +103,23 @@ namespace DisplayMagician.GameLibraries
}
}
public static string OriginExe
public override string GameLibraryName
{
get
{
return "Origin";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Origin;
}
}
public override string GameLibraryExe
{
get
{
@ -114,7 +127,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string OriginPath
public override string GameLibraryPath
{
get
{
@ -122,7 +135,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static bool IsOriginInstalled
public override bool IsGameLibraryInstalled
{
get
{
@ -135,18 +148,24 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Methods
public static bool AddOriginGame(OriginGame originGame)
public static OriginLibrary GetLibrary()
{
return _instance;
}
public bool AddGame(OriginGame originGame)
{
if (!(originGame is OriginGame))
return false;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if (ContainsOriginGame(originGame))
if (ContainsGame(originGame))
{
logger.Debug($"OriginLibrary/AddOriginGame: Updating Origin game {originGame.Name} in our Origin library");
// We update the existing Shortcut with the data over
OriginGame originGameToUpdate = GetOriginGame(originGame.Id.ToString());
OriginGame originGameToUpdate = GetGame(originGame.Id.ToString());
originGame.CopyTo(originGameToUpdate);
}
else
@ -157,7 +176,7 @@ namespace DisplayMagician.GameLibraries
}
//Doublecheck it's been added
if (ContainsOriginGame(originGame))
if (ContainsGame(originGame))
{
return true;
}
@ -166,7 +185,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveOriginGame(OriginGame originGame)
public bool RemoveGame(OriginGame originGame)
{
if (!(originGame is OriginGame))
return false;
@ -190,7 +209,7 @@ namespace DisplayMagician.GameLibraries
throw new OriginLibraryException();
}
public static bool RemoveOriginGameById(string originGameId)
public override bool RemoveGameById(string originGameId)
{
if (originGameId.Equals(0))
return false;
@ -214,7 +233,7 @@ namespace DisplayMagician.GameLibraries
throw new OriginLibraryException();
}
public static bool RemoveOriginGame(string originGameNameOrId)
public override bool RemoveGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return false;
@ -243,7 +262,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsOriginGame(OriginGame originGame)
public bool ContainsGame(OriginGame originGame)
{
if (!(originGame is OriginGame))
return false;
@ -257,7 +276,7 @@ namespace DisplayMagician.GameLibraries
return false;
}
public static bool ContainsOriginGameById(string originGameId)
public override bool ContainsGameById(string originGameId)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
@ -270,7 +289,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsOriginGame(string originGameNameOrId)
public override bool ContainsGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return false;
@ -301,7 +320,7 @@ namespace DisplayMagician.GameLibraries
}
public static OriginGame GetOriginGame(string originGameNameOrId)
public OriginGame GetGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return null;
@ -330,7 +349,7 @@ namespace DisplayMagician.GameLibraries
}
public static OriginGame GetOriginGameById(string originGameId)
public OriginGame GetGameById(string originGameId)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
@ -342,7 +361,7 @@ namespace DisplayMagician.GameLibraries
}
private static Dictionary<string, string> ParseOriginManifest(string path)
private Dictionary<string, string> ParseOriginManifest(string path)
{
string encodedContents = File.ReadAllText(path);
Dictionary<string, string> parameters = Regex.Matches(encodedContents, "([^?=&]+)(=([^&]*))?").Cast<Match>().ToDictionary(x => x.Groups[1].Value, x => x.Groups[3].Value);
@ -350,7 +369,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool LoadInstalledGames()
public override bool LoadInstalledGames()
{
try
{
@ -372,7 +391,7 @@ namespace DisplayMagician.GameLibraries
{
try
{
OriginAppInfo originGame = new OriginAppInfo();
GameAppInfo originGame = new GameAppInfo();
originGame.GameID = Path.GetFileNameWithoutExtension(package);
if (!originGame.GameID.StartsWith("Origin"))
{
@ -546,10 +565,10 @@ namespace DisplayMagician.GameLibraries
}
// TODO check for icon! For now we will just use the exe one
originGame.GameOriginIconPath = originGame.GameExePath;
originGame.GameIconPath = originGame.GameExePath;
// If we reach here we add the Game to the list of games we have!
_allOriginGames.Add(new OriginGame(originGame.GameID, originGame.GameName, originGame.GameExePath, originGame.GameOriginIconPath));
_allOriginGames.Add(new OriginGame(originGame.GameID, originGame.GameName, originGame.GameExePath, originGame.GameIconPath));
}
else
@ -662,7 +681,7 @@ namespace DisplayMagician.GameLibraries
}
[global::System.Serializable]
public class OriginLibraryException : Exception
public class OriginLibraryException : GameLibraryException
{
public OriginLibraryException() { }
public OriginLibraryException(string message) : base(message) { }

View File

@ -11,21 +11,8 @@ using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public static class SteamLibrary
public sealed class SteamLibrary : GameLibrary
{
#region Class Variables
// Common items to the class
private static List<Game> _allSteamGames = new List<Game>();
private static string steamAppIdRegex = @"/^[0-9A-F]{1,10}$";
private static string _steamExe;
private static string _steamPath;
private static string _steamConfigVdfFile;
private static string _registrySteamKey = @"SOFTWARE\WOW6432Node\Valve\Steam"; // under LocalMachine
private static string _registryAppsKey = $@"SOFTWARE\Valve\Steam\Apps"; // under CurrentUser
private static bool _isSteamInstalled = false;
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
private struct SteamAppInfo
{
@ -33,11 +20,30 @@ namespace DisplayMagician.GameLibraries
public string GameName;
public List<string> GameExes;
public string GameInstallDir;
public string GameSteamIconPath;
public string GameIconPath;
}
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static readonly SteamLibrary _instance = new SteamLibrary();
// Common items to the class
private List<Game> _allSteamGames = new List<Game>();
private string steamAppIdRegex = @"/^[0-9A-F]{1,10}$";
private string _steamExe;
private string _steamPath;
private string _steamConfigVdfFile;
private string _registrySteamKey = @"SOFTWARE\WOW6432Node\Valve\Steam"; // under LocalMachine
private string _registryAppsKey = $@"SOFTWARE\Valve\Steam\Apps"; // under CurrentUser
private bool _isSteamInstalled = false;
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
#region Class Constructors
static SteamLibrary()
SteamLibrary()
{
try
{
@ -80,7 +86,7 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Properties
public static List<Game> AllInstalledGames
public override List<Game> AllInstalledGames
{
get
{
@ -92,7 +98,7 @@ namespace DisplayMagician.GameLibraries
}
public static int InstalledSteamGameCount
public override int InstalledGameCount
{
get
{
@ -100,7 +106,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamRegistryKey
public string SteamRegistryKey
{
get
{
@ -108,7 +114,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamAppsRegistryKey
public string SteamAppsRegistryKey
{
get
{
@ -116,7 +122,23 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamExe
public override string GameLibraryName
{
get
{
return "Steam";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Steam;
}
}
public override string GameLibraryExe
{
get
{
@ -124,7 +146,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamPath
public override string GameLibraryPath
{
get
{
@ -132,7 +154,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static bool IsSteamInstalled
public override bool IsGameLibraryInstalled
{
get
{
@ -145,18 +167,23 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Methods
public static bool AddSteamGame(SteamGame steamGame)
public static SteamLibrary GetLibrary()
{
return _instance;
}
public bool AddGame(SteamGame steamGame)
{
if (!(steamGame is SteamGame))
return false;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if (ContainsSteamGame(steamGame))
if (ContainsGame(steamGame))
{
logger.Debug($"SteamLibrary/AddSteamGame: Updating Steam game {steamGame.Name} in our Steam library");
// We update the existing Shortcut with the data over
SteamGame steamGameToUpdate = GetSteamGame(steamGame.Id.ToString());
SteamGame steamGameToUpdate = (SteamGame)GetGameById(steamGame.Id.ToString());
steamGame.CopyInto(steamGameToUpdate);
}
else
@ -167,7 +194,7 @@ namespace DisplayMagician.GameLibraries
}
//Doublecheck it's been added
if (ContainsSteamGame(steamGame))
if (ContainsGame(steamGame))
{
return true;
}
@ -176,7 +203,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveSteamGame(SteamGame steamGame)
public bool RemoveGame(SteamGame steamGame)
{
if (!(steamGame is SteamGame))
return false;
@ -200,7 +227,7 @@ namespace DisplayMagician.GameLibraries
throw new SteamLibraryException();
}
public static bool RemoveSteamGameById(string steamGameId)
public override bool RemoveGameById(string steamGameId)
{
if (steamGameId.Equals("0"))
return false;
@ -225,7 +252,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveSteamGame(string steamGameNameOrId)
public override bool RemoveGame(string steamGameNameOrId)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrId))
return false;
@ -254,7 +281,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsSteamGame(SteamGame steamGame)
public bool ContainsGame(SteamGame steamGame)
{
if (!(steamGame is SteamGame))
return false;
@ -268,7 +295,7 @@ namespace DisplayMagician.GameLibraries
return false;
}
public static bool ContainsSteamGame(string steamGameNameOrUuid)
public override bool ContainsGame(string steamGameNameOrUuid)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
return false;
@ -298,7 +325,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsSteamGameById(string steamGameId)
public override bool ContainsGameById(string steamGameId)
{
foreach (SteamGame testSteamGame in _allSteamGames)
{
@ -312,7 +339,7 @@ namespace DisplayMagician.GameLibraries
}
public static SteamGame GetSteamGame(string steamGameNameOrUuid)
public override Game GetGame(string steamGameNameOrUuid)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
return null;
@ -341,7 +368,7 @@ namespace DisplayMagician.GameLibraries
}
public static SteamGame GetSteamGameById(string steamGameId)
public override Game GetGameById(string steamGameId)
{
foreach (SteamGame testSteamGame in _allSteamGames)
{
@ -353,7 +380,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool LoadInstalledGames()
public override bool LoadInstalledGames()
{
try
{
@ -468,7 +495,7 @@ namespace DisplayMagician.GameLibraries
else if (common.Name == "clienticon")
{
logger.Trace($"SteamLibrary/LoadInstalledGames: clienticon: App: {app.AppID} - Common {common.Name}: {common.Value}");
steamGameAppInfo.GameSteamIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
steamGameAppInfo.GameIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
}
else if (common.Name == "type")
{
@ -617,9 +644,9 @@ namespace DisplayMagician.GameLibraries
// Next, we need to get the Icons we want to use, and make sure it's the latest one.
string steamGameIconPath = "";
// First of all, we attempt to use the Icon that Steam has cached, if it's available, as that will be updated to the latest
if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath) && steamAppInfo[steamGameId].GameSteamIconPath.EndsWith(".ico"))
if (File.Exists(steamAppInfo[steamGameId].GameIconPath) && steamAppInfo[steamGameId].GameIconPath.EndsWith(".ico"))
{
steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath;
steamGameIconPath = steamAppInfo[steamGameId].GameIconPath;
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Icon Path {steamGameIconPath} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
}
@ -684,7 +711,7 @@ namespace DisplayMagician.GameLibraries
}
[global::System.Serializable]
public class SteamLibraryException : Exception
public class SteamLibraryException : GameLibraryException
{
public SteamLibraryException() { }
public SteamLibraryException(string message) : base(message) { }

View File

@ -8,36 +8,33 @@ using System.Security;
namespace DisplayMagician.GameLibraries
{
public static class UplayLibrary
public class UplayLibrary : GameLibrary
{
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static readonly UplayLibrary _instance = new UplayLibrary();
// Common items to the class
private static List<Game> _allUplayGames = new List<Game>();
private static string uplayAppIdRegex = @"/^[0-9A-F]{1,10}$";
private static bool _isUplayInstalled = false;
private static string _uplayExe;
private static string _uplayPath;
//private static string _uplayConfigVdfFile;
internal static string registryUplayLauncherKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher";
internal static string registryUplayInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
internal static string registryUplayOpenCmdKey = @"SOFTWARE\Classes\uplay\Shell\Open\Command";
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private List<Game> _allGames = new List<Game>();
private string uplayAppIdRegex = @"/^[0-9A-F]{1,10}$";
private bool _isUplayInstalled = false;
private string _uplayExe;
private string _uplayPath;
//private string _uplayConfigVdfFile;
internal string registryUplayLauncherKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher";
internal string registryUplayInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
internal string registryUplayOpenCmdKey = @"SOFTWARE\Classes\uplay\Shell\Open\Command";
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
private struct UplayAppInfo
{
public string GameID;
public string GameName;
public string GameExe;
public string GameInstallDir;
public string GameUplayIconPath;
}
#region Class Constructors
static UplayLibrary()
UplayLibrary()
{
try
{
@ -79,27 +76,43 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Properties
public static List<Game> AllInstalledGames
public override List<Game> AllInstalledGames
{
get
{
// Load the Uplay Games from Uplay Client if needed
if (_allUplayGames.Count == 0)
if (_allGames.Count == 0)
LoadInstalledGames();
return _allUplayGames;
return _allGames;
}
}
public static int InstalledUplayGameCount
public override int InstalledGameCount
{
get
{
return _allUplayGames.Count;
return _allGames.Count;
}
}
public static string UplayExe
public override string GameLibraryName
{
get
{
return "Uplay";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Ubiconnect;
}
}
public override string GameLibraryExe
{
get
{
@ -107,7 +120,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string UplayPath
public override string GameLibraryPath
{
get
{
@ -115,7 +128,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static bool IsUplayInstalled
public override bool IsGameLibraryInstalled
{
get
{
@ -128,29 +141,34 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Methods
public static bool AddUplayGame(UplayGame uplayGame)
public static UplayLibrary GetLibrary()
{
return _instance;
}
public bool AddGame(UplayGame uplayGame)
{
if (!(uplayGame is UplayGame))
return false;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if (ContainsUplayGame(uplayGame))
if (ContainsGame(uplayGame))
{
logger.Debug($"UplayLibrary/AddUplayGame: Updating Uplay game {uplayGame.Name} in our Uplay library");
logger.Debug($"UplayLibrary/AddGame: Updating Uplay game {uplayGame.Name} in our Uplay library");
// We update the existing Shortcut with the data over
UplayGame uplayGameToUpdate = GetUplayGame(uplayGame.Id.ToString());
UplayGame uplayGameToUpdate = GetGame(uplayGame.Id.ToString());
uplayGame.CopyTo(uplayGameToUpdate);
}
else
{
logger.Debug($"UplayLibrary/AddUplayGame: Adding Uplay game {uplayGame.Name} to our Uplay library");
logger.Debug($"UplayLibrary/AddGame: Adding Uplay game {uplayGame.Name} to our Uplay library");
// Add the uplayGame to the list of uplayGames
_allUplayGames.Add(uplayGame);
_allGames.Add(uplayGame);
}
//Doublecheck it's been added
if (ContainsUplayGame(uplayGame))
if (ContainsGame(uplayGame))
{
return true;
}
@ -159,76 +177,76 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveUplayGame(UplayGame uplayGame)
public bool RemoveGame(UplayGame uplayGame)
{
if (!(uplayGame is UplayGame))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame: Removing Uplay game {uplayGame.Name} from our Uplay library");
logger.Debug($"UplayLibrary/RemoveGame: Removing Uplay game {uplayGame.Name} from our Uplay library");
// Remove the uplayGame from the list.
int numRemoved = _allUplayGames.RemoveAll(item => item.Id.Equals(uplayGame.Id));
int numRemoved = _allGames.RemoveAll(item => item.Id.Equals(uplayGame.Id));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame: Removed Uplay game with name {uplayGame.Name}");
logger.Debug($"UplayLibrary/RemoveGame: Removed Uplay game with name {uplayGame.Name}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame: Didn't remove Uplay game with ID {uplayGame.Name} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame: Didn't remove Uplay game with ID {uplayGame.Name} from the Uplay Library");
return false;
}
else
throw new UplayLibraryException();
}
public static bool RemoveUplayGameById(string uplayGameId)
public override bool RemoveGameById(string uplayGameId)
{
if (uplayGameId.Equals(0))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame2: Removing Uplay game with ID {uplayGameId} from the Uplay library");
logger.Debug($"UplayLibrary/RemoveGame2: Removing Uplay game with ID {uplayGameId} from the Uplay library");
// Remove the uplayGame from the list.
int numRemoved = _allUplayGames.RemoveAll(item => item.Id.Equals(uplayGameId));
int numRemoved = _allGames.RemoveAll(item => item.Id.Equals(uplayGameId));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame2: Removed Uplay game with ID {uplayGameId}");
logger.Debug($"UplayLibrary/RemoveGame2: Removed Uplay game with ID {uplayGameId}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame2: Didn't remove Uplay game with ID {uplayGameId} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame2: Didn't remove Uplay game with ID {uplayGameId} from the Uplay Library");
return false;
}
else
throw new UplayLibraryException();
}
public static bool RemoveUplayGame(string uplayGameNameOrId)
public override bool RemoveGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame3: Removing Uplay game with Name or ID {uplayGameNameOrId} from the Uplay library");
logger.Debug($"UplayLibrary/RemoveGame3: Removing Uplay game with Name or ID {uplayGameNameOrId} from the Uplay library");
int numRemoved;
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
numRemoved = _allUplayGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Id));
numRemoved = _allGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Id));
else
numRemoved = _allUplayGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Name));
numRemoved = _allGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Name));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame3: Removed Uplay game with Name or UUID {uplayGameNameOrId} ");
logger.Debug($"UplayLibrary/RemoveGame3: Removed Uplay game with Name or UUID {uplayGameNameOrId} ");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame3: Didn't remove Uplay game with Name or UUID {uplayGameNameOrId} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame3: Didn't remove Uplay game with Name or UUID {uplayGameNameOrId} from the Uplay Library");
return false;
}
else
@ -236,25 +254,25 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsUplayGame(UplayGame uplayGame)
public bool ContainsGame(UplayGame uplayGame)
{
if (!(uplayGame is UplayGame))
return false;
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (testUplayGame.Id.Equals(uplayGame.Id))
if (testGame.Id.Equals(uplayGame.Id))
return true;
}
return false;
}
public static bool ContainsUplayGameById(string uplayGameId)
public override bool ContainsGameById(string uplayGameId)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameId == testUplayGame.Id)
if (uplayGameId == testGame.Id)
return true;
}
@ -263,7 +281,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsUplayGame(string uplayGameNameOrId)
public override bool ContainsGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return false;
@ -272,18 +290,18 @@ namespace DisplayMagician.GameLibraries
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrId.Equals(Convert.ToInt32(testUplayGame.Id)))
if (uplayGameNameOrId.Equals(Convert.ToInt32(testGame.Id)))
return true;
}
}
else
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrId.Equals(testUplayGame.Name))
if (uplayGameNameOrId.Equals(testGame.Name))
return true;
}
@ -294,7 +312,7 @@ namespace DisplayMagician.GameLibraries
}
public static UplayGame GetUplayGame(string uplayGameNameOrId)
public UplayGame GetGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return null;
@ -302,19 +320,19 @@ namespace DisplayMagician.GameLibraries
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrId.Equals(Convert.ToInt32(testUplayGame.Id)))
return testUplayGame;
if (uplayGameNameOrId.Equals(Convert.ToInt32(testGame.Id)))
return testGame;
}
}
else
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrId.Equals(testUplayGame.Name))
return testUplayGame;
if (uplayGameNameOrId.Equals(testGame.Name))
return testGame;
}
}
@ -323,19 +341,19 @@ namespace DisplayMagician.GameLibraries
}
public static UplayGame GetUplayGameById(string uplayGameId)
public UplayGame GetGameById(string uplayGameId)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameId == testUplayGame.Id)
return testUplayGame;
if (uplayGameId == testGame.Id)
return testGame;
}
return null;
}
public static bool LoadInstalledGames()
public override bool LoadInstalledGames()
{
try
{
@ -462,7 +480,7 @@ namespace DisplayMagician.GameLibraries
}
// for each game record grab:
UplayAppInfo uplayGameAppInfo = new UplayAppInfo();
GameAppInfo uplayGameAppInfo = new GameAppInfo();
// find the exe name looking at root: -> start_game: -> online: -> executables: -> path: -> relative: (get ACU.exe)
// Lookup the Game registry key from looking at root: -> start_game: -> online: -> executables: -> working_directory: -> register: (get HKEY_LOCAL_MACHINE\SOFTWARE\Ubisoft\Launcher\Installs\720\InstallDir)
@ -485,7 +503,7 @@ namespace DisplayMagician.GameLibraries
// Stop this loop once we have both filname and gameid
if (gotGameFileName && gotGameId && gotGameIconPath && gotGameName && gotGameRegistryKey)
{
logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameUplayIconPath} && gameName = {uplayGameAppInfo.GameName}");
logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameIconPath} && gameName = {uplayGameAppInfo.GameName}");
break;
}
@ -516,8 +534,8 @@ namespace DisplayMagician.GameLibraries
string uplayGameIconPath = _uplayPath + @"data\games\" + iconImageFileName;
if (File.Exists(uplayGameIconPath) && uplayGameIconPath.EndsWith(".ico"))
{
uplayGameAppInfo.GameUplayIconPath = uplayGameIconPath;
logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameUplayIconPath = {uplayGameAppInfo.GameUplayIconPath }");
uplayGameAppInfo.GameIconPath = uplayGameIconPath;
logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameUplayIconPath = {uplayGameAppInfo.GameIconPath }");
}
gotGameIconPath = true;
}
@ -546,7 +564,7 @@ namespace DisplayMagician.GameLibraries
logger.Trace($"UplayLibrary/LoadInstalledGames: gameId = {gameId}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameFileName = {gameFileName}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameUplayIconPath}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameIconPath}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameRegistryKey = {gameRegistryKey}");
if (gotGameRegistryKey)
@ -575,8 +593,8 @@ namespace DisplayMagician.GameLibraries
{
uplayGameAppInfo.GameInstallDir = Path.GetFullPath(gameInstallDir).TrimEnd('\\');
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameInstallDir = {uplayGameAppInfo.GameInstallDir }");
uplayGameAppInfo.GameExe = Path.Combine(uplayGameAppInfo.GameInstallDir, gameFileName);
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameExe = {uplayGameAppInfo.GameExe }");
uplayGameAppInfo.GameExePath = Path.Combine(uplayGameAppInfo.GameInstallDir, gameFileName);
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameExe = {uplayGameAppInfo.GameExePath}");
uplayGameAppInfo.GameID = gameId;
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameID = {uplayGameAppInfo.GameID }");
}
@ -587,14 +605,14 @@ namespace DisplayMagician.GameLibraries
// Then we have the gameID, the thumbimage, the icon, the name, the exe path
// And we add the Game to the list of games we have!
_allUplayGames.Add(new UplayGame(uplayGameAppInfo.GameID, uplayGameAppInfo.GameName, uplayGameAppInfo.GameExe, uplayGameAppInfo.GameUplayIconPath));
logger.Debug($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {uplayGameAppInfo.GameID}, name {uplayGameAppInfo.GameName}, game exe {uplayGameAppInfo.GameExe} and icon path {uplayGameAppInfo.GameUplayIconPath}");
_allGames.Add(new UplayGame(uplayGameAppInfo.GameID, uplayGameAppInfo.GameName, uplayGameAppInfo.GameExePath, uplayGameAppInfo.GameIconPath));
logger.Debug($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {uplayGameAppInfo.GameID}, name {uplayGameAppInfo.GameName}, game exe {uplayGameAppInfo.GameExePath} and icon path {uplayGameAppInfo.GameIconPath}");
}
}
}
logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allUplayGames.Count} installed Uplay games");
logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allGames.Count} installed Uplay games");
}

View File

@ -17,14 +17,6 @@ using System.Runtime.Serialization;
using NLog.Config;
namespace DisplayMagician {
public enum SupportedGameLibrary
{
Unknown,
Origin,
Steam,
Uplay
}
public enum ApplyProfileResult
{

View File

@ -1050,6 +1050,204 @@ namespace DisplayMagician
}
else if (shortcutToUse.Category.Equals(ShortcutCategory.Game))
{
Game gameToRun = null;
GameLibrary gameLibraryToUse = null;
// If the game is a Steam Game we check for that
if (shortcutToUse.GameLibrary.Equals(GameLibrary.SupportedGameLibraryType.Steam))
{
// We now need to get the SteamGame info
gameLibraryToUse = SteamLibrary.GetLibrary();
logger.Info($"ShortcutRepository/RunShortcut: Starting the {gameToRun.Name} Steam Game, and then we're going to monitor it to wait for it to close.");
}
// If the game is a Ubiconnect Uplay Game we check for that
else if (shortcutToUse.GameLibrary.Equals(GameLibrary.SupportedGameLibraryType.Ubiconnect))
{
// We now need to get the Uplay Game info
gameLibraryToUse = UplayLibrary.GetLibrary();
logger.Info($"ShortcutRepository/RunShortcut: Starting the {gameToRun.Name} Ubiconnect Game, and then we're going to monitor it to wait for it to close.");
}
// If the game is a Uplay Game we check for that
else if (shortcutToUse.GameLibrary.Equals(GameLibrary.SupportedGameLibraryType.Origin))
{
// We now need to get the Uplay Game info
gameLibraryToUse = UplayLibrary.GetLibrary();
logger.Info($"ShortcutRepository/RunShortcut: Starting the {gameToRun.Name} Origin Game, and then we're going to monitor it to wait for it to close.");
}
logger.Info($"ShortcutRepository/RunShortcut: Starting the {gameToRun.Name} {gameLibraryToUse.GameLibraryName} Game, and then we're going to monitor it to wait for it to close.");
gameToRun = gameLibraryToUse.GetGameById(shortcutToUse.GameAppId);
// If the GameAppID is not null, then we've matched a game! Lets run it.
if (gameToRun != null)
{
Process gameProcess;
if (gameToRun.StartMode.Equals(Game.GameStartMode.URI))
{
// Now we want to tell the user we're start a game
// Construct the Windows toast content
ToastContentBuilder tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo($"notify=starting{gameToRun.GameLibrary}", ToastActivationType.Foreground)
.AddText($"Starting {gameToRun.GameLibrary}", hintMaxLines: 1)
.AddText($"Waiting for {gameToRun.GameLibrary}to start (and update if needed)...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
ToastContent toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
var doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
var toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
// Prepare to start the game using the URI method
string address = "";
if (shortcutToUse.GameArgumentsRequired)
{
address = gameToRun.GetStartURI(shortcutToUse.GameArguments);
logger.Debug($"ShortcutRepository/RunShortcut: Shortcut has arguments: {shortcutToUse.GameArguments}");
}
else
{
address = gameToRun.GetStartURI("");
logger.Debug($"ShortcutRepository/RunShortcut: Shortcut has no arguments");
}
logger.Debug($"ShortcutRepository/RunShortcut: Game launch URI is {address}");
logger.Info($"ShortcutRepository/RunShortcut: Starting process with command '{address}'");
gameProcess = Process.Start(address);
// Delay 500ms
Thread.Sleep(500);
// Wait for Origin to start
List<Process> originProcesses = null;
for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
// Look for the processes with the ProcessName we sorted out earlier
originProcesses = Process.GetProcessesByName("origin").ToList();
// If we have found one or more processes then we should be good to go
// so let's break
if (originProcesses.Count > 0)
{
logger.Debug($"ShortcutRepository/RunShortcut: Found {originProcesses.Count} 'origin' processes have started");
break;
}
// Let's wait a little while if we couldn't find
// any processes yet
Thread.Sleep(500);
}
// Delay 5secs
Thread.Sleep(5000);
logger.Debug($"ShortcutRepository/RunShortcut: Pausing for 5 seconds to let the Origin process start the game.");
// Now we know the Origin app is running then
// we wait until the Origin game is running (*allows for origin update)
for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
if (originGameToRun.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Found the '{originGameToRun.Name}' process has started");
break;
}
// Delay 500ms
Thread.Sleep(500);
}
// Store the Origin Process ID for later
IPCService.GetInstance().HoldProcessId = originStartProcess?.Id ?? 0;
IPCService.GetInstance().Status = InstanceStatus.OnHold;
// Add a status notification icon in the status area
if (originGameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {originGameToRun.Name}...";
else
notifyIcon.Text = $"DisplayMagician: Running {originGameToRun.Name.Substring(0, 41)}...";
Application.DoEvents();
// Now we want to tell the user we're running a game!
// Construct the Windows toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=runningOriginGame", ToastActivationType.Foreground)
.AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1)
.AddText($"Waiting for the Origin Game {shortcutToUse.GameName} to exit...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
// Wait 5 seconds for the game process to spawn
Thread.Sleep(5000);
// Wait for the game to exit
Console.WriteLine($"Waiting for {originGameToRun.Name} to exit.");
logger.Debug($"ShortcutRepository/RunShortcut: waiting for Origin Game {originGameToRun.Name} to exit.");
while (true)
{
if (!originGameToRun.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Origin Game {originGameToRun.Name} is no longer running (IsRunning is false).");
break;
}
// Send a message to windows so that it doesn't think
// we're locked and try to kill us
System.Threading.Thread.CurrentThread.Join(0);
Thread.Sleep(1000);
}
Console.WriteLine($"{originGameToRun.Name} has exited.");
logger.Debug($"ShortcutRepository/RunShortcut: Origin Game {originGameToRun.Name} has exited.");
// Tell the user that the Uplay Game has closed
// Construct the toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground)
.AddText($"{shortcutToUse.GameName} was closed", hintMaxLines: 1)
.AddText($"{shortcutToUse.GameName} game was shutdown and changes were reverted.");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show it
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
}
}
else
{
logger.Error($"ShortcutRepository/RunShortcut: Error starting the {gameToRun.Name} {gameToRun.GameLibrary} Game as the game wasn't found.");
}
//-------------------------
// If the game is a Steam Game we check for that
if (shortcutToUse.GameLibrary.Equals(SupportedGameLibrary.Steam))
{
@ -1690,3 +1888,4 @@ namespace DisplayMagician
}
}