diff --git a/DlssUpdater/DLSSUpdater.csproj b/DlssUpdater/DLSSUpdater.csproj index 4996c1b..ac9e79d 100644 --- a/DlssUpdater/DLSSUpdater.csproj +++ b/DlssUpdater/DLSSUpdater.csproj @@ -9,11 +9,11 @@ enable enable x64 - 2.0.3.0 + 2.0.4.0 true win-x64 False - 2.0.3.0 + 2.0.4.0 diff --git a/DlssUpdater/Defines/GameInfo.cs b/DlssUpdater/Defines/GameInfo.cs index 45063db..87c6242 100644 --- a/DlssUpdater/Defines/GameInfo.cs +++ b/DlssUpdater/Defines/GameInfo.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text.Json; using System.Text.Json.Serialization; @@ -58,19 +59,25 @@ public GameInfo(GameInfo gameInfo) { GameName = gameInfo.GameName; GamePath = gameInfo.GamePath; - GameImageUri = gameInfo.GameImageUri; LibraryType = gameInfo.LibraryType; _removeVisible = LibraryType == LibraryType.Manual ? Visibility.Visible : Visibility.Collapsed; UniqueId = gameInfo.UniqueId; IsHidden = gameInfo.IsHidden; - GameImage = gameInfo.GameImage; - InstalledDlls = gameInfo.InstalledDlls; + GameImageUri = gameInfo.GameImageUri; + foreach(var kvp in gameInfo.InstalledDlls) + { + InstalledDlls.Add(kvp.Key, kvp.Value); + } _updater = gameInfo._updater; _logger = gameInfo._logger; _libPage = gameInfo._libPage; - InstalledVersionDlss = "N/A"; - InstalledVersionDlssD = "N/A"; - InstalledVersionDlssG = "N/A"; + InstalledVersionDlss = gameInfo.InstalledVersionDlss; + InstalledVersionDlssD = gameInfo.InstalledVersionDlssD; + InstalledVersionDlssG = gameInfo._installedVersionDlssG; + GenerateGameImage(); + setLibraryImage(); + setHideImage(); + SetAntiCheatImage(); Self = this; } @@ -210,6 +217,10 @@ public bool HasInstalledDlls() public void SetGameImageUri(string imageUri) { GameImageUri = imageUri; + } + + public void GenerateGameImage() + { try { if (!string.IsNullOrEmpty(GameImageUri)) @@ -217,7 +228,7 @@ public void SetGameImageUri(string imageUri) GameImage = new BitmapImage(new Uri(GameImageUri)); } } - catch(FileNotFoundException ex) + catch (FileNotFoundException ex) { _logger.Error($"Image not found: {ex}"); } @@ -263,7 +274,11 @@ public class GameConvert : JsonConverter } info.UniqueId = uniqueId!; info.IsHidden = isHidden; - if (!string.IsNullOrEmpty(gameImageUri)) info.SetGameImageUri(gameImageUri); + if (!string.IsNullOrEmpty(gameImageUri)) + { + info.SetGameImageUri(gameImageUri); + info.GenerateGameImage(); + } return info; } diff --git a/DlssUpdater/GameLibrary/EpicGames/EpicGamesLibrary.cs b/DlssUpdater/GameLibrary/EpicGames/EpicGamesLibrary.cs index 19596a3..c151c3b 100644 --- a/DlssUpdater/GameLibrary/EpicGames/EpicGamesLibrary.cs +++ b/DlssUpdater/GameLibrary/EpicGames/EpicGamesLibrary.cs @@ -3,6 +3,7 @@ using System.Text; using System.Text.Json; using System.Xml.Linq; +using DlssUpdater; using DlssUpdater.GameLibrary; using DlssUpdater.Helpers; using DLSSUpdater.Defines; @@ -90,57 +91,72 @@ private async Task> getGames() } } + List tasks = []; + var throttler = new SemaphoreSlim(initialCount: Settings.Constants.CoreCount); var files = Directory.GetFiles(path); foreach (var file in files) { - var data = await File.ReadAllBytesAsync(file); - var yourObject = JsonDocument.Parse(data); - - try + var task = Task.Run(async () => { - var isApp = yourObject.RootElement.GetProperty("bIsApplication").GetBoolean(); - if (!isApp) - { - continue; - } - - var displayName = yourObject.RootElement.GetProperty("DisplayName").GetString(); - var location = yourObject.RootElement.GetProperty("InstallLocation").GetString()?.Replace('/', '\\'); - var catalogId = yourObject.RootElement.GetProperty("CatalogItemId").GetString(); - - var cachedData = cachedGames.FirstOrDefault(g => g.Id == catalogId); - if (cachedData is null || string.IsNullOrEmpty(displayName) || string.IsNullOrEmpty(location)) - { - continue; - } + // do an async wait until we can schedule again + await throttler.WaitAsync(); - var imageObj = cachedData.KeyImages.FirstOrDefault(i => i.Type == "DieselGameBoxTall"); + var data = await File.ReadAllBytesAsync(file); + var yourObject = JsonDocument.Parse(data); - var info = new GameInfo(displayName, location, GetLibraryType()) - { - UniqueId = "epic_" + catalogId! - }; - if (imageObj is not null && !string.IsNullOrEmpty(imageObj.Url)) + try { - info.SetGameImageUri(imageObj.Url); + var isApp = yourObject.RootElement.GetProperty("bIsApplication").GetBoolean(); + if (!isApp) + { + return; + } + + var displayName = yourObject.RootElement.GetProperty("DisplayName").GetString(); + var location = yourObject.RootElement.GetProperty("InstallLocation").GetString()?.Replace('/', '\\'); + var catalogId = yourObject.RootElement.GetProperty("CatalogItemId").GetString(); + + var cachedData = cachedGames.FirstOrDefault(g => g.Id == catalogId); + if (cachedData is null || string.IsNullOrEmpty(displayName) || string.IsNullOrEmpty(location)) + { + return; + } + + var imageObj = cachedData.KeyImages.FirstOrDefault(i => i.Type == "DieselGameBoxTall"); + + var info = new GameInfo(displayName, location, GetLibraryType()) + { + UniqueId = "epic_" + catalogId! + }; + if (imageObj is not null && !string.IsNullOrEmpty(imageObj.Url)) + { + info.SetGameImageUri(imageObj.Url); + } + + await info.GatherInstalledVersions(); + if (info.HasInstalledDlls()) + { + ret.Add(info); + } + else + { + _logger.Debug($"EpicGames: '{info.GameName}' does not have any DLSS dll and is being ignored."); + } } - - await info.GatherInstalledVersions(); - if (info.HasInstalledDlls()) + catch (Exception ex) { - ret.Add(info); + _logger.Warn($"EpicGames Parsing manifest failed with: {ex}"); } - else + finally { - _logger.Debug($"EpicGames: '{info.GameName}' does not have any DLSS dll and is being ignored."); + throttler.Release(); } - } - catch (Exception ex) - { - _logger.Warn($"EpicGames Parsing manifest failed with: {ex}"); - } + }); + + tasks.Add(task); } + await Task.WhenAll(tasks); return ret; } diff --git a/DlssUpdater/GameLibrary/GOGLibrary.cs b/DlssUpdater/GameLibrary/GOGLibrary.cs index 9ff204e..185fd17 100644 --- a/DlssUpdater/GameLibrary/GOGLibrary.cs +++ b/DlssUpdater/GameLibrary/GOGLibrary.cs @@ -1,5 +1,6 @@ using System.IO; using System.Text.Json; +using DlssUpdater; using DlssUpdater.GameLibrary; using DlssUpdater.Helpers; using DLSSUpdater.Defines; @@ -51,47 +52,66 @@ private async Task> getGames() return ret; } + List tasks = []; + var throttler = new SemaphoreSlim(initialCount: Settings.Constants.CoreCount); foreach (var subKey in subKeys) { - var gameKey = hklm.OpenSubKey(Path.Combine(@"SOFTWARE\GOG.com\Games", subKey)); - if (gameKey == null) + var task = Task.Run(async () => { - continue; - } - - var dependsOn = gameKey.GetValue("dependsOn") as string; - if (!string.IsNullOrEmpty(dependsOn)) - { - continue; - } - - var name = gameKey.GetValue("gameName") as string; - var path = gameKey.GetValue("path") as string; - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(path)) - { - continue; - } - - var info = new GameInfo(name, path, GetLibraryType()) - { - UniqueId = "gog_" + subKey - }; - var gameImage = await getGameImage(subKey) ?? string.Empty; - if (!string.IsNullOrEmpty(gameImage)) - { - info.SetGameImageUri(gameImage); - } - - await info.GatherInstalledVersions(); - if (info.HasInstalledDlls()) - { - ret.Add(info); - } - else - { - _logger.Debug($"GOG: '{info.GameName}' does not have any DLSS dll and is being ignored."); - } + try + { + // do an async wait until we can schedule again + await throttler.WaitAsync(); + + var gameKey = hklm.OpenSubKey(Path.Combine(@"SOFTWARE\GOG.com\Games", subKey)); + if (gameKey == null) + { + return; + } + + var dependsOn = gameKey.GetValue("dependsOn") as string; + if (!string.IsNullOrEmpty(dependsOn)) + { + return; + } + + var name = gameKey.GetValue("gameName") as string; + var path = gameKey.GetValue("path") as string; + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(path)) + { + return; + } + + var info = new GameInfo(name, path, GetLibraryType()) + { + UniqueId = "gog_" + subKey + }; + var gameImage = await getGameImage(subKey) ?? string.Empty; + if (!string.IsNullOrEmpty(gameImage)) + { + info.SetGameImageUri(gameImage); + } + + await info.GatherInstalledVersions(); + if (info.HasInstalledDlls()) + { + ret.Add(info); + } + else + { + _logger.Debug($"GOG: '{info.GameName}' does not have any DLSS dll and is being ignored."); + } + } + finally + { + throttler.Release(); + } + }); + + tasks.Add(task); } + await Task.WhenAll(tasks); + return ret; } diff --git a/DlssUpdater/GameLibrary/Steam/SteamLibrary.cs b/DlssUpdater/GameLibrary/Steam/SteamLibrary.cs index 3b381e7..7122112 100644 --- a/DlssUpdater/GameLibrary/Steam/SteamLibrary.cs +++ b/DlssUpdater/GameLibrary/Steam/SteamLibrary.cs @@ -68,7 +68,12 @@ private async Task> getLibraryFolders() for (var i = 0; i < paths.Count; i++) { var path = paths[i]; - var appIds = apps[i]; + List appIds = []; + foreach (var a in apps[i]) + { + appIds.Add(a); + } + LibraryFolder folder = new(Path.Combine(path, "steamapps")) { Apps = appIds @@ -93,27 +98,43 @@ public void GetInstallationDirectory() private async Task> getGames(List folder) { + List tasks = []; List ret = []; + var throttler = new SemaphoreSlim(initialCount: Settings.Constants.CoreCount); + foreach (var folderItem in folder) { foreach (var app in folderItem.Apps) { - var appPath = Path.Combine(folderItem.Path, $"appmanifest_{app}.acf"); - if (!File.Exists(appPath)) + var task = Task.Run(async () => { - _logger.Warn($"Steam: {appPath} not found."); - continue; - } - - var info = await getGameFromManifest(appPath, app); - if (info is not null) - { - ret.Add(info); - } + // do an async wait until we can schedule again + await throttler.WaitAsync(); + + var appPath = Path.Combine(folderItem.Path, $"appmanifest_{app}.acf"); + if (!File.Exists(appPath)) + { + _logger.Warn($"Steam: {appPath} not found."); + } + else + { + + var info = await getGameFromManifest(appPath, app); + if (info is not null) + { + ret.Add(info); + } + } + + throttler.Release(); + }); + tasks.Add(task); } } + await Task.WhenAll(tasks); + return ret; } @@ -136,6 +157,7 @@ private async Task> getGames(List folder) _logger.Warn($"Steam: getGameFromManifest could not find file {finalGamePath}"); return null; } + var info = new GameInfo(gameName[0], finalGamePath, LibraryType.Steam) { UniqueId = "steam_" + appId, @@ -150,7 +172,6 @@ private async Task> getGames(List folder) if (info.HasInstalledDlls()) return info; _logger.Debug($"Steam: '{info.GameName}' does not have any DLSS dll and is being ignored."); - return null; } diff --git a/DlssUpdater/GameLibrary/UbisoftConnectLibrary.cs b/DlssUpdater/GameLibrary/UbisoftConnectLibrary.cs index 7a34a53..1442b74 100644 --- a/DlssUpdater/GameLibrary/UbisoftConnectLibrary.cs +++ b/DlssUpdater/GameLibrary/UbisoftConnectLibrary.cs @@ -63,58 +63,76 @@ private async Task> getGames() var data = await File.ReadAllTextAsync(configPath); var entries = data.Split("root:", StringSplitOptions.TrimEntries); + List tasks = []; + var throttler = new SemaphoreSlim(initialCount: Settings.Constants.CoreCount); foreach (var entry in entries) { - var result = entry - .Split("\n") - .Select(x => x.Split(':')) - .SafeToDictionary(x => x[0].Trim(), x => x.Length >= 2 ? x[1].Trim() : ""); - - if (!result.TryGetValue("name", out var name)) - { - continue; - } - if (!result.TryGetValue("register", out var registerKey)) - { - continue; - } - if (!result.TryGetValue("thumb_image", out var thumbImage)) - { - continue; - } - if (!result.TryGetValue("app_id", out var appId)) + var task = Task.Run(async () => { - continue; - } - - var gamePath = RegistryHelper.GetRegistryValue(registerKey.Replace("HKEY_LOCAL_MACHINE\\", "") - .Replace("\\InstallDir", ""), "InstallDir") as string; - if (string.IsNullOrEmpty(gamePath)) - { - _logger.Warn($"Ubisoft connect: Could not find regkey for {registerKey}"); - continue; - } - - var info = new GameInfo(name, gamePath, LibraryType.Ubisoft) - { - UniqueId = "ubi_" + appId - }; - await info.GatherInstalledVersions(); - if (info.HasInstalledDlls()) - { - var imageUri = getGameImage(thumbImage); - if (imageUri != null) + try { - info.SetGameImageUri(imageUri); + // do an async wait until we can schedule again + await throttler.WaitAsync(); + + var result = entry + .Split("\n") + .Select(x => x.Split(':')) + .SafeToDictionary(x => x[0].Trim(), x => x.Length >= 2 ? x[1].Trim() : ""); + + if (!result.TryGetValue("name", out var name)) + { + return; + } + if (!result.TryGetValue("register", out var registerKey)) + { + return; + } + if (!result.TryGetValue("thumb_image", out var thumbImage)) + { + return; + } + if (!result.TryGetValue("app_id", out var appId)) + { + return; + } + + var gamePath = RegistryHelper.GetRegistryValue(registerKey.Replace("HKEY_LOCAL_MACHINE\\", "") + .Replace("\\InstallDir", ""), "InstallDir") as string; + if (string.IsNullOrEmpty(gamePath)) + { + _logger.Warn($"Ubisoft connect: Could not find regkey for {registerKey}"); + return; + } + + var info = new GameInfo(name, gamePath, LibraryType.Ubisoft) + { + UniqueId = "ubi_" + appId + }; + await info.GatherInstalledVersions(); + if (info.HasInstalledDlls()) + { + var imageUri = getGameImage(thumbImage); + if (imageUri != null) + { + info.SetGameImageUri(imageUri); + } + ret.Add(info); + } + else + { + _logger.Debug($"Ubisoft connect: '{info.GameName}' does not have any DLSS dll and is being ignored."); + } } - ret.Add(info); - } - else - { - _logger.Debug($"Ubisoft connect: '{info.GameName}' does not have any DLSS dll and is being ignored."); - } + finally + { + throttler.Release(); + } + }); + tasks.Add(task); } + await Task.WhenAll(tasks); + return ret; } diff --git a/DlssUpdater/GameLibrary/XboxLibrary.cs b/DlssUpdater/GameLibrary/XboxLibrary.cs index 1dba29f..262c10e 100644 --- a/DlssUpdater/GameLibrary/XboxLibrary.cs +++ b/DlssUpdater/GameLibrary/XboxLibrary.cs @@ -41,101 +41,119 @@ public void GetInstallationDirectory() private async Task> getGames() { + List tasks = []; + var throttler = new SemaphoreSlim(initialCount: Settings.Constants.CoreCount); List ret = []; var drive = DriveInfo.GetDrives(); foreach (var driveItem in drive) { - if (driveItem.DriveType != DriveType.Fixed) + var task = Task.Run(async () => { - continue; - } - - var rootFile = Path.Combine(driveItem.RootDirectory.FullName, ".GamingRoot"); - if(!File.Exists(rootFile)) - { - continue; - } - - var fileData = await File.ReadAllTextAsync(rootFile); - fileData = fileData.Replace("\0", string.Empty); - fileData = fileData.Replace("\u0001", string.Empty); - if (!fileData.StartsWith("RGBX")) - { - continue; - } - - fileData = fileData.Replace("RGBX", string.Empty); - - var gamePath = Path.Combine(driveItem.RootDirectory.FullName, fileData); - if(!Path.Exists(gamePath)) - { - continue; - } - - var gameDirs = Directory.GetDirectories(gamePath); - foreach (var gameDir in gameDirs) - { - var manifestPath = Path.Combine(gameDir, "Content", "appxmanifest.xml"); - if (!File.Exists(manifestPath)) + try { - continue; - } - - // Load the XML file - XDocument xmlDoc = XDocument.Load(manifestPath); - - // Extract the "uap" namespace dynamically from the XML - XNamespace uap = xmlDoc.Root?.GetNamespaceOfPrefix("uap")!; - - // Query the SplashScreen element and get the Image attribute - var splashScreenImage = xmlDoc - .Descendants(uap + "SplashScreen") - .FirstOrDefault()?.Attribute("Image")?.Value; - - // Query the DisplayName inside uap:VisualElements - var displayName = xmlDoc - .Descendants(uap + "VisualElements") - .FirstOrDefault()?.Attribute("DisplayName")?.Value; + // do an async wait until we can schedule again + await throttler.WaitAsync(); - // Extract the namespace (if any is necessary) - XNamespace ns = xmlDoc.Root!.Name.Namespace; - - // Query all Application elements and get their Id attributes - var id = xmlDoc - .Descendants(ns + "Application") // Include the namespace for the Application element - .Select(app => app.Attribute("Id")?.Value).FirstOrDefault(); + if (driveItem.DriveType != DriveType.Fixed) + { + return; + } - string imagePathFinal = ""; - if(splashScreenImage != null) - { - imagePathFinal = Path.Combine(gameDir, "Content", splashScreenImage); - } - - if (!string.IsNullOrEmpty(displayName)) - { - var info = new GameInfo(displayName, gameDir, GetLibraryType()) + var rootFile = Path.Combine(driveItem.RootDirectory.FullName, ".GamingRoot"); + if (!File.Exists(rootFile)) { - UniqueId = "xbox_" + id, - }; - if (!string.IsNullOrEmpty(imagePathFinal)) + return; + } + + var fileData = await File.ReadAllTextAsync(rootFile); + fileData = fileData.Replace("\0", string.Empty); + fileData = fileData.Replace("\u0001", string.Empty); + if (!fileData.StartsWith("RGBX")) { - info.SetGameImageUri(imagePathFinal); + return; } - - await info.GatherInstalledVersions(); - if (info.HasInstalledDlls()) + + fileData = fileData.Replace("RGBX", string.Empty); + + var gamePath = Path.Combine(driveItem.RootDirectory.FullName, fileData); + if (!Path.Exists(gamePath)) { - ret.Add(info); + return; } - else + + var gameDirs = Directory.GetDirectories(gamePath); + foreach (var gameDir in gameDirs) { - _logger.Debug($"Xbox: '{info.GameName}' does not have any DLSS dll and is being ignored."); + var manifestPath = Path.Combine(gameDir, "Content", "appxmanifest.xml"); + if (!File.Exists(manifestPath)) + { + return; + } + + // Load the XML file + XDocument xmlDoc = XDocument.Load(manifestPath); + + // Extract the "uap" namespace dynamically from the XML + XNamespace uap = xmlDoc.Root?.GetNamespaceOfPrefix("uap")!; + + // Query the SplashScreen element and get the Image attribute + var splashScreenImage = xmlDoc + .Descendants(uap + "SplashScreen") + .FirstOrDefault()?.Attribute("Image")?.Value; + + // Query the DisplayName inside uap:VisualElements + var displayName = xmlDoc + .Descendants(uap + "VisualElements") + .FirstOrDefault()?.Attribute("DisplayName")?.Value; + + // Extract the namespace (if any is necessary) + XNamespace ns = xmlDoc.Root!.Name.Namespace; + + // Query all Application elements and get their Id attributes + var id = xmlDoc + .Descendants(ns + "Application") // Include the namespace for the Application element + .Select(app => app.Attribute("Id")?.Value).FirstOrDefault(); + + string imagePathFinal = ""; + if (splashScreenImage != null) + { + imagePathFinal = Path.Combine(gameDir, "Content", splashScreenImage); + } + + if (!string.IsNullOrEmpty(displayName)) + { + var info = new GameInfo(displayName, gameDir, GetLibraryType()) + { + UniqueId = "xbox_" + id, + }; + if (!string.IsNullOrEmpty(imagePathFinal)) + { + info.SetGameImageUri(imagePathFinal); + } + + await info.GatherInstalledVersions(); + if (info.HasInstalledDlls()) + { + ret.Add(info); + } + else + { + _logger.Debug($"Xbox: '{info.GameName}' does not have any DLSS dll and is being ignored."); + } + } } } - } + finally + { + throttler.Release(); + } + }); + tasks.Add(task); } + await Task.WhenAll(tasks); + return ret; } diff --git a/DlssUpdater/Settings.cs b/DlssUpdater/Settings.cs index 5d11822..083b09b 100644 --- a/DlssUpdater/Settings.cs +++ b/DlssUpdater/Settings.cs @@ -28,6 +28,7 @@ public static class Constants public static string CacheFile { get; } = "cache.json"; public static string SettingsFile { get; } = "settings.json"; public static TimeSpan CacheTime { get; } = TimeSpan.FromMinutes(30); + public static int CoreCount { get; } = Environment.ProcessorCount; } public class Paths diff --git a/DlssUpdater/Singletons/GameContainer.cs b/DlssUpdater/Singletons/GameContainer.cs index da3f3a0..df7d5b0 100644 --- a/DlssUpdater/Singletons/GameContainer.cs +++ b/DlssUpdater/Singletons/GameContainer.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Text.Json; using DlssUpdater.Defines; @@ -56,7 +57,14 @@ public void UpdateLibraries() public async Task LoadGamesAsync() { + _logger.Debug("Starting gathering games"); + Stopwatch stopwatch = Stopwatch.StartNew(); + await loadGamesAsync(); + + stopwatch.Stop(); + var elapsedMs = stopwatch.ElapsedMilliseconds; + _logger.Debug($"Game Loading done. Took {elapsedMs} ms"); } public void RemoveGame(GameInfo game) @@ -129,13 +137,16 @@ private async Task loadGamesAsync() { var id = Games[index].UniqueId; var isHidden = Games[index].IsHidden; - Games[index] = item; + Games[index] = new(item); Games[index].UniqueId = id; Games[index].IsHidden = isHidden; + await Games[index].GatherInstalledVersions(); } else - { - Games.Add(item); + { + var info = new GameInfo(item); + await info.GatherInstalledVersions(); + Games.Add(info); } _watcher.AddFile(item); } diff --git a/DlssUpdater/Views/Windows/GameConfigWindow.xaml.cs b/DlssUpdater/Views/Windows/GameConfigWindow.xaml.cs index f9cfefd..83ca434 100644 --- a/DlssUpdater/Views/Windows/GameConfigWindow.xaml.cs +++ b/DlssUpdater/Views/Windows/GameConfigWindow.xaml.cs @@ -32,7 +32,8 @@ public GameConfigWindow(GameConfigWindowViewModel viewModel, GameContainer gameC ViewModel = viewModel; _logger = logger; _newGame = true; - if(gameInfo is not null) + ViewModel.GameInfo = new("", "", LibraryType.Manual); + if (gameInfo is not null) { watcher.RemoveFile(gameInfo); ViewModel.GameInfo = new(gameInfo); @@ -158,6 +159,7 @@ private void btnImage_Click(object sender, RoutedEventArgs e) if (dlg.ShowDialog() == true) { ViewModel.GameInfo.SetGameImageUri(dlg.FileName); + ViewModel.GameInfo.GenerateGameImage(); updateUi(); } } diff --git a/DlssUpdater/changelog.md b/DlssUpdater/changelog.md index 1ee3a96..d9cd80d 100644 --- a/DlssUpdater/changelog.md +++ b/DlssUpdater/changelog.md @@ -1,4 +1,9 @@ -# 2.0.3.0 +# 2.0.4.0 +* Improve speed of game gather step +* Fix bug after adding a new game the game will be already selected on adding another manual game +* Changing game data in configuration view only applies if clicking apply now not in realtime + +# 2.0.3.0 * "Restore default version" is no longer added multiple times * No longer crashes if the user is not allowed to access a path diff --git a/DlssUpdater/version.json b/DlssUpdater/version.json index 06c69f9..e897162 100644 --- a/DlssUpdater/version.json +++ b/DlssUpdater/version.json @@ -1,3 +1,3 @@ { - "version": "2.0.3.0" + "version": "2.0.4.0" } \ No newline at end of file