diff --git a/DisplayMagician/DisplayMagician.csproj b/DisplayMagician/DisplayMagician.csproj
index ae13c6b..0b110c3 100644
--- a/DisplayMagician/DisplayMagician.csproj
+++ b/DisplayMagician/DisplayMagician.csproj
@@ -108,7 +108,7 @@
-
+
@@ -312,6 +312,9 @@
4.7.11
+
+ 3.0.101
+
1.0.0
@@ -324,6 +327,9 @@
1.6.0.4
+
+ 11.2.1
+
diff --git a/DisplayMagician/GameLibraries/UplayConfigurationParser/UplayConfigurationParser.cs b/DisplayMagician/GameLibraries/UplayConfigurationParser/UplayConfigurationParser.cs
deleted file mode 100644
index 4ef7932..0000000
--- a/DisplayMagician/GameLibraries/UplayConfigurationParser/UplayConfigurationParser.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-// This configuration parses logic is kept here for possible future use
-// It was really difficult to find this logic in some obscure webpage
-// so I'm keeping it in case I need it later.
-namespace DisplayMagician.GameLibraries.UplayConfigurationParser
-{
- class UplayConfigurationParser
- {
-
- /*def _convert_data(self, data):
- # calculate object size (konrad's formula)
- if data > 256 * 256:
- data = data - (128 * 256 * math.ceil(data / (256 * 256)))
- data = data - (128 * math.ceil(data / 256))
- else:
- if data > 256:
- data = data - (128 * math.ceil(data / 256))
- return data*/
-
- internal static decimal ConvertData (decimal data)
- {
- if (data > 65536)
- {
- data = data - (128 * 256 * Math.Ceiling(data / 65536));
- }
- else if (data > 256)
- {
- data = data - (128 * Math.Ceiling(data / 256));
- }
-
- return data;
-
- }
-
-
-
- /*def _parse_configuration_header(self, header, second_eight= False):
- try:
- offset = 1
- multiplier = 1
- record_size = 0
- tmp_size = 0
-
- if second_eight:
- while header[offset] != 0x08 or(header[offset] == 0x08 and header[offset + 1] == 0x08) :
- record_size += header[offset] * multiplier
- multiplier *= 256
- offset += 1
- tmp_size += 1
- else:
- while header[offset] != 0x08 or record_size == 0:
- record_size += header[offset] * multiplier
- multiplier *= 256
- offset += 1
- tmp_size += 1
-
- record_size = self._convert_data(record_size)
-
- offset += 1 # skip 0x08
-
- # look for launch_id
- multiplier = 1
- launch_id = 0
-
- while header[offset] != 0x10 or header[offset + 1] == 0x10:
- launch_id += header[offset] * multiplier
- multiplier *= 256
- offset += 1
-
- launch_id = self._convert_data(launch_id)
-
- offset += 1 # skip 0x10
-
- multiplier = 1
- launch_id_2 = 0
- while header[offset] != 0x1A or(header[offset] == 0x1A and header[offset + 1] == 0x1A) :
- launch_id_2 += header[offset] * multiplier
- multiplier *= 256
- offset += 1
-
- launch_id_2 = self._convert_data(launch_id_2)
-
- #if object size is smaller than 128b, there might be a chance that secondary size will not occupy 2b
- if record_size - offset < 128 <= record_size:
- tmp_size -= 1
- record_size += 1
-
-# we end up in the middle of header, return values normalized
-# to end of record as well real yaml size and game launch_id
- return record_size - offset, launch_id, launch_id_2, offset + tmp_size + 1
- except:
-# something went horribly wrong, do not crash it,
-# just return 0s, this way it will be handled later in the code
-# 10 is to step a little in configuration file in order to find next game
- return 0, 0, 0, 10*/
-
- //internal static decimal ParseConfigurationHeader(decimal data);
- }
-}
diff --git a/DisplayMagician/GameLibraries/UplayFileStructure.cs b/DisplayMagician/GameLibraries/UplayFileStructure.cs
new file mode 100644
index 0000000..f54813f
--- /dev/null
+++ b/DisplayMagician/GameLibraries/UplayFileStructure.cs
@@ -0,0 +1,144 @@
+using ProtoBuf;
+using System.Collections.Generic;
+
+namespace DisplayMagician.GameLibraries
+{
+ // #####################################################################################################
+ // # This set of classes are used for deserialising Uplay protobuf files
+ // #####################################################################################################
+
+ [ProtoContract]
+ public class UplayCachedGame
+ {
+ [ProtoMember(1)]
+ public uint UplayId { get; set; }
+ [ProtoMember(2)]
+ public uint InstallId { get; set; }
+ [ProtoMember(3)]
+ public string GameInfo { get; set; }
+ }
+
+ [ProtoContract]
+ public class UplayCachedGameCollection
+ {
+ [ProtoMember(1)]
+ public List Games { get; set; }
+ }
+
+ // #####################################################################################################
+ // # This set of classes are used for deserialising Uplay YAML enbedded within the protobuf file format
+ // #####################################################################################################
+ public class ProductInformation
+ {
+ public class Executable
+ {
+ public class Path
+ {
+ public string relative;
+ }
+
+ public class WorkingDirectory
+ {
+ public string register;
+ public string append;
+ }
+
+ public Path path;
+ public WorkingDirectory working_directory;
+ public string internal_name;
+ public string description;
+ public string shortcut_name;
+ public string icon_image;
+ }
+
+ public class StartGameItem
+ {
+ public bool after_game_report_enabled;
+ public bool overlay_supported;
+ public bool overlay_product_activation_enabled;
+ public bool overlay_required;
+ public bool overlay_shop_enabled;
+ public bool legacy_ticket_enabled;
+ public List executables;
+
+ }
+
+ public class StartGame
+ {
+ public StartGameItem online;
+ public StartGameItem offline;
+ }
+
+ public class DigitalDistribution
+ {
+ public int version;
+ }
+
+ public class Localization
+ {
+ public string l1;
+ }
+
+ public class Club
+ {
+ public bool enabled;
+ }
+
+ public class Addon
+ {
+ public uint id;
+ public bool is_visible;
+ public string name;
+ public string description;
+ public string thumb_image;
+ }
+
+ public class Uplay
+ {
+ public string game_code;
+ public string achievements;
+ public string achievements_sync_id;
+ }
+
+ public class ThirdPartyPlatform
+ {
+ public string name;
+ }
+
+ public class Product
+ {
+ public string name;
+ public string background_image;
+ public string thumb_image;
+ public string logo_image;
+ public string dialog_image;
+ public string icon_image;
+ public ThirdPartyPlatform third_party_platform;
+ public string sort_string;
+ public bool cloud_saves;
+ public string forum_url;
+ public string homepage_url;
+ public string facebook_url;
+ public string help_url;
+ public bool after_game_report_ad;
+ public bool force_safe_mode;
+ public bool uplay_pipe_required;
+ public bool show_properties;
+ public bool game_streaming_enabled;
+ public Uplay uplay;
+ public List addons;
+ public Club club;
+ public DigitalDistribution digital_distribution;
+ public bool is_ulc;
+ public bool is_visible;
+ public StartGame start_game;
+ }
+
+ public string version;
+ public Product root;
+ public Dictionary localizations;
+ public uint uplay_id;
+ public uint install_id;
+ }
+
+}
diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs
index 3c281bc..db1fccc 100644
--- a/DisplayMagician/GameLibraries/UplayLibrary.cs
+++ b/DisplayMagician/GameLibraries/UplayLibrary.cs
@@ -6,6 +6,10 @@ using Microsoft.Win32;
using System.IO;
using System.Security;
using System.Diagnostics;
+using ProtoBuf;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+using System.Globalization;
namespace DisplayMagician.GameLibraries
{
@@ -404,6 +408,52 @@ namespace DisplayMagician.GameLibraries
}
+ public bool GetInstallDirFromRegKey(string regKeyPath, out string filePath)
+ {
+ filePath = "";
+
+ RegistryKey uplayGameInstallKey;
+ if (regKeyPath.StartsWith("HKEY_LOCAL_MACHINE"))
+ {
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKLM reg key {regKeyPath}");
+ string regKeyText = regKeyPath.Replace(@"HKEY_LOCAL_MACHINE\", "");
+ uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(regKeyText, RegistryKeyPermissionCheck.ReadSubTree);
+ }
+ else if (regKeyPath.StartsWith("HKEY_CURRENT_USER"))
+ {
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKCU reg key {regKeyPath}");
+ string regKeyText = regKeyPath.Replace(@"HKEY_CURRENT_USER\", "");
+ uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(regKeyText, RegistryKeyPermissionCheck.ReadSubTree);
+ }
+ else
+ {
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Skipping processing as regkey supplied was odd: {regKeyPath}");
+ return false;
+ }
+
+ // If the key doesn't exist we skip it as the game isn't installed any longer!
+ if (uplayGameInstallKey == null)
+ {
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Skipping Uplay Game as it isn't installed at the moment (it was uninstalled at some point)");
+ return false;
+ }
+
+ // From that we lookup the actual game path
+ string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString();
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: gameInstallDir found = {gameInstallDir}");
+ if (!String.IsNullOrWhiteSpace(gameInstallDir))
+ {
+ filePath = Path.GetFullPath(gameInstallDir).TrimEnd('\\');
+ return true;
+ }
+ else
+ {
+ logger.Warn($"UplayLibrary/GetInstallDirFromRegKey: gameInstallDir is null or all whitespace!");
+ return false;
+ }
+ }
+
+
public override bool LoadInstalledGames()
{
try
@@ -475,211 +525,287 @@ namespace DisplayMagician.GameLibraries
// Access {installdir}\\cache\\configuration\\configurations file
string uplayConfigFilePath = _uplayPath + @"cache\configuration\configurations";
logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Config File Path = {uplayConfigFilePath }");
- string uplayConfigFileString = File.ReadAllText(uplayConfigFilePath);
- uplayConfigFileString = uplayConfigFileString.Remove(0, 12);
- string[] dividingText = { "version: 2.0" };
- List uplayConfigFile = uplayConfigFileString.Split(dividingText,StringSplitOptions.RemoveEmptyEntries).ToList();
- // Split the file into records at the SOH unicode character
- //List uplayConfigFile = uplayConfigFileString.Split((Char)1).ToList();
- // Go through every record and attempt to parse it
- foreach (string uplayEntry in uplayConfigFile) {
- // Skip any Uplay entry records that don't start with 'version:'
- //if (!uplayEntry.StartsWith("version:",StringComparison.OrdinalIgnoreCase))
- // continue;
+ var deserializer = new DeserializerBuilder()
+ .IgnoreUnmatchedProperties()
+ .Build();
- logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Entry that starts with 'version: 2.0') = {uplayEntry}");
-
- //Split the record into entrylines
- string[] delimeters = { "\r\n" };
- List uplayEntryLines = uplayEntry.Split(delimeters, System.StringSplitOptions.RemoveEmptyEntries).ToList();
-
- // Skip any records NOT containing an entryline with ' start_game:' (note 2 leading spaces)
- // All games contain a start_game entry
- if (!uplayEntryLines.Exists(a => a.StartsWith(" start_game:")))
- continue;
-
- // Skip any records containing an entryline with ' third_party_platform:' (note 2 leading spaces)
- // We only want the native uplay games....
- if (uplayEntryLines.Exists(a => a.StartsWith(" third_party_platform:")))
- continue;
-
- // if we get here then we have a real game to parse!
- // Yay us :).
-
- // First we want to know the index of the start_game entry to use later
- //int startGameIndex = uplayEntryLines.FindIndex(a => a.StartsWith(" start_game:"));
- MatchCollection mc;
-
- // First we check if there are any localization CONSTANTS that we will need to map later.
- Dictionary localizations = new Dictionary();
- int localizationsIndex = uplayEntryLines.FindIndex(a => a == "localizations:");
- // If there are localizations, then we need to store them for later
- if (localizationsIndex != -1)
+ using (var file = File.OpenRead(uplayConfigFilePath))
+ {
+ try
{
- // grab the localizations: -> default: entries to use as a lookup table for the info we need
- int defaultIndex = localizationsIndex + 1;
- int currentIndex = defaultIndex + 1;
-
- // Grab all EntryLines with 4 leading spaces (these are all the localizations)
- while (uplayEntryLines[currentIndex].StartsWith(" ")){
- string[] split = uplayEntryLines[currentIndex].Split(':');
- localizations.Add(split[0].Trim(), split[1].Trim());
- currentIndex++;
- }
-
- }
-
- // for each game record grab:
- 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)
- // Extract the GameAppID from the number in the working directory (e.g. 720)
- // Lookup the Game install path by reading the game registry key: D:/Ubisoft Game Launcher/Assassin's Creed Unity/
- // join the Game install path and the exe name to get the full game exe path: D:/Ubisoft Game Launcher/Assassin's Creed Unity/ACU.exe
-
- //if (uplayEntryLines.Find (a => a.StartsWith(" icon_image:", StringComparison.InvariantCultureIgnoreCase)))
-
- bool gotGameIconPath = false;
- bool gotGameName = false;
- string gameFileName = "";
- bool gotGameFileName = false;
- string gameId = "";
- bool gotGameId = false;
- string gameRegistryKey = "";
- bool gotGameRegistryKey = false;
- for (int i = 0; i <= 50; i++)
- {
- // Stop this loop once we have both filname and gameid
- if (gotGameFileName && gotGameId && gotGameIconPath && gotGameName && gotGameRegistryKey)
+ var gameCollection = ProtoBuf.Serializer.Deserialize(file).Games;
+ foreach (var item in gameCollection)
{
- logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameIconPath} && gameName = {uplayGameAppInfo.GameName}");
- break;
- }
-
- // This line contains the Game Name
- if (uplayEntryLines[i].StartsWith(" name:", StringComparison.OrdinalIgnoreCase) && !gotGameName)
- {
- mc = Regex.Matches(uplayEntryLines[i], @" name\: (.*)");
- if (mc.Count > 0)
+ if (!String.IsNullOrEmpty(item.GameInfo))
{
- uplayGameAppInfo.GameName = mc[0].Groups[1].ToString();
- // if the name contains a localization reference, then dereference it
- if (localizations.ContainsKey(uplayGameAppInfo.GameName))
+ ProductInformation productInfo;
+ try
{
- uplayGameAppInfo.GameName = localizations[uplayGameAppInfo.GameName];
+ productInfo = deserializer.Deserialize(item.GameInfo);
+ var root = productInfo.root;
+
+ string gameName = "";
+ string gameExePath = "";
+ string gameIconPath = "";
+
+ // Try finding the Game Name using the localisation currently in use as a first step
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Looking for the Uplay game name.");
+ string currentLang = CultureInfo.CurrentCulture.Name;
+ foreach (var lang in productInfo.localizations)
+ {
+ // If we find the same language as the user is using, then let's use that!
+ if (lang.Key.Equals(currentLang))
+ {
+ gameName = lang.Value.l1;
+ logger.Trace($"UplayLibrary/LoadInstalledGames: We found the Uplay game name '{gameName}' in the user's language of {currentLang}.");
+ break;
+ }
+ }
+ // If the gameName isn't available in the users language, then we go for default
+ if (String.IsNullOrEmpty(gameName) && productInfo.localizations.ContainsKey("default"))
+ {
+ gameName = productInfo.localizations["default"].l1;
+ if (!String.IsNullOrEmpty(gameName))
+ {
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Looking for the Uplay game name with the en language as the local language didn't work. We found game name '{gameName}'. ");
+ }
+ else
+ {
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Looking for the Uplay game name with the en language as the local language didn't work. We found no en language. ");
+ }
+ }
+
+
+ // Now we'll try to sort out the rest of the game data!
+ // We first look for the online executable information
+ if (root.start_game.online.executables.Count > 0)
+ {
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay game {gameName} has some online executables to process! ");
+
+ // First up we look at the online games, cause they're just better!
+ foreach (var executable in root.start_game.online.executables)
+ {
+ string exePath = "";
+
+ // Check if its a full path or a relative path
+ if (!String.IsNullOrEmpty(executable.path.relative))
+ {
+ if (executable.working_directory.register.StartsWith("HKEY_LOCAL_MACHINE"))
+ {
+ // This copes with relative files using a HKEY_LOCAL_MACHINE registry
+
+ string regKeyText = executable.working_directory.register;
+ regKeyText = regKeyText.Replace(@"\InstallDir", "");
+ regKeyText = regKeyText.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft");
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKLM reg key {regKeyText}");
+
+ if (this.GetInstallDirFromRegKey(regKeyText, out exePath))
+ {
+ gameExePath = Path.Combine(exePath, executable.path.relative);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses local machine registry key: {executable.working_directory.register} ");
+ }
+ }
+ /*else if (executable.working_directory.register.StartsWith("HKEY_CURRENT_USER"))
+ {
+ // This copes with relative files using a HKEY_CURRENT_USER registry
+
+ string regKeyText = executable.working_directory.register;
+ regKeyText = regKeyText.Replace(@"\InstallDir", "");
+ regKeyText = regKeyText.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft");
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKLM reg key {regKeyText}");
+
+ if (this.GetInstallDirFromRegKey(executable.working_directory.register, out exePath))
+ {
+ gameExePath = Path.Combine(exePath, executable.path.relative);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses current user registry key: {executable.working_directory.register} ");
+ }
+ }*/
+ else if (!String.IsNullOrEmpty(executable.working_directory.append))
+ {
+ // This copes with relative files using an appended path
+ gameExePath = Path.Combine(executable.working_directory.append, executable.path.relative);
+ gameIconPath = Path.Combine(executable.working_directory.append, executable.icon_image);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses appended file path: {executable.working_directory.append} ");
+ }
+ else
+ {
+ // Problem!
+ logger.Error($"UplayLibrary/LoadInstalledGames: Found relative GameExePath {executable.path.relative} for Uplay game {gameName} but no registry key or appended file path! Skipping this game.");
+ continue;
+ }
+ }
+ else
+ {
+ // This should cope with full pathed files, but we have no examples to test! So log it
+ logger.Error($"UplayLibrary/LoadInstalledGames: Found non-relative GameExePath {executable.path} for Uplay game {gameName} but we've not seen it before so no idea how to handle it! Skipping this game.");
+ logger.Error($"UplayLibrary/LoadInstalledGames: executable.path for troubleshooting: {executable.path}");
+ continue;
+ }
+
+ // We should check the exe file exists, and if it doesn't then we need to do the next exe
+ if (!File.Exists(gameExePath))
+ {
+ logger.Error($"UplayLibrary/LoadInstalledGames: Couldn't find the GameExePath {gameExePath} for Uplay game {gameName} so skipping this exe, and trying the next one.");
+ continue;
+ }
+
+ // Now try to get the Uplay game icon
+ if (!String.IsNullOrEmpty(executable.icon_image))
+ {
+ gameIconPath = Path.Combine(_uplayPath, "data", "games", executable.icon_image);
+
+ // If the icon file isn't actually there, then use the game exe instead.
+ if (!File.Exists(gameIconPath))
+ {
+ gameIconPath = gameExePath;
+ }
+ }
+
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Found GameExePath {exePath} and Icon Path {gameIconPath} for Uplay game {gameName}.");
+
+ // We do a final check to make sure that we do have a GameName, and if not we use the shortcut
+ if (String.IsNullOrEmpty(gameName) && !String.IsNullOrEmpty(executable.shortcut_name))
+ {
+ gameName = executable.shortcut_name;
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Game Name was still empty, so we're using the shortcut name as a last resort: {executable.shortcut_name} ");
+ }
+
+ // Now we need to save the game name, cause if we're here then we're good enough to save
+ // 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!
+ _allGames.Add(new UplayGame(productInfo.uplay_id.ToString(), gameName, gameExePath, gameIconPath));
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {productInfo.uplay_id}, name {gameName}, game exe {gameExePath} and icon path {gameIconPath}");
+ break;
+ }
+
+ }
+ // This is the offline exes
+ else if (root.start_game.offline.executables.Count > 0)
+ {
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay game {gameName} has some offline executables to process! ");
+
+ // we look at the offline games, cause there weren't any online ones
+ foreach (var executable in root.start_game.offline.executables)
+ {
+ string exePath = "";
+
+ // Check if its a full path or a relative path
+ if (!String.IsNullOrEmpty(executable.path.relative))
+ {
+ if (executable.working_directory.register.StartsWith("HKEY_LOCAL_MACHINE"))
+ {
+ // This copes with relative files using a HKEY_LOCAL_MACHINE registry
+
+ string regKeyText = executable.working_directory.register;
+ regKeyText = regKeyText.Replace(@"\InstallDir", "");
+ regKeyText = regKeyText.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft");
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKLM reg key {regKeyText}");
+
+ if (this.GetInstallDirFromRegKey(regKeyText, out exePath))
+ {
+ gameExePath = Path.Combine(exePath, executable.path.relative);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses local machine registry key: {executable.working_directory.register} ");
+ }
+ }
+ /*else if (executable.working_directory.register.StartsWith("HKEY_CURRENT_USER"))
+ {
+ // This copes with relative files using a HKEY_CURRENT_USER registry
+
+ string regKeyText = executable.working_directory.register;
+ regKeyText = regKeyText.Replace(@"\InstallDir", "");
+ regKeyText = regKeyText.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft");
+ logger.Trace($"UplayLibrary/GetInstallDirFromRegKey: Accessing HKLM reg key {regKeyText}");
+
+ if (this.GetInstallDirFromRegKey(executable.working_directory.register, out exePath))
+ {
+ gameExePath = Path.Combine(exePath, executable.path.relative);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses current user registry key: {executable.working_directory.register} ");
+ }
+ }*/
+ else if (!String.IsNullOrEmpty(executable.working_directory.append))
+ {
+ // This copes with relative files using an appended path
+ gameExePath = Path.Combine(executable.working_directory.append, executable.path.relative);
+ gameIconPath = Path.Combine(executable.working_directory.append, executable.icon_image);
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Relative executable uses appended file path: {executable.working_directory.append} ");
+ }
+ else
+ {
+ // Problem!
+ logger.Error($"UplayLibrary/LoadInstalledGames: Found relative GameExePath {executable.path.relative} for Uplay game {gameName} but no registry key or appended file path! Skipping this game.");
+ continue;
+ }
+ }
+ else
+ {
+ // This should cope with full pathed files, but we have no examples to test! So log it
+ logger.Error($"UplayLibrary/LoadInstalledGames: Found non-relative GameExePath {executable.path} for Uplay game {gameName} but we've not seen it before so no idea how to handle it! Skipping this game.");
+ logger.Error($"UplayLibrary/LoadInstalledGames: executable.path for troubleshooting: {executable.path}");
+ continue;
+ }
+
+ // We should check the exe file exists, and if it doesn't then we need to do the next exe
+ if (!File.Exists(gameExePath))
+ {
+ logger.Error($"UplayLibrary/LoadInstalledGames: Couldn't find the GameExePath {gameExePath} for Uplay game {gameName} so skipping this exe, and trying the next one.");
+ continue;
+ }
+
+ // Now try to get the Uplay game icon
+ if (!String.IsNullOrEmpty(executable.icon_image))
+ {
+ gameIconPath = Path.Combine(_uplayPath, "data", "games", executable.icon_image);
+
+ // If the icon file isn't actually there, then use the game exe instead.
+ if (!File.Exists(gameIconPath))
+ {
+ gameIconPath = gameExePath;
+ }
+ }
+
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Found GameExePath {exePath} and Icon Path {gameIconPath} for Uplay game {gameName}.");
+
+ // We do a final check to make sure that we do have a GameName, and if not we use the shortcut
+ if (String.IsNullOrEmpty(gameName) && !String.IsNullOrEmpty(executable.shortcut_name))
+ {
+ gameName = executable.shortcut_name;
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Game Name was still empty, so we're using the shortcut name as a last resort: {executable.shortcut_name} ");
+ }
+
+ // Now we need to save the game name, cause if we're here then we're good enough to save
+ // 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!
+ _allGames.Add(new UplayGame(productInfo.uplay_id.ToString(), gameName, gameExePath, gameIconPath));
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {productInfo.uplay_id}, name {gameName}, game exe {gameExePath} and icon path {gameIconPath}");
+ break;
+ }
+
+ }
+ else
+ {
+ logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Entry {gameName} doesn't have any executables associated with it! We have to skip adding this game.");
+ continue;
+ }
+
}
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameName = {uplayGameAppInfo.GameName}");
- gotGameName = true;
- }
- }
- else if (uplayEntryLines[i].StartsWith(" icon_image:", StringComparison.OrdinalIgnoreCase) && !gotGameIconPath)
- {
- mc = Regex.Matches(uplayEntryLines[i], @"icon_image: (.*)");
- if (mc.Count > 0)
- {
- string iconImageFileName = mc[0].Groups[1].ToString();
- // if the icon_image contains a localization reference, then dereference it
- if (localizations.ContainsKey(iconImageFileName))
+ catch (Exception ex)
{
- iconImageFileName = localizations[iconImageFileName];
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found iconImageFile = {iconImageFileName }");
+ // If we get an error processing the game YAML, lets try and skip this game and try the next one. It might work!
+ logger.Error($"UplayLibrary/LoadInstalledGames: Problem deserialising the YAML embedded in the Uplay configuration file {uplayConfigFilePath}. Cannot process this games!");
+ continue;
}
- //61fdd16f06ae08158d0a6d476f1c6bd5.ico
- string uplayGameIconPath = _uplayPath + @"data\games\" + iconImageFileName;
- if (File.Exists(uplayGameIconPath) && uplayGameIconPath.EndsWith(".ico"))
- {
- uplayGameAppInfo.GameIconPath = uplayGameIconPath;
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameUplayIconPath = {uplayGameAppInfo.GameIconPath }");
- }
- gotGameIconPath = true;
- }
- }
- // This line contains the filename
- else if (uplayEntryLines[i].StartsWith(" relative:") && !gotGameFileName)
- {
- mc = Regex.Matches(uplayEntryLines[i], @"relative: (.*)");
- if (mc.Count > 0)
- {
- gameFileName = mc[0].Groups[1].ToString();
- gotGameFileName = true;
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameFileName = {gameFileName}");
- }
- }
- // This line contains the registryKey
- else if (uplayEntryLines[i].StartsWith(" register: HKEY_LOCAL_MACHINE") && !gotGameId)
- {
-
- // Lookup the GameId within the registry key
- mc = Regex.Matches(uplayEntryLines[i], @"Installs\\(\d+)\\InstallDir");
- if (mc.Count > 0)
- {
- gameId = mc[0].Groups[1].ToString();
- gotGameId = true;
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameId = {gameId}");
+
}
- mc = Regex.Matches(uplayEntryLines[i], @"HKEY_LOCAL_MACHINE\\(.*?)\\InstallDir");
- if (mc.Count > 0)
- {
- gameRegistryKey = mc[0].Groups[1].ToString();
- gameRegistryKey = gameRegistryKey.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft");
- gotGameRegistryKey = true;
- logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameRegistryKey = {gameRegistryKey}");
- }
-
}
}
-
- logger.Trace($"UplayLibrary/LoadInstalledGames: gameId = {gameId}");
- logger.Trace($"UplayLibrary/LoadInstalledGames: gameFileName = {gameFileName}");
- logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameIconPath}");
- logger.Trace($"UplayLibrary/LoadInstalledGames: gameRegistryKey = {gameRegistryKey}");
-
- if (gotGameRegistryKey)
+ catch (Exception ex)
{
- // Now we need to lookup the game install path in registry using the game reg we got above
- // We assume its 64-bit OS too (not 32bit)
- using (RegistryKey uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
- {
- // If the key doesn't exist we skip it as the game isn't installed any longer!
- if (uplayGameInstallKey == null)
- {
- logger.Trace($"UplayLibrary/LoadInstalledGames: Skipping Uplay Game {uplayGameAppInfo.GameName} as it isn't installed at the moment (it was uninstalled at some point)");
- continue;
- }
-
- // If we get here, then we have a real game.
- foreach (string regKeyName in uplayGameInstallKey.GetValueNames())
- {
- logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameInstallKey[{regKeyName}] = {uplayGameInstallKey.GetValue(regKeyName)}");
- }
-
- // From that we lookup the actual game path
- string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString();
- logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found = {gameInstallDir}");
- if (!String.IsNullOrWhiteSpace(gameInstallDir))
- {
- uplayGameAppInfo.GameInstallDir = Path.GetFullPath(gameInstallDir).TrimEnd('\\');
- logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameInstallDir = {uplayGameAppInfo.GameInstallDir }");
- 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 }");
- }
- else
- {
- logger.Warn($"UplayLibrary/LoadInstalledGames: gameInstallDir is null or all whitespace!");
- }
-
- // 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!
- _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}");
- }
+ // We can't do anything if we hit here.
+ logger.Error($"UplayLibrary/LoadInstalledGames: Problem deserialising the protobuf Uplay configuration file {uplayConfigFilePath}. Cannot process any games!");
+ return false;
}
-
- }
+ }
logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allGames.Count} installed Uplay games");
diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs
index 7d2074f..b68add6 100644
--- a/DisplayMagician/Properties/AssemblyInfo.cs
+++ b/DisplayMagician/Properties/AssemblyInfo.cs
@@ -26,8 +26,8 @@ using System.Resources;
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
// Version information
-[assembly: AssemblyVersion("2.0.1.95")]
-[assembly: AssemblyFileVersion("2.0.1.95")]
+[assembly: AssemblyVersion("2.0.1.123")]
+[assembly: AssemblyFileVersion("2.0.1.123")]
[assembly: NeutralResourcesLanguageAttribute( "en" )]
[assembly: CLSCompliant(true)]