private void Collect() { var detectedError = AcLogHelper.DetermineWhatsGoingOn(_log)?.GetDescription(); if (detectedError != null) { Group("Detected issue"); Add("Error", detectedError); } Group("Versions"); Add("AC", Match(@"AC VERSION : (.*)")); Add("CSP", Match(@"Custom Shaders Patch, (\S*)").TrimEnd('.')); Group("Hardware"); Add("Cores", Match(@"LOGICAL CPU DETECTED: (.*)")); Add("GPU", Match(@"ADAPTER DESCRIPTION\s+DESCRIPTION: (.*)")); Add("VRAM", Match(@"VIDEO MEM: (.*)")); Group("Configuration"); Add("Mode", _video["CAMERA"].GetNonEmpty("MODE")); Add("Resolution", $"{_video["VIDEO"].GetInt("WIDTH", 0)}×{_video["VIDEO"].GetInt("HEIGHT", 0)}"); Add("Fullscreen", _video["VIDEO"].GetBool("FULLSCREEN", false)); Add("YEBIS", _video["POST_PROCESS"].GetBool("ENABLED", false)); Add("FXAA", _video["EFFECTS"].GetBool("FXAA", false)); Add("AC blur", _video["EFFECTS"].GetBool("MOTION_BLUR", false)); Add("Apps", _python.Keys.Where(x => _python[x].GetBool("ACTIVE", false)).OrderBy(x => x) .JoinToString(", ").ToLowerInvariant()); Add("Input", _controls["HEADER"].GetNonEmpty("INPUT_METHOD")); Add("Devices", _controls["CONTROLLERS"].Where(x => x.Key.StartsWith("CON")).Select(x => x.Value).JoinToString(", ")); Group("Race"); Add("Type", _race["REMOTE"].GetBool("ACTIVE", false) ? "Online" : _race["REPLAY"].GetBool("ACTIVE", false) ? "Replay" : "Offline"); Add("Track", _race["RACE"].GetNonEmpty("TRACK")); Add("Layout", _race["RACE"].GetNonEmpty("CONFIG_TRACK")); Add("Car", _race["RACE"].GetNonEmpty("MODEL")); Group("Errors"); Add("Clean", Contains("CLEAN EXIT")); Add("Online", Match("ACClient:: (.+)")); Add("Race", Match("ERROR: RaceManager :: (.+)")); Add("CSP", _cspLog.Split('\n').Where(x => x.Contains("| ERROR |")) .Select(x => x.Split(new[] { '|' }, 3).ElementAtOrDefault(2)?.TrimStart()).NonNull().JoinToString("\n")); Add("Stack", _log.Split(new[] { "CRASH in:" }, StringSplitOptions.None).ElementAtOrDefault(1).Or("none").Trim()); Group("Other logs"); Add("Python", _pyLog); Add("Warnings", _acErrors); }
public async void RunAsync() { string restoreVideoSettings = null; try { if (VideoPresetFilename != null && File.Exists(VideoPresetFilename)) { restoreVideoSettings = AcSettingsHolder.VideoPresets.ExportToPresetData(); AcSettingsHolder.VideoPresets.ImportFromPresetData(File.ReadAllText(VideoPresetFilename)); } await Task.Run(() => Showroom.Start(new Showroom.ShowroomProperties { AcRoot = AcRootDirectory.Instance.Value, CarId = SelectedCar.Id, CarSkinId = SelectedSkinId, ShowroomId = SelectedShowroom.Id, CameraFov = CameraFov, DisableSweetFx = DisableSweetFx, DisableWatermark = DisableWatermark, Filter = ForceFilterAcId ?? SelectedFilter.AcId, UseBmp = false })); var whatsGoingOn = AcLogHelper.TryToDetermineWhatsGoingOn(); if (whatsGoingOn != null) { NonfatalError.Notify(whatsGoingOn.GetDescription(), solutions: new[] { whatsGoingOn.Solution }); } } catch (Exception e) { NonfatalError.Notify(ControlsStrings.Showroom_CannotStart, e); } finally { if (restoreVideoSettings != null) { AcSettingsHolder.VideoPresets.ImportFromPresetData(restoreVideoSettings); } } }
private static async Task <Game.Result> StartAsync_Ui(Game.StartProperties properties, GameMode mode) { using (var ui = _uiFactory.Create()) { Logging.Write($"Starting game: {properties.GetDescription()}"); ui.Show(properties, mode); CancellationTokenSource linked = null; IsInGame = true; try { Game.Result result; using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { Started?.Invoke(null, new GameStartedArgs(properties, mode)); if (mode == GameMode.Race) { properties.SetAdditional(new RaceCommandExecutor(properties)); properties.SetAdditional(new DBoxIntegration()); if (SettingsHolder.Drive.ContinueOnEscape) { properties.SetAdditional(new ContinueRaceHelper()); } } else if (mode == GameMode.Replay) { properties.SetAdditional(new ReplayCommandExecutor(properties)); } var cancellationToken = ui.CancellationToken; if (SettingsHolder.Drive.ImmediateCancel) { var cancelHelper = new ImmediateCancelHelper(); linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancelHelper.GetCancellationToken()); cancellationToken = linked.Token; properties.SetAdditional(cancelHelper); properties.SetKeyboardListener = true; } if (mode == GameMode.Replay) { await PrepareReplay(properties, ui, cancellationToken); } ui.OnProgress("Loading data for Custom Shaders Patch…"); var trackId = string.IsNullOrWhiteSpace(properties.BasicProperties?.TrackConfigurationId) ? properties.BasicProperties?.TrackId : properties.BasicProperties?.TrackId + @"/" + properties.BasicProperties?.TrackConfigurationId; await PatchTracksDataUpdater.Instance.TriggerAutoLoadAsync(trackId); await PatchTracksVaoDataUpdater.Instance.TriggerAutoLoadAsync(trackId); await PatchBackgroundDataUpdater.Instance.TriggerAutoLoadAsync(trackId); await PatchCarsDataUpdater.Instance.TriggerAutoLoadAsync(properties.BasicProperties?.CarId); result = await Game.StartAsync(CreateStarter(properties), properties, new ProgressHandler(ui), cancellationToken); } Logging.Write($"Result: {result?.GetDescription() ?? @"<NULL>"}"); if (ui.CancellationToken.IsCancellationRequested) { ui.OnError(new UserCancelledException()); return(null); } var whatsGoingOn = mode != GameMode.Race || result == null?AcLogHelper.TryToDetermineWhatsGoingOn() : null; if (whatsGoingOn != null) { properties.SetAdditional(whatsGoingOn); } if (mode == GameMode.Race) { var param = new GameEndedArgs(properties, result); Ended?.Invoke(null, param); /* TODO: should set result to null if param.Cancel is true? */ var replayHelper = new ReplayHelper(properties, result); (result == null || param.Cancel ? Cancelled : Finished)?.Invoke(null, new GameFinishedArgs(properties, result)); ui.OnResult(result, replayHelper); } else { ui.OnResult(null, null); } return(result); } catch (Exception e) when(e.IsCancelled()) { // ui.OnError(new UserCancelledException()); ui.OnResult(null, null); return(null); } catch (Exception e) { Logging.Warning(e); ui.OnError(e); return(null); } finally { linked?.Dispose(); IsInGame = false; } } }
private static async Task <Game.Result> StartAsync_Ui(Game.StartProperties properties, GameMode mode) { using (var ui = _uiFactory.Create()) { Logging.Write($"Starting game: {properties.GetDescription()}"); ui.Show(properties, mode); CancellationTokenSource linked = null; IsInGame = true; try { FileUtils.TryToDelete(AcPaths.GetLogFilename()); Game.Result result; using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { Started?.Invoke(null, new GameStartedArgs(properties, mode)); if (mode == GameMode.Race) { properties.SetAdditional(new RaceCommandExecutor(properties)); properties.SetAdditional(new DBoxIntegration()); if (SettingsHolder.Drive.ContinueOnEscape) { properties.SetAdditional(new ContinueRaceHelper()); } } else if (mode == GameMode.Replay) { properties.SetAdditional(new ReplayCommandExecutor(properties)); } var cancellationToken = ui.CancellationToken; if (SettingsHolder.Drive.ImmediateCancel) { var cancelHelper = new ImmediateCancelHelper(); linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancelHelper.GetCancellationToken()); cancellationToken = linked.Token; properties.SetAdditional(cancelHelper); properties.SetKeyboardListener = true; } if (mode == GameMode.Replay) { await PrepareReplay(properties, ui, cancellationToken); } if (SettingsHolder.Drive.LoadPatchDataAutomatically && PatchHelper.IsActive()) { var trackId = string.IsNullOrWhiteSpace(properties.BasicProperties?.TrackConfigurationId) ? properties.BasicProperties?.TrackId : properties.BasicProperties?.TrackId + @"/" + properties.BasicProperties?.TrackConfigurationId; using (var cancellation = new CancellationTokenSource()) { ui.OnProgress("Loading data for Custom Shaders Patch…", AsyncProgressEntry.Indetermitate, () => { cancellation.Cancel(); }); var carName = properties.BasicProperties?.CarId == null ? null : CarsManager.Instance.GetById(properties.BasicProperties?.CarId); var trackName = trackId == null ? null : TracksManager.Instance.GetById(trackId)?.Name ?? trackId; await PatchTracksDataUpdater.Instance.TriggerAutoLoadAsync(trackId, PatchSubProgress($"Config for track {trackName}"), cancellation.Token); await PatchTracksVaoDataUpdater.Instance.TriggerAutoLoadAsync(trackId, PatchSubProgress($"Ambient occlusion patch for track {trackName}"), cancellation.Token); await PatchBackgroundDataUpdater.Instance.TriggerAutoLoadAsync(trackId, PatchSubProgress($"Backgrounds for track {trackName}"), cancellation.Token); await PatchCarsDataUpdater.Instance.TriggerAutoLoadAsync(properties.BasicProperties?.CarId, PatchSubProgress($"Config for car {carName}"), cancellation.Token); await PatchCarsVaoDataUpdater.Instance.TriggerAutoLoadAsync(properties.BasicProperties?.CarId, PatchSubProgress($"Ambient occlusion patch for car {carName}"), cancellation.Token); ui.OnProgress("Final preparations…"); IProgress <AsyncProgressEntry> PatchSubProgress(string target) { return(new Progress <AsyncProgressEntry>(p => ui.OnProgress("Loading data for Custom Shaders Patch…", new AsyncProgressEntry($"{target}\n{p.Message ?? @"…"}", p.IsReady || p.Progress == null ? 0d : p.Progress), () => cancellation.Cancel()))); } } } result = await Game.StartAsync(CreateStarter(properties), properties, new ProgressHandler(ui), cancellationToken); } Logging.Write($"Result: {result?.GetDescription() ?? @"<NULL>"}"); if (ui.CancellationToken.IsCancellationRequested) { ui.OnError(new UserCancelledException()); return(null); } var whatsGoingOn = mode != GameMode.Race || result == null?AcLogHelper.TryToDetermineWhatsGoingOn() : null; if (whatsGoingOn != null) { properties.SetAdditional(whatsGoingOn); } if (mode == GameMode.Race) { var param = new GameEndedArgs(properties, result); Ended?.Invoke(null, param); /* TODO: should set result to null if param.Cancel is true? */ var replayHelper = new ReplayHelper(properties, result); (result == null || param.Cancel ? Cancelled : Finished)?.Invoke(null, new GameFinishedArgs(properties, result)); ui.OnResult(result, replayHelper); } else { ui.OnResult(null, null); } return(result); } catch (Exception e) when(e.IsCancelled()) { // ui.OnError(new UserCancelledException()); ui.OnResult(null, null); return(null); } catch (Exception e) { Logging.Warning(e); ui.OnError(e); return(null); } finally { linked?.Dispose(); IsInGame = false; } } }
private static async Task <Game.Result> StartAsync(Game.StartProperties properties, bool raceMode) { AcSettingsHolder.Graphics.FixShadowMapBias(); if (SettingsHolder.Drive.CopyFilterToSystemForOculus && AcSettingsHolder.Video.CameraMode.Id == "OCULUS") { properties.SetAdditional(new CopyFilterToSystemForOculusHelper()); } if (SettingsHolder.Common.FixResolutionAutomatically) { AcSettingsHolder.Video.EnsureResolutionIsCorrect(); } if (SettingsHolder.Drive.WeatherSpecificClouds) { properties.SetAdditional(new WeatherSpecificCloudsHelper()); } if (SettingsHolder.Drive.WeatherSpecificTyreSmoke) { properties.SetAdditional(new WeatherSpecificTyreSmokeHelper()); } if (SettingsHolder.Live.RsrEnabled && SettingsHolder.Live.RsrDisableAppAutomatically) { PrepareRaceModeRsr(properties); } if (SettingsHolder.Drive.SidekickIntegration && properties.BasicProperties?.CarId != null) { SidekickHelper.UpdateSidekickDatabase(properties.BasicProperties.CarId); } properties.SetAdditional(new WeatherSpecificVideoSettingsHelper()); properties.SetAdditional(new ModeSpecificPresetsHelper()); properties.SetAdditional(new CarSpecificControlsPresetHelper()); if (raceMode) { if (properties.AssistsProperties == null) { properties.AssistsProperties = _defaultAssistsFactory?.Create(); } PrepareRaceModeImmediateStart(properties); PrepareRaceDriverName(properties); Logging.Write("Assists: " + properties.AssistsProperties?.GetDescription()); } if (_uiFactory == null) { using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { if (raceMode) { properties.SetAdditional(new RaceCommandExecutor(properties)); } else { properties.SetAdditional(new ReplayCommandExecutor(properties)); } return(await Game.StartAsync(AcsStarterFactory.Create(), properties, null, CancellationToken.None)); } } using (var ui = _uiFactory.Create()) { Logging.Write($"Starting game: {properties.GetDescription()}"); ui.Show(properties); CancellationTokenSource linked = null; IsInGame = true; try { Game.Result result; using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { if (raceMode) { properties.SetAdditional(new RaceCommandExecutor(properties)); Started?.Invoke(null, new GameStartedArgs(properties)); if (SettingsHolder.Drive.ContinueOnEscape) { properties.SetAdditional(new ContinueRaceHelper()); } } else { properties.SetAdditional(new ReplayCommandExecutor(properties)); } var cancellationToken = ui.CancellationToken; if (SettingsHolder.Drive.ImmediateCancel) { var cancelHelper = new ImmediateCancelHelper(); linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancelHelper.GetCancellationToken()); cancellationToken = linked.Token; properties.SetAdditional(cancelHelper); properties.SetKeyboardListener = true; } result = await Game.StartAsync(AcsStarterFactory.Create(), properties, new ProgressHandler(ui), cancellationToken); } Logging.Write($"Result: {result?.GetDescription() ?? @"<NULL>"}"); if (ui.CancellationToken.IsCancellationRequested) { ui.OnError(new UserCancelledException()); return(null); } if (raceMode) { if (result == null) { var whatsGoingOn = AcLogHelper.TryToDetermineWhatsGoingOn(); if (whatsGoingOn != null) { properties.SetAdditional(whatsGoingOn); } } var param = new GameEndedArgs(properties, result); Ended?.Invoke(null, param); /* TODO: should set result to null if param.Cancel is true? */ var replayHelper = new ReplayHelper(properties, result); (result == null || param.Cancel ? Cancelled : Finished)?.Invoke(null, new GameFinishedArgs(properties, result)); ui.OnResult(result, replayHelper); } else { ui.OnResult(null, null); } return(result); } catch (TaskCanceledException) { // ui.OnError(new UserCancelledException()); ui.OnResult(null, null); return(null); } catch (Exception e) { Logging.Warning(e); ui.OnError(e); return(null); } finally { linked?.Dispose(); IsInGame = false; } } }
public static void Initialize() { AcLogHelper.AddExtension(new LogExtension()); }
private static void UnwrapReport(string filename) { var location = OptionLocation; if (string.IsNullOrWhiteSpace(location)) { location = FilesStorage.Instance.GetTemporaryDirectory("Reports"); } try { using (var stream = File.OpenRead(filename)) using (var archive = new ZipArchive(stream)) { var log = archive.ReadString(@"log.txt"); var detectedError = AcLogHelper.DetermineWhatsGoingOn(log)?.GetDescription(); /*if (detectedError != null) { * if (MessageDialog.Show($"Crash seems familiar: {detectedError.ToSentenceMember()}.\n\nContinue unwrapping?", "Crash report", MessageDialogButton.YesNo) != MessageBoxResult.Yes) { * return; * } * }*/ var username = Regex.Match(log, @"Steam Name:(\S*)").Groups[1].Value; username = Regex.Replace(username, "[^A-Za-z0-9-]+", ""); if (string.IsNullOrEmpty(username)) { username = IniFile.Parse(archive.ReadString(@"race.ini"))["CAR_0"].GetNonEmpty("DRIVER_NAME") ?? ""; username = Regex.Replace(username, "[^A-Za-z0-9-]+", "").Or("-"); } var crashId = username + "_" + Path.GetFileNameWithoutExtension(filename).Replace(@"crash_", ""); var destination = Path.Combine(location, crashId); if (!Directory.Exists(destination)) { Directory.CreateDirectory(destination); } var dump = archive.Entries.FirstOrDefault(x => x.Name.EndsWith(".dmp"))?.Open().ReadAsBytesAndDispose(); if (dump != null) { File.WriteAllBytes(Path.Combine(destination, crashId + ".dmp"), dump); } if (detectedError != null) { var name = FileUtils.EnsureFileNameIsValid(detectedError, false); if (name.Length > 120) { name = name.Substring(0, 120); } File.WriteAllText(Path.Combine(destination, name), detectedError); } File.WriteAllText(Path.Combine(destination, crashId + ".txt"), new SummaryGenerator(archive).Run()); File.WriteAllText(Path.Combine(destination, crashId + ".report-launch"), ""); File.WriteAllBytes(Path.Combine(destination, crashId + ".zip"), File.ReadAllBytes(filename)); WindowsHelper.ViewDirectory(destination); } } catch (Exception e) { NonfatalError.Notify("Failed to load report", e); } }
private async Task RunShootingProcess(bool manualMode = false) { if (SelectedShowroom == null) { if (ShowMessage(AppStrings.CarPreviews_ShowroomIsMissingOptions, AppStrings.Common_OneMoreThing, MessageBoxButton.YesNo) == MessageBoxResult.Yes) { SelectPhase(Phase.Options); } else { _cancelled = true; Top = -9999; await Task.Delay(1); Close(); } return; } if (SelectedFilter == null) { if (ShowMessage(AppStrings.CarPreviews_FilterIsMissingOptions, AppStrings.Common_OneMoreThing, MessageBoxButton.YesNo) == MessageBoxResult.Yes) { SelectPhase(Phase.Options); } else { _cancelled = true; Top = -9999; await Task.Delay(1); Close(); } return; } if (_toUpdate.Any(u => !u.Car.Enabled || u.Skins?.Any(x => x.Enabled == false) == true)) { SelectPhase(Phase.Error, AppStrings.CarPreviews_CannotUpdateForDisabled); return; } Progress = AsyncProgressEntry.FromStringIndetermitate(UiStrings.Common_PleaseWait); SelectPhase(Phase.Waiting); _cancellationTokenSource = new CancellationTokenSource(); try { string filterId; var builtInPpFilter = SelectedFilter as BuiltInPpFilter; if (builtInPpFilter != null) { builtInPpFilter.EnsureInstalled(); filterId = builtInPpFilter.Name; } else { var filterObject = SelectedFilter as PpFilterObject; filterId = filterObject?.Name; } var begin = DateTime.Now; if (_toUpdate.Count > 1 && !ApplyImmediately) { throw new Exception("Can’t apply previews later if there are more than one car"); } for (var i = 0; i < _toUpdate.Count; i++) { var toUpdate = _toUpdate[i]; SeriesProgress = new AsyncProgressEntry(toUpdate.Car.DisplayName, i, _toUpdate.Count); await ShootCar(toUpdate, filterId, manualMode, ApplyImmediately, _cancellationTokenSource.Token); if (_cancellationTokenSource.IsCancellationRequested) { SelectPhase(Phase.Error, AppStrings.CarPreviews_CancelledMessage); return; } } TakenTime = DateTime.Now - begin; SelectPhase(ApplyImmediately ? Phase.ResultSummary : Phase.Result); } catch (ShotingCancelledException e) { SelectPhase(Phase.Error, e.UserCancelled ? AppStrings.CarPreviews_CancelledMessage : e.Message); if (!e.UserCancelled) { Logging.Warning("Cannot update previews: " + e); } } catch (ProcessExitedException e) { SelectPhase(Phase.Error, e.Message, AcLogHelper.TryToDetermineWhatsGoingOn()); Logging.Warning("Cannot update previews: " + e); } catch (Exception e) { SelectPhase(Phase.Error, e.Message); Logging.Warning("Cannot update previews: " + e); } }
private async Task ShootCar([NotNull] ToUpdatePreview toUpdate, string filterId, bool manualMode, bool applyImmediately, CancellationToken cancellation) { if (toUpdate == null) { throw new ArgumentNullException(nameof(toUpdate)); } try { _currentCar = toUpdate.Car; _resultDirectory = await Showroom.ShotAsync(new Showroom.ShotProperties { AcRoot = AcRootDirectory.Instance.Value, CarId = toUpdate.Car.Id, ShowroomId = SelectedShowroom.Id, SkinIds = toUpdate.Skins?.Select(x => x.Id).ToArray(), Filter = filterId, Fxaa = EnableFxaa, SpecialResolution = UseSpecialResolution, MaximizeVideoSettings = MaximizeVideoSettings, Mode = manualMode ? Showroom.ShotMode.ClassicManual : Showroom.ShotMode.Fixed, UseBmp = true, DisableWatermark = DisableWatermark, DisableSweetFx = DisableSweetFx, ClassicCameraDx = 0.0, ClassicCameraDy = 0.0, ClassicCameraDistance = 5.5, FixedCameraPosition = CameraPosition, FixedCameraLookAt = CameraLookAt, FixedCameraFov = CameraFov, FixedCameraExposure = CameraExposure ?? 0d, }, this, cancellation); if (cancellation.IsCancellationRequested) { return; } } catch (ProcessExitedException e) when(applyImmediately) { Errors.Add(new UpdatePreviewError(toUpdate, e.Message, AcLogHelper.TryToDetermineWhatsGoingOn())); return; } if (applyImmediately) { if (_resultDirectory == null) { Errors.Add(new UpdatePreviewError(toUpdate, AppStrings.CarPreviews_SomethingWentWrong, AcLogHelper.TryToDetermineWhatsGoingOn())); } else { Progress = AsyncProgressEntry.Indetermitate; await ImageUtils.ApplyPreviewsAsync(AcRootDirectory.Instance.RequireValue, toUpdate.Car.Id, _resultDirectory, ResizePreviews, new AcPreviewImageInformation { Name = toUpdate.Car.DisplayName, Style = Path.GetFileNameWithoutExtension(UserPresetsControl.SelectedPresetFilename) }, new Progress <Tuple <string, double?> >(t => { Progress = new AsyncProgressEntry($"Applying freshly made previews ({t.Item1})…", t.Item2); }), cancellation); } } else { if (_resultDirectory == null) { SelectPhase(Phase.Error, AppStrings.CarPreviews_SomethingWentWrong, AcLogHelper.TryToDetermineWhatsGoingOn()); return; } ResultPreviewComparisons = new ObservableCollection <ResultPreviewComparison>( Directory.GetFiles(_resultDirectory, "*.*").Select(x => { var id = (Path.GetFileNameWithoutExtension(x) ?? "").ToLower(); return(new ResultPreviewComparison { Name = toUpdate.Car.GetSkinById(id)?.DisplayName ?? id, /* custom paths, because theoretically skin might no longer exist at this point */ LiveryImage = Path.Combine(toUpdate.Car.Location, @"skins", id, @"livery.png"), OriginalImage = Path.Combine(toUpdate.Car.Location, @"skins", id, @"preview.jpg"), UpdatedImage = x }); })); } }
private static async Task <Game.Result> StartAsync_Ui(Game.StartProperties properties, GameMode mode) { using (var ui = _uiFactory.Create()) { Logging.Write($"Starting game: {properties.GetDescription()}"); ui.Show(properties, mode); CancellationTokenSource linked = null; IsInGame = true; try { Game.Result result; using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { if (mode == GameMode.Race) { properties.SetAdditional(new RaceCommandExecutor(properties)); Started?.Invoke(null, new GameStartedArgs(properties)); if (SettingsHolder.Drive.ContinueOnEscape) { properties.SetAdditional(new ContinueRaceHelper()); } } else if (mode == GameMode.Replay) { properties.SetAdditional(new ReplayCommandExecutor(properties)); } var cancellationToken = ui.CancellationToken; if (SettingsHolder.Drive.ImmediateCancel) { var cancelHelper = new ImmediateCancelHelper(); linked = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancelHelper.GetCancellationToken()); cancellationToken = linked.Token; properties.SetAdditional(cancelHelper); properties.SetKeyboardListener = true; } result = await Game.StartAsync(AcsStarterFactory.Create(), properties, new ProgressHandler(ui), cancellationToken); } Logging.Write($"Result: {result?.GetDescription() ?? @"<NULL>"}"); if (ui.CancellationToken.IsCancellationRequested) { ui.OnError(new UserCancelledException()); return(null); } if (mode == GameMode.Race) { if (result == null) { var whatsGoingOn = AcLogHelper.TryToDetermineWhatsGoingOn(); if (whatsGoingOn != null) { properties.SetAdditional(whatsGoingOn); } } var param = new GameEndedArgs(properties, result); Ended?.Invoke(null, param); /* TODO: should set result to null if param.Cancel is true? */ var replayHelper = new ReplayHelper(properties, result); (result == null || param.Cancel ? Cancelled : Finished)?.Invoke(null, new GameFinishedArgs(properties, result)); ui.OnResult(result, replayHelper); } else { ui.OnResult(null, null); } return(result); } catch (Exception e) when(e.IsCanceled()) { // ui.OnError(new UserCancelledException()); ui.OnResult(null, null); return(null); } catch (Exception e) { Logging.Warning(e); ui.OnError(e); return(null); } finally { linked?.Dispose(); IsInGame = false; } } }