First working version after refactor

Have fixed the mistake I made with the
Parallel.Invoke actions where I accidentally
kept adding the SteamLibrary 3 times!

This now works well, and as a bonus the
game libraries are now thread safe!
This commit is contained in:
Terry MacDonald 2021-04-19 22:32:58 +12:00
parent 4c54e72dc2
commit 395d4fa5d9
7 changed files with 127 additions and 56 deletions

View File

@ -18,6 +18,7 @@ namespace DisplayMagician.GameLibraries
private string _originGameProcessName;
private string _originGameIconPath;
//private string _originURI;
private static readonly OriginLibrary _originGameLibrary = OriginLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static OriginGame()

View File

@ -42,6 +42,8 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Constructors
static OriginLibrary() { }
private OriginLibrary()
{
try

View File

@ -20,6 +20,7 @@ namespace DisplayMagician.GameLibraries
private string _steamGameExe;
private string _steamGameProcessName;
private string _steamGameIconPath;
private static readonly SteamLibrary _steamGameLibrary = SteamLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static SteamGame()
@ -32,7 +33,7 @@ namespace DisplayMagician.GameLibraries
public SteamGame(string steamGameId, string steamGameName, string steamGameExePath, string steamGameIconPath)
{
_gameRegistryKey = $@"{SteamLibrary.GetLibrary().SteamAppsRegistryKey}\\{steamGameId}";
_gameRegistryKey = $@"{_steamGameLibrary.SteamAppsRegistryKey}\\{steamGameId}";
_steamGameId = steamGameId;
_steamGameName = steamGameName;
_steamGameExePath = steamGameExePath;

View File

@ -27,7 +27,7 @@ namespace DisplayMagician.GameLibraries
// 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();
private static SteamLibrary _instance = new SteamLibrary();
// Common items to the class
private List<Game> _allSteamGames = new List<Game>();
@ -44,7 +44,9 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Constructors
SteamLibrary()
static SteamLibrary() { }
private SteamLibrary()
{
try
{
@ -573,7 +575,7 @@ namespace DisplayMagician.GameLibraries
if (steamAppType.Equals("Game",StringComparison.OrdinalIgnoreCase))
{
steamAppInfo.Add(detectedAppID, steamGameAppInfo);
logger.Trace($"SteamLibrary/LoadInstalledGames: Adding Game with ID {detectedAppID} to the list of games");
logger.Trace($"SteamLibrary/LoadInstalledGames: Adding Game with ID {detectedAppID} '{steamGameAppInfo.GameName}' to the list of games");
}
}
@ -647,30 +649,30 @@ namespace DisplayMagician.GameLibraries
// This game is an installed game! so we start to populate it with data!
string steamGameExe = "";
string steamGameName = steamAppInfo[steamGameId].GameName;
string steamGameName = steamAppInfo[steamGameId].GameName;
// Construct the full path to the game dir from the appInfo and libraryAppManifest data
string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir);
// Construct the full path to the game dir from the appInfo and libraryAppManifest data
string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }");
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// And finally we try to populate the 'where', to see what gets run
// And so we can extract the process name
if (steamAppInfo[steamGameId].GameExes.Count > 0)
{
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
// And finally we try to populate the 'where', to see what gets run
// And so we can extract the process name
if (steamAppInfo[steamGameId].GameExes.Count > 0)
{
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// If the game executable exists, then we can proceed
if (File.Exists(steamGameExe))
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
{
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
break;
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// If the game executable exists, then we can proceed
if (File.Exists(steamGameExe))
{
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
break;
}
}
}
}
}
// Next, we need to get the Icons we want to use, and make sure it's the latest one.
string steamGameIconPath = "";

View File

@ -18,6 +18,7 @@ namespace DisplayMagician.GameLibraries
private string _uplayGameExe;
private string _uplayGameProcessName;
private string _uplayGameIconPath;
private static readonly UplayLibrary _uplayGameLibrary = UplayLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static UplayGame()

View File

@ -11,6 +11,8 @@ namespace DisplayMagician.GameLibraries
{
public class UplayLibrary : GameLibrary
{
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
@ -36,7 +38,9 @@ namespace DisplayMagician.GameLibraries
#region Class Constructors
UplayLibrary()
static UplayLibrary() { }
private UplayLibrary()
{
try
{

View File

@ -16,6 +16,7 @@ using System.Drawing;
using DesktopNotifications;
using System.Runtime.Serialization;
using NLog.Config;
using System.Collections.Generic;
namespace DisplayMagician {
@ -778,47 +779,106 @@ namespace DisplayMagician {
});
Action loadSteamGamesAction = new Action(() =>
{
// Check if Steam is installed
GameLibrary steamLibrary = SteamLibrary.GetLibrary();
if (steamLibrary.IsGameLibraryInstalled)
{
// Load Steam library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Steam Games");
Console.Write("Loading Installed Steam Games...");
if (!steamLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Steam Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Steam Games (found {steamLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Steam not installed.");
Console.WriteLine("Steam not installed.");
}
});
// Store all the tasks in an array so we can wait on them later
Task[] loadGamesTasks = new Task[3];
loadGamesTasks[0] = loadSteamGamesTask;
loadGamesTasks[1] = loadUplayGamesTask;
loadGamesTasks[2] = loadOriginGamesTask;
// Now lets prepare loading all the Uplay games we have installed
Action loadUplayGamesAction = new Action(() =>
{
// Check if Uplay is installed
GameLibrary uplayLibrary = UplayLibrary.GetLibrary();
if (uplayLibrary.IsGameLibraryInstalled)
{
// Load Uplay library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Uplay Games");
Console.Write("Loading Installed Uplay Games...");
if (!uplayLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Uplay Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Uplay Games (found {uplayLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Uplay not installed.");
Console.WriteLine("Uplay not installed.");
}
logger.Debug($"Program/LoadGamesInBackground: Running game loading tasks.");
// Go through and start all the tasks
foreach (Task loadGameTask in loadGamesTasks)
loadGameTask.Start();
});
// Now lets prepare loading all the Origin games we have installed
Action loadOriginGamesAction = new Action(() =>
{
// Check if Origin is installed
GameLibrary originLibrary = OriginLibrary.GetLibrary();
if (originLibrary.IsGameLibraryInstalled)
{
// Load Origin library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Origin Games");
Console.Write("Loading Installed Origin Games...");
if (!originLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Origin Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Origin Games (found {originLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Origin not installed.");
Console.WriteLine("Origin not installed.");
}
});
// Store all the actions in a array so we can wait on them later
List<Action> loadGamesActions = new List<Action>();
loadGamesActions.Add(loadSteamGamesAction);
loadGamesActions.Add(loadUplayGamesAction);
loadGamesActions.Add(loadOriginGamesAction);
try
{
logger.Debug($"Program/LoadGamesInBackground: Waiting for all game loading tasks to finish");
Task.WaitAll(loadGamesTasks);
logger.Debug($"Program/LoadGamesInBackground: Running game loading actions.");
// Go through and start all the actions, making sure we only have one threat per action to avoid thread issues
int threads = loadGamesActions.Count;
ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = threads };
Parallel.Invoke(options, loadGamesActions.ToArray());
logger.Debug($"Program/LoadGamesInBackground: All game loading tasks finished");
}
catch (AggregateException ae)
{
logger.Error(ae, $"Program/LoadGamesInBackground exception during loadGamesTasks");
Console.WriteLine("Program/LoadGamesInBackground : Task exception!");
foreach (var e in ae.InnerExceptions)
{
// Handle the custom exception.
if (e is LoadingInstalledGamesException)
{
Console.WriteLine(e.Message);
}
// Rethrow any other exception.
else
{
throw;
}
}
logger.Error(ae, $"Program/LoadGamesInBackground exception during loadGamesActions");
}
bool failedTask = false;
foreach (var loadGameTask in loadGamesTasks)
// TODO replicate this failed Task handling in Actions
/*bool failedAction = false;
foreach (var loadGameAction in loadGamesActions)
{
if (loadGameTask.Exception != null)
if (loadGameAction. .Exception != null)
{
failedTask = true;
foreach (var ex in loadGameTask.Exception.InnerExceptions)
@ -827,7 +887,7 @@ namespace DisplayMagician {
}
if (failedTask)
return false;
return false;*/
return true;