diff --git a/source/Libraries/GogLibrary/GogGameController.cs b/source/Libraries/GogLibrary/GogGameController.cs index 363da772..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,44 +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 startedAutomaticInstall = false; - 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); + ProcessStarter.StartUrl(@"https://www.gog.com/account"); + return; + } - // 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); - } + if (!gogLibrary.SettingsViewModel.Settings.UseAutomaticGameInstalls) + { + ProcessStarter.StartUrl(openGameViewUri); + return; + } - startedAutomaticInstall = true; - } - } + var clientPath = Gog.ClientInstallationPath; + if (!FileSystem.FileExists(clientPath)) + { + ProcessStarter.StartUrl(openGameViewUri); + return; + } - if (!startedAutomaticInstall) - { - ProcessStarter.StartUrl(@"goggalaxy://openGameView/" + Game.GameId); - } + 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); } else { - ProcessStarter.StartUrl(@"https://www.gog.com/account"); + ProcessStarter.StartUrl(openGameViewUri); } + } - StartInstallWatcher(); + 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); + } + + private void InitializeFileSystemWatcher() + { + fileSystemWatcher = new FileSystemWatcher(gogGalaxyLockFilesPath) + { + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName, + Filter = "*.*", + EnableRaisingEvents = true + }; + + fileSystemWatcher.Changed += OnFileChanged; + fileSystemWatcher.Created += OnFileChanged; + fileSystemWatcher.Renamed += OnFileChanged; + } + + private void DisableFileSystemWatcher() + { + if (fileSystemWatcher != null) + { + fileSystemWatcher.EnableRaisingEvents = false; + } + } + + private void OnFileChanged(object sender, FileSystemEventArgs e) + { + if (e.Name == "GOG Galaxy Notifications Renderer.exe.lock") + { + DisableFileSystemWatcher(); + InstallGameWithCommand(); + } } public async void StartInstallWatcher() @@ -91,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() {