From d6c52401af91d2f16dddb9a137d03ed8d470c7ed Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 2 Dec 2024 21:35:32 -0600 Subject: [PATCH 1/3] GOG: Fix automatic install process no longer working --- .../Libraries/GogLibrary/GogGameController.cs | 62 ++++++++++++++----- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/source/Libraries/GogLibrary/GogGameController.cs b/source/Libraries/GogLibrary/GogGameController.cs index 363da772..4653adc3 100644 --- a/source/Libraries/GogLibrary/GogGameController.cs +++ b/source/Libraries/GogLibrary/GogGameController.cs @@ -42,30 +42,22 @@ public override void Install(InstallActionArgs args) { if (Gog.IsInstalled) { - var startedAutomaticInstall = false; + var openGameViewUri = @"goggalaxy://openGameView/" + Game.GameId; if (gogLibrary.SettingsViewModel.Settings.UseAutomaticGameInstalls) { var clientPath = Gog.ClientInstallationPath; if (FileSystem.FileExists(clientPath)) { - var arguments = string.Format(@"/gameId={0} /command=installGame", Game.GameId); - ProcessStarter.StartProcess(clientPath, arguments); - - // Starting a game install via command will add the game to a queue but Galaxy itself - // won't be started to initiate the download process so we need to start it if it's - // not running already - if (!Gog.IsRunning) - { - ProcessStarter.StartProcess(clientPath); - } - - startedAutomaticInstall = true; + InstallGameWithCommand(openGameViewUri, clientPath); + } + else + { + ProcessStarter.StartUrl(openGameViewUri); } } - - if (!startedAutomaticInstall) + else { - ProcessStarter.StartUrl(@"goggalaxy://openGameView/" + Game.GameId); + ProcessStarter.StartUrl(openGameViewUri); } } else @@ -76,6 +68,44 @@ public override void Install(InstallActionArgs args) StartInstallWatcher(); } + private async void InstallGameWithCommand(string openGameViewUri, string clientPath) + { + if (!Gog.IsRunning) + { + ProcessStarter.StartProcess(clientPath); + } + + var maxWaitTime = DateTime.Now.AddSeconds(10); + var waitInterval = TimeSpan.FromMilliseconds(150); + var installCommandUsed = false; + do + { + // The game installation command can only be executed if "GalaxyClient Helper" is running (not just the main GOG client executable) + if (Process.GetProcessesByName("GalaxyClient Helper")?.Any() == true) + { + var arguments = string.Format(@"/gameId={0} /command=installGame", Game.GameId); + ProcessStarter.StartProcess(clientPath, arguments); + installCommandUsed = true; + break; + } + + await Task.Delay(waitInterval); + } while (DateTime.Now <= maxWaitTime); + + maxWaitTime = DateTime.Now.AddSeconds(20); + do + { + // If the install command is used, the game page will only open if GOG is components are initiated + if (!installCommandUsed || Process.GetProcessesByName("GOG Galaxy Notifications Renderer")?.Any() == true) + { + ProcessStarter.StartUrl(openGameViewUri); + return; + } + + await Task.Delay(waitInterval); + } while (DateTime.Now <= maxWaitTime); + } + public async void StartInstallWatcher() { watcherToken = new CancellationTokenSource(); From 49e653aa13bb634b1af5af25b75ae3690074f1b0 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 2 Dec 2024 21:52:04 -0600 Subject: [PATCH 2/3] Increase wait interval --- source/Libraries/GogLibrary/GogGameController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Libraries/GogLibrary/GogGameController.cs b/source/Libraries/GogLibrary/GogGameController.cs index 4653adc3..32f8a382 100644 --- a/source/Libraries/GogLibrary/GogGameController.cs +++ b/source/Libraries/GogLibrary/GogGameController.cs @@ -93,6 +93,7 @@ private async void InstallGameWithCommand(string openGameViewUri, string clientP } while (DateTime.Now <= maxWaitTime); maxWaitTime = DateTime.Now.AddSeconds(20); + waitInterval = TimeSpan.FromMilliseconds(400); do { // If the install command is used, the game page will only open if GOG is components are initiated From 095a5cd20e44ec605d4d30e1262aea03ce038a5e Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 3 Dec 2024 14:11:59 -0600 Subject: [PATCH 3/3] Use detection of client lock files to know when client is ready for commands --- .../Libraries/GogLibrary/GogGameController.cs | 135 +++++++++++------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/source/Libraries/GogLibrary/GogGameController.cs b/source/Libraries/GogLibrary/GogGameController.cs index 32f8a382..6d458a8e 100644 --- a/source/Libraries/GogLibrary/GogGameController.cs +++ b/source/Libraries/GogLibrary/GogGameController.cs @@ -19,10 +19,16 @@ public class GogInstallController : InstallController { private CancellationTokenSource watcherToken; private readonly GogLibrary gogLibrary; + private readonly string openGameViewUri; + private readonly string gogGalaxyLockFilesPath; + private FileSystemWatcher fileSystemWatcher; public GogInstallController(Game game, GogLibrary gogLibrary) : base(game) { this.gogLibrary = gogLibrary; + openGameViewUri = @"goggalaxy://openGameView/" + Game.GameId; + var programDataPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData); + gogGalaxyLockFilesPath = Path.Combine(programDataPath, @"GOG.com\Galaxy\lock-files"); if (Gog.IsInstalled) { Name = "Install using Galaxy"; @@ -36,75 +42,101 @@ public GogInstallController(Game game, GogLibrary gogLibrary) : base(game) public override void Dispose() { watcherToken?.Cancel(); + if (fileSystemWatcher != null) + { + fileSystemWatcher.EnableRaisingEvents = false; + fileSystemWatcher.Changed -= OnFileChanged; + fileSystemWatcher.Created -= OnFileChanged; + fileSystemWatcher.Renamed -= OnFileChanged; + fileSystemWatcher.Dispose(); + fileSystemWatcher = null; + } } public override void Install(InstallActionArgs args) { - if (Gog.IsInstalled) + InitiateInstall(); + StartInstallWatcher(); + } + + private void InitiateInstall() + { + if (!Gog.IsInstalled) { - var openGameViewUri = @"goggalaxy://openGameView/" + Game.GameId; - if (gogLibrary.SettingsViewModel.Settings.UseAutomaticGameInstalls) - { - var clientPath = Gog.ClientInstallationPath; - if (FileSystem.FileExists(clientPath)) - { - InstallGameWithCommand(openGameViewUri, clientPath); - } - else - { - ProcessStarter.StartUrl(openGameViewUri); - } - } - else - { - ProcessStarter.StartUrl(openGameViewUri); - } + ProcessStarter.StartUrl(@"https://www.gog.com/account"); + return; } - else + + if (!gogLibrary.SettingsViewModel.Settings.UseAutomaticGameInstalls) { - ProcessStarter.StartUrl(@"https://www.gog.com/account"); + ProcessStarter.StartUrl(openGameViewUri); + return; } - StartInstallWatcher(); - } + var clientPath = Gog.ClientInstallationPath; + if (!FileSystem.FileExists(clientPath)) + { + ProcessStarter.StartUrl(openGameViewUri); + return; + } - private async void InstallGameWithCommand(string openGameViewUri, string clientPath) - { - if (!Gog.IsRunning) + if (Gog.IsRunning) { + InstallGameWithCommand(); + } + else if (FileSystem.DirectoryExists(gogGalaxyLockFilesPath)) + { + // Install command only works when Galaxy core components are initialized. This can be detected when Galaxy + // has created lock files in its program data directory + InitializeFileSystemWatcher(); ProcessStarter.StartProcess(clientPath); } - - var maxWaitTime = DateTime.Now.AddSeconds(10); - var waitInterval = TimeSpan.FromMilliseconds(150); - var installCommandUsed = false; - do + else { - // The game installation command can only be executed if "GalaxyClient Helper" is running (not just the main GOG client executable) - if (Process.GetProcessesByName("GalaxyClient Helper")?.Any() == true) - { - var arguments = string.Format(@"/gameId={0} /command=installGame", Game.GameId); - ProcessStarter.StartProcess(clientPath, arguments); - installCommandUsed = true; - break; - } + ProcessStarter.StartUrl(openGameViewUri); + } + } + + private async void InstallGameWithCommand() + { + var clientPath = Gog.ClientInstallationPath; + var arguments = string.Format(@"/gameId={0} /command=installGame", Game.GameId); + ProcessStarter.StartProcess(clientPath, arguments); + + // The GOG Galaxy client can't handle two instructions in quick succession + await Task.Delay(2500); + ProcessStarter.StartUrl(openGameViewUri); + } - await Task.Delay(waitInterval); - } while (DateTime.Now <= maxWaitTime); + private void InitializeFileSystemWatcher() + { + fileSystemWatcher = new FileSystemWatcher(gogGalaxyLockFilesPath) + { + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName, + Filter = "*.*", + EnableRaisingEvents = true + }; + + fileSystemWatcher.Changed += OnFileChanged; + fileSystemWatcher.Created += OnFileChanged; + fileSystemWatcher.Renamed += OnFileChanged; + } - maxWaitTime = DateTime.Now.AddSeconds(20); - waitInterval = TimeSpan.FromMilliseconds(400); - do + private void DisableFileSystemWatcher() + { + if (fileSystemWatcher != null) { - // If the install command is used, the game page will only open if GOG is components are initiated - if (!installCommandUsed || Process.GetProcessesByName("GOG Galaxy Notifications Renderer")?.Any() == true) - { - ProcessStarter.StartUrl(openGameViewUri); - return; - } + fileSystemWatcher.EnableRaisingEvents = false; + } + } - await Task.Delay(waitInterval); - } while (DateTime.Now <= maxWaitTime); + private void OnFileChanged(object sender, FileSystemEventArgs e) + { + if (e.Name == "GOG Galaxy Notifications Renderer.exe.lock") + { + DisableFileSystemWatcher(); + InstallGameWithCommand(); + } } public async void StartInstallWatcher() @@ -122,6 +154,7 @@ await Task.Run(async () => var games = GogLibrary.GetInstalledGames(); if (games.ContainsKey(Game.GameId)) { + DisableFileSystemWatcher(); var game = games[Game.GameId]; var installInfo = new GameInstallationData() {