public LaunchManagerResult LaunchGameHandlingDelaysAndTitles(BackgroundWorker worker) { var result = new LaunchManagerResult(); if (worker.CancellationPending) { return(result); } DateTime lastLaunchUtc = (_accountLaunchTimes.ContainsKey(_launchItem.AccountName) ? _accountLaunchTimes[_launchItem.AccountName] : DateTime.MinValue); // Add a 5 second delay before launching the same account. EMU servers won't have cross-server timouts like Live servers did. TimeSpan delay = new TimeSpan(0, 0, 5) - (DateTime.UtcNow - lastLaunchUtc); GameLaunchResult gameLaunchResult = null; while (delay.TotalMilliseconds > 0) { if (worker.CancellationPending) { return(result); } string context = string.Format("Waiting {0} sec", (int)delay.TotalSeconds + 1); ReportStatus(context, _launchItem); System.Threading.Thread.Sleep(1000); delay = new TimeSpan(0, 0, 5) - (DateTime.UtcNow - lastLaunchUtc); } ReportStatus("Launching", _launchItem); _accountLaunchTimes[_launchItem.AccountName] = DateTime.UtcNow; var launcher = new GameLauncher(); launcher.ReportGameStatusEvent += (o) => { ReportStatus(o, _launchItem); }; launcher.StopLaunchEvent += (o, eventArgs) => { return(worker.CancellationPending); }; try { var finder = new ThwargUtils.WindowFinder(); finder.RecordExistingWindows(); string launcherPath = GetLaunchItemLauncherLocation(_launchItem); OverridePreferenceFile(_launchItem.CustomPreferencePath); gameLaunchResult = launcher.LaunchGameClient( launcherPath, _launchItem.ServerName, accountName: _launchItem.AccountName, password: _launchItem.Password, ipAddress: _launchItem.IpAndPort, emu: _launchItem.EMU, desiredCharacter: _launchItem.CharacterSelected, rodatSetting: _launchItem.RodatSetting, simpleLaunch: _launchItem.IsSimpleLaunch ); if (!gameLaunchResult.Success) { return(result); } string gameCaptionPattern = ConfigSettings.GetConfigString("GameCaptionPattern", null); if (gameCaptionPattern != null) { var regex = new System.Text.RegularExpressions.Regex(gameCaptionPattern); IntPtr hwnd = finder.FindNewWindow(regex); if (hwnd != IntPtr.Zero) { string newGameTitle = GetNewGameTitle(_launchItem); if (!string.IsNullOrEmpty(newGameTitle)) { finder.SetWindowTitle(hwnd, newGameTitle); } } } } catch (Exception exc) { ReportStatus("Exception launching game launcher: " + exc.Message, _launchItem); return(result); } if (gameLaunchResult != null && gameLaunchResult.Success) { result.Success = true; result.ProcessId = gameLaunchResult.ProcessId; } return(result); }
/// <summary> /// Read all process files /// Check if any characters have changed /// </summary> private void PerformReadProcessFiles() { foreach (var gameSession in _map.GetAllGameSessions()) { string heartbeatFile = gameSession.ProcessStatusFilepath; if (string.IsNullOrEmpty(heartbeatFile)) { // This occurs when launching game session continue; } var response = ThwargFilter.LaunchControl.GetHeartbeatStatus(heartbeatFile); if (!response.IsValid) { Logger.WriteError(string.Format("Invalid contents in heartbeat file: {0}", heartbeatFile)); continue; } var status = GetStatusFromHeartbeatFileTime(gameSession); if (!response.Status.IsOnline) { int gameInteractionTimeoutSeconds = ConfigSettings.GetConfigInt("GameInteractionTimeoutSeconds", 120); // ThwargFilter reports !IsOnline if server dispatch quits firing // but that isn't reliable, as it doesn't fire when not logged in to a character if (response.Status.LastServerDispatchSecondsAgo > gameInteractionTimeoutSeconds) { status = ServerAccountStatusEnum.None; Logger.WriteInfo("Killing offline/character screen game"); } } else { _lastOnlineTimeUtc = DateTime.UtcNow; } if (status == ServerAccountStatusEnum.None) { if (!Globals.NeverKillClients) { Process p = TryGetProcessFromId(response.Status.ProcessId); if (p != null) { p.Kill(); File.Delete(heartbeatFile); _map.RemoveGameSessionByProcessId(p.Id); Logger.WriteDebug("Killing process: " + p.Id.ToString()); OnGameDied(new EventArgs()); } } } bool newGame = false; bool changedGame = false; bool changedStatus = false; if (gameSession.AccountName == null) { newGame = true; } else if (gameSession.AccountName != response.Status.AccountName || gameSession.ServerName != response.Status.ServerName) { // This doesn't make sense and shouldn't happen // Account & Server should be fixed for the life of a game session Logger.WriteError(string.Format("Account/Server change in heartbeat file!: {0}", heartbeatFile)); changedGame = true; } else if (gameSession.CharacterName != response.Status.CharacterName) { changedGame = true; } else if (gameSession.Status != status) { changedStatus = true; gameSession.Status = status; } UpdateGameSessionFromHeartbeatStatus(gameSession, heartbeatFile, response); if (newGame) { NotifyGameChange(gameSession, GameChangeType.StartGame); } else if (changedGame) { NotifyGameChange(gameSession, GameChangeType.ChangeGame); } else if (changedStatus) { NotifyGameChange(gameSession, GameChangeType.ChangeStatus); } } _lastReadProcesFilesUtc = DateTime.UtcNow; }