using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Security; using System.Drawing; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using HeliosPlus.Resources; using HeliosPlus.Shared; using HtmlAgilityPack; using Microsoft.Win32; using Newtonsoft.Json; namespace HeliosPlus.GameLibraries { public class UplayGame { private static string _uplayExe; private static string _uplayPath; private static string _uplayConfigVdfFile; private static string _registryUplayKey = @"SOFTWARE\\Valve\\Uplay"; private static string _registryAppsKey = $@"{_registryUplayKey}\\Apps"; private static SupportedGameLibrary _library = SupportedGameLibrary.Uplay; //private static string _iconCachePath; private string _gameRegistryKey; private uint _uplayGameId; private string _uplayGameName; private string _uplayGamePath; private string _uplayGameExe; private Icon _uplayGameIcon; private static List _allUplayGames; static UplayGame() { ServicePointManager.ServerCertificateValidationCallback += (send, certificate, chain, sslPolicyErrors) => true; } public UplayGame(uint uplayGameId, string uplayGameName, string uplayGamePath, string uplayGameExe, Icon uplayGameIcon) { _gameRegistryKey = $@"{_registryAppsKey}\\{uplayGameId}"; _uplayGameId = uplayGameId; _uplayGameName = uplayGameName; //_iconCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), // Assembly.GetExecutingAssembly().GetName().Name, @"UplayIconCache"); _uplayGamePath = uplayGamePath; _uplayGameExe = uplayGameExe; _uplayGameIcon = uplayGameIcon; } public uint GameId { get => _uplayGameId; } public SupportedGameLibrary GameLibrary { get => SupportedGameLibrary.Uplay; } public Icon GameIcon { get => _uplayGameIcon; } /* public static string GameIdCacheFilePath { get => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Assembly.GetExecutingAssembly().GetName().Name, @"UplayGamesCache.json"); } */ public bool IsRunning { get { try { using ( var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) { if ((int)key?.GetValue(@"Running", 0) == 1) { return true; } return false; } } catch (SecurityException e) { if (e.Source != null) Console.WriteLine("SecurityException source: {0} - Message: {1}", e.Source, e.Message); throw; } catch (IOException e) { // Extract some information from this exception, and then // throw it to the parent method. if (e.Source != null) Console.WriteLine("IOException source: {0} - Message: {1}", e.Source, e.Message); throw; } } } public bool IsUpdating { get { try { using ( var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) { if ((int)key?.GetValue(@"Updating", 0) == 1) { return true; } return false; } } catch (SecurityException e) { if (e.Source != null) Console.WriteLine("SecurityException source: {0} - Message: {1}", e.Source, e.Message); throw; } catch (IOException e) { // Extract some information from this exception, and then // throw it to the parent method. if (e.Source != null) Console.WriteLine("IOException source: {0} - Message: {1}", e.Source, e.Message); throw; } } } public string GameName { get => _uplayGameName; } public static string UplayExe { get => _uplayExe; } public string GamePath { get => _uplayGamePath; } public static List AllGames { get => _allUplayGames; } public static bool UplayInstalled { get { if (!string.IsNullOrWhiteSpace(UplayGame._uplayExe) && File.Exists(UplayGame._uplayExe)) { return true; } return false; } } /*public static List GetAllGames() { lock (AllGamesLock) { if (_allGames == null) { _allGames = GetCachedGameIds()?.ToList(); } } // Update only once if (!_allGamesUpdated) { if (_allGames?.Count > 0) { UpdateGamesFromWeb(); } else { UpdateGamesFromWeb()?.Join(); } } return _allGames; }*/ public static List GetAllInstalledGames() { List uplayGameList = new List(); _allUplayGames = uplayGameList; try { // Find the UplayExe location, and the UplayPath for later using (var key = Registry.CurrentUser.OpenSubKey(_registryUplayKey, RegistryKeyPermissionCheck.ReadSubTree)) { _uplayExe = (string)key?.GetValue(@"UplayExe", string.Empty) ?? string.Empty; _uplayPath = (string)key?.GetValue(@"UplayPath", string.Empty) ?? string.Empty; } if (_uplayExe == string.Empty) { // Uplay isn't installed, so we return an empty list. return uplayGameList; } List uplayAppIdsInstalled = new List(); // Now look for what games app id's are actually installed on this computer using (RegistryKey uplayAppsKey = Registry.CurrentUser.OpenSubKey(_registryAppsKey, RegistryKeyPermissionCheck.ReadSubTree)) { if (uplayAppsKey != null) { // Loop through the subKeys as they are the Uplay Game IDs foreach (string uplayGameKeyName in uplayAppsKey.GetSubKeyNames()) { uint uplayAppId = 0; if (uint.TryParse(uplayGameKeyName, out uplayAppId)) { using (RegistryKey uplayGameKey = Registry.CurrentUser.OpenSubKey(uplayGameKeyName, RegistryKeyPermissionCheck.ReadSubTree)) { // If the Installed Value is set to 1, then the game is installed // We want to keep track of that for later if ((bool)uplayGameKey.GetValue(@"Installed", 0)) { // Add this Uplay App ID to the list we're keeping for later uplayAppIdsInstalled.Add(uplayAppId); } } } } } } // Now we access the config.vdf that lives in the Uplay Config file, as that lists all // the UplayLibraries. We need to find out where they areso we can interrogate them _uplayConfigVdfFile = Path.Combine(_uplayPath, @"config", @"config.vdf"); string uplayConfigVdfText = File.ReadAllText(_uplayConfigVdfFile); List uplayLibrariesPaths = new List(); // Now we have to parse the config.vdf looking for the location of the UplayLibraries // We look for lines similar to this: "BaseInstallFolder_1" "E:\\UplayLibrary" // There may be multiple so we need to check the whole file Regex uplayLibrariesRegex = new Regex(@"""BaseInstallFolder_\d+""\s+""([^""])"")", RegexOptions.IgnoreCase); // Try to match all lines against the Regex. Match uplayLibrariesMatches = uplayLibrariesRegex.Match(uplayConfigVdfText); // If at least one of them matched! if (uplayLibrariesMatches.Success) { // Loop throug the results and add to an array for (int i = 1; i <= uplayLibrariesMatches.Groups.Count; i++) { Console.WriteLine($"Found uplay library: {uplayLibrariesMatches.Groups[i].Value}"); uplayLibrariesPaths.Add(uplayLibrariesMatches.Groups[i].Value); } } // Now we go off and find the details for the games in each Uplay Library foreach (string uplayLibraryPath in uplayLibrariesPaths) { // Work out the path to the appmanifests for this uplayLibrary string uplayLibraryAppManifestPath = Path.Combine(uplayLibraryPath, @"uplayapps"); // Get the names of the App Manifests for the games installed in this UplayLibrary string[] uplayLibraryAppManifestFilenames = Directory.GetFiles(uplayLibraryAppManifestPath, "appmanifest_*.acf"); // Go through each app and extract it's details foreach (string uplayLibraryAppManifestFilename in uplayLibraryAppManifestFilenames) { // Read in the contents of the file string uplayLibraryAppManifestText = File.ReadAllText(uplayLibraryAppManifestFilename); // Grab the appid from the file Regex appidRegex = new Regex(@"""appid""\s+""(\d+)"")", RegexOptions.IgnoreCase); Match appidMatches = appidRegex.Match(uplayLibraryAppManifestText); if (appidMatches.Success) { uint uplayGameId = 0; string uplayGameName = String.Empty; if (uint.TryParse(appidMatches.Groups[1].Value, out uplayGameId)) { // Check if this game is one that was installed if (uplayAppIdsInstalled.Contains(uplayGameId)) { // This game is an installed game! so we start to populate it with data! // Grab the Uplay game name from the app manifeest file Regex nameRegex = new Regex(@"""name""\s+""([^""])"")", RegexOptions.IgnoreCase); Match nameMatches = nameRegex.Match(uplayLibraryAppManifestText); if (nameMatches.Success) { uplayGameName = nameMatches.Groups[1].Value; // We need to also get the installdir from the app manifeest file Regex installDirRegex = new Regex(@"""installdir""\s+""([^""])"")", RegexOptions.IgnoreCase); Match installDirMatches = installDirRegex.Match(uplayLibraryAppManifestText); if (installDirMatches.Success) { // Construct the full path to the game dir string uplayGameInstallDir = Path.Combine(uplayLibraryPath, @"uplayapps", @"common", installDirMatches.Groups[1].Value); // Get the names of the *.config within the gamesdir. There is one per game, and it is the main game exe // This is the one we want to get the icon from. string[] uplayGameConfigs = Directory.GetFiles(uplayGameInstallDir, "*.config"); // Pick the first one, and use that (as there should only be one). Derive the exe name from it //string uplayGameExe = Path.Combine(uplayGameInstallDir, uplayGameConfigs[0].Remove(uplayGameConfigs[0].LastIndexOf(".config"))); string uplayGameExe = Path.Combine(uplayGameInstallDir, Path.GetFileNameWithoutExtension(uplayGameConfigs[0])); // Now we need to get the Icon Icon uplayGameIcon = Icon.ExtractAssociatedIcon(uplayGameExe); uplayGameList.Add(new UplayGame(uplayGameId, uplayGameName, uplayGameInstallDir, uplayGameExe, uplayGameIcon)); } } } } } } } } catch (SecurityException e) { if (e.Source != null) Console.WriteLine("SecurityException source: {0} - Message: {1}", e.Source, e.Message); throw; } catch (IOException e) { // Extract some information from this exception, and then // throw it to the parent method. if (e.Source != null) Console.WriteLine("IOException source: {0} - Message: {1}", e.Source, e.Message); throw; } return uplayGameList; } /* public static string GetAppName(uint appId) { return GetAllGames()?.FirstOrDefault(g => g.AppId == appId)?.Name; }*/ /* private static void CacheGameIds(IEnumerable gameIds) { try { var json = JsonConvert.SerializeObject(gameIds, Formatting.Indented); if (!string.IsNullOrWhiteSpace(json)) { var dir = Path.GetDirectoryName(GameIdCacheFilePath); if (dir != null) { Directory.CreateDirectory(dir); File.WriteAllText(GameIdCacheFilePath, json, Encoding.Unicode); } } } catch { // ignored } }*/ /* private static GameLibraryAppDetails[] GetCachedGameIds() { try { if (File.Exists(GameIdCacheFilePath)) { var json = File.ReadAllText(GameIdCacheFilePath, Encoding.Unicode); if (!string.IsNullOrWhiteSpace(json)) { return JsonConvert.DeserializeObject(json); } } } catch { // ignored } return null; }*/ /* private static Thread UpdateGamesFromWeb() { if (_allGamesUpdated) { return null; } _allGamesUpdated = true; var thread = new Thread(() => { try { var newGames = new List(); using (var webClient = new WebClient()) { webClient.Headers.Add(@"User-Agent", @"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"); webClient.Headers.Add(@"Accept", @"text/html,application/xhtml+xml,application/xml;"); var response = webClient.OpenRead(@"https://uplaydb.info/api/GetAppList/"); if (response != null) { using (response) { using (var reader = new StreamReader(response)) { var content = reader.ReadToEnd(); if (!string.IsNullOrWhiteSpace(content)) { dynamic appids = JsonConvert.DeserializeObject(content); if (appids != null && appids.success == true) { foreach (var app in appids.data) { try { newGames.Add(new GameLibraryAppDetails(SupportedGameLibrary.Uplay, uint.Parse(app.Name), app.Value.Value)); } catch { // ignored } } } } reader.Close(); } response.Close(); } } } *//* if (newGames.Count > 0) { lock (AllGamesLock) { _allGames = newGames; CacheGameIds(_allGames); } }*//* } catch { // ignored } }); thread.Start(); return thread; }*/ public override string ToString() { var name = _uplayGameName; if (string.IsNullOrWhiteSpace(name)) { name = Language.Unknown; } if (IsRunning) { return name + " " + Language.Running; } if (IsUpdating) { return name + " " + Language.Updating; } /*if (IsInstalled) { return name + " " + Language.Installed; }*/ return name + " " + Language.Not_Installed; } /* public Task DownloadIcon() { return Task.Run(() => { if (!Directory.Exists(IconCachePath)) { try { Directory.CreateDirectory(IconCachePath); } catch { return null; } } var localPath = Path.Combine(IconCachePath, GameId + ".ico"); if (File.Exists(localPath)) { return localPath; } var iconUrl = new HtmlWeb().Load("https://uplaydb.info/app/" + GameId) .DocumentNode.SelectNodes("//a[@href]") .Select(node => node.Attributes["href"].Value) .FirstOrDefault(attribute => attribute.EndsWith(".ico") && attribute.Contains("/" + GameId + "/")); if (!string.IsNullOrWhiteSpace(iconUrl)) { try { using (var client = new WebClient()) { client.DownloadFile(iconUrl, localPath); } } catch { return null; } } return File.Exists(localPath) ? localPath : null; }); }*/ } }