private static async Task PrepareReplay(Game.StartProperties properties, IGameUi ui, CancellationToken cancellation) { var replayProperties = properties.ReplayProperties; if (replayProperties != null) { var replayFilename = replayProperties.Filename ?? Path.Combine(AcPaths.GetReplaysDirectory(), replayProperties.Name); ui.OnProgress("Checking replay for fake cars…"); var fakes = await FakeCarsHelper.GetFakeCarsIds(replayFilename); if (fakes.Count > 0) { Logging.Debug("Fakes found: " + fakes.Select(x => $"{x.FakeId} ({x.SourceId})").JoinToString(", ")); foreach (var fake in fakes) { var car = CarsManager.Instance.GetById(fake.SourceId); if (car != null) { FakeCarsHelper.CreateFakeCar(car, fake.FakeId, null); } else { Logging.Warning("Original not found: " + fake.SourceId); } } } } }
void IGameUi.Show(Game.StartProperties properties) { _properties = properties; ShowDialogWithoutBlocking(); Model.WaitingStatus = AppStrings.Race_Initializing; }
private static void PrepareRaceDriverName(Game.StartProperties properties) { if (properties.HasAdditional <SrsMark>()) { return; } if (properties.BasicProperties?.DriverName != null) { properties.SetAdditional(new DriverName(properties.BasicProperties.DriverName, properties.BasicProperties.DriverNationality)); return; } if (properties.ModeProperties is Game.OnlineProperties online && SettingsHolder.Live.SrsEnabled && SettingsHolder.Live.SrsAutoMode) { var filter = Filter.Create(new StringTester(), SettingsHolder.Live.SrsAutoMask, true); if (filter.Test(online.ServerName ?? "")) { Logging.Write("Looks like this is a SRS server, let’s use SRS name"); properties.SetAdditional(new SrsMark { Name = SrsMark.GetName(), Nationality = "", Team = "" }); return; } } properties.SetAdditional(new DriverName()); }
private static void PrepareRaceModeImmediateStart(Game.StartProperties properties) { if (!SettingsHolder.Drive.ImmediateStart) { return; } properties.SetAdditional(new ImmediateStart()); }
private static IAcsStarter CreateStarter(Game.StartProperties properties) { var starter = AcsStarterFactory.Create(); if (SettingsHolder.Drive.PatchAcToDisableShadows && AcShadowsPatcher.IsSupposedToWork()) { properties.SetAdditional(new AcShadowsPatcher(starter)); } return(starter); }
private static void StartAsync_AdjustProperties(Game.StartProperties properties) { if (SettingsHolder.Integrated.RsrLimitTemperature && properties.ConditionProperties != null && (properties.ConditionProperties.AmbientTemperature < 10d || properties.ConditionProperties.RoadTemperature < 10d) && AcSettingsHolder.Python.IsActivated("RsrLiveTime")) { Toast.Show("Temperature Set To 10 °C", "RSR is active, and according to its rules, you are not allowed to use temperatures lower than 10 °C"); properties.ConditionProperties.AmbientTemperature = 10d; properties.ConditionProperties.RoadTemperature = 10d; } }
private static void StartAsync_Prepare(Game.StartProperties properties) { if (!_nationCodesProviderSet) { _nationCodesProviderSet = true; try { Game.NationCodeProvider = NationCodeProvider.Instance; } catch (Exception e) { Logging.Unexpected(e); } } AcSettingsHolder.Graphics.FixShadowMapBias(); if (SettingsHolder.Drive.CopyFilterToSystemForOculus && AcSettingsHolder.Video.CameraMode.Id == "OCULUS") { properties.SetAdditional(new CopyFilterToSystemForOculusHelper()); } if (SettingsHolder.Common.FixResolutionAutomatically) { Logging.Debug("Trying to fix resolution just in case…"); 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); } if (SettingsHolder.Drive.RaceEssentialsIntegration && properties.BasicProperties?.CarId != null) { RaceEssentialsHelper.UpdateRaceEssentialsDatabase(properties.BasicProperties.CarId, false); } properties.SetAdditional(new WeatherSpecificVideoSettingsHelper()); properties.SetAdditional(new ModeSpecificPresetsHelper()); properties.SetAdditional(new CarSpecificControlsPresetHelper()); }
private static void PrepareRaceModeRsr(Game.StartProperties properties) { var rsrMode = properties.GetAdditional <RsrMark>() != null; var form = AcSettingsHolder.Forms.Entries.GetByIdOrDefault(RsrMark.FormId); if (form != null) { form.SetVisibility(rsrMode); AcSettingsHolder.Forms.SaveImmediately(); } }
private static void StartAsync_PrepareRace(Game.StartProperties properties) { if (properties.AssistsProperties == null) { properties.AssistsProperties = _defaultAssistsFactory?.Create(); } PrepareRaceModeImmediateStart(properties); PrepareRaceDriverName(properties); Logging.Write("Assists: " + properties.AssistsProperties?.GetDescription()); }
internal ReplayHelper(Game.StartProperties startProperties, Game.Result result) { OriginalFilename = Path.Combine(FileUtils.GetReplaysDirectory(), ReplayObject.PreviousReplayName); RenamedFilename = FileUtils.EnsureUnique(OriginalFilename); Name = GetReplayName(startProperties, result); IsAvailable = File.Exists(OriginalFilename); if (IsAvailable && SettingsHolder.Drive.AutoSaveReplays) { IsRenamed = true; } }
private static Task <Game.Result> StartAsync(Game.StartProperties properties, GameMode mode) { StartAsync_AdjustProperties(properties); StartAsync_Prepare(properties); if (mode == GameMode.Race) { StartAsync_PrepareRace(properties); } return(_uiFactory == null?StartAsync_NoUi(properties, mode) : StartAsync_Ui(properties, mode)); }
private static Task <Game.Result> StartAsync(Game.StartProperties properties, GameMode mode) { StartAsync_Prepare(properties); // properties.SetAdditional(new FocusHelper()); if (mode == GameMode.Race) { StartAsync_PrepareRace(properties); } return(_uiFactory == null?StartAsync_NoUi(properties, mode) : StartAsync_Ui(properties, mode)); }
public void Show(Game.StartProperties properties, GameMode mode) { _properties = properties; _mode = mode; ShowDialogAsync().Forget(); Model.WaitingStatus = AppStrings.Race_Initializing; if (SettingsHolder.Drive.WatchForSharedMemory && (SettingsHolder.Drive.MonitorFramesPerSecond || mode == GameMode.Benchmark || mode == GameMode.Replay && OptionBenchmarkReplays)) { AcSharedMemory.Instance.MonitorFramesPerSecond = true; } }
public GameDiscordPresence(Game.StartProperties properties, GameMode mode) { switch (mode) { case GameMode.Replay: _presence = new DiscordRichPresence(1000, "Preparing to race", "Watching replay"); break; case GameMode.Benchmark: _presence = new DiscordRichPresence(1000, "Preparing to race", "Running benchmark"); break; case GameMode.Race: if (properties.GetAdditional <RsrMark>() != null) { _presence = new DiscordRichPresence(1000, "RSR", "Hotlap"); } else if (properties.GetAdditional <SrsMark>() != null) { _presence = new DiscordRichPresence(1000, "SRS", "In a race"); } else if (properties.GetAdditional <WorldSimSeriesMark>() != null) { _presence = new DiscordRichPresence(1000, "WSS", "In a race"); } else if (properties.ModeProperties is Game.OnlineProperties online) { _presence = new DiscordRichPresence(1000, "Online", "In a race"); WatchForOnlineDetails(online).Ignore(); } else if (properties.GetAdditional <SpecialEventsManager.EventProperties>()?.EventId is string challengeId) { var challenge = SpecialEventsManager.Instance.GetById(challengeId); _presence = new DiscordRichPresence(1000, "Driving Solo", challenge != null ? $"Challenge | {challenge.DisplayName}" : "Challenge"); } else { _presence = new DiscordRichPresence(1000, "Driving Solo", GetSessionName(properties.ModeProperties)); } break; default: throw new ArgumentOutOfRangeException(nameof(mode), mode, null); } _presence.Now() .Car(properties.BasicProperties?.CarId) .Track(properties.BasicProperties?.TrackId, properties.BasicProperties?.TrackConfigurationId); }
private static async Task <Game.Result> StartAsync_NoUi(Game.StartProperties properties, GameMode mode) { using (ReplaysExtensionSetter.OnlyNewIfEnabled()) using (ScreenshotsConverter.OnlyNewIfEnabled()) { if (mode == GameMode.Race) { properties.SetAdditional(new RaceCommandExecutor(properties)); } else if (mode == GameMode.Replay) { properties.SetAdditional(new ReplayCommandExecutor(properties)); } return(await Game.StartAsync(AcsStarterFactory.Create(), properties, null, CancellationToken.None)); } }
private static string GetReplayName([CanBeNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { if (startProperties == null) { return($"_autosave_{DateTime.Now.ToMillisecondsTimestamp()}.acreplay"); } var s = SettingsHolder.Drive.ReplaysNameFormat; if (string.IsNullOrEmpty(s)) { s = SettingsHolder.Drive.DefaultReplaysNameFormat; } return(FileUtils.EnsureFileNameIsValid(VariablesReplacement.Process(s, startProperties, result))); }
public void AddNewResult([NotNull] Game.StartProperties startProperties, [NotNull] Game.Result result) { var directory = SessionsDirectory; FileUtils.EnsureDirectoryExists(directory); var fileName = DateTime.Now.ToString("yyMMdd-HHmmss") + ".json"; var raceOut = AcPaths.GetResultJsonFilename(); JObject data = null; if (File.Exists(raceOut)) { try { // Let’s try to save original data instead in case we missed something during parsing. // But let’s remove formatting just in case. data = JObject.Parse(File.ReadAllText(raceOut)); } catch (Exception e) { Logging.Warning(e); } } if (data == null) { data = JObject.FromObject(result); } // Trying to keep race params as well… // TODO: Do it the other way around, from start params? var raceIni = AcPaths.GetRaceIniFilename(); if (File.Exists(raceIni)) { data[KeyRaceIni] = File.ReadAllText(raceIni); } var quickDrive = startProperties.GetAdditional <QuickDrivePresetProperty>(); if (quickDrive?.SerializedData != null) { data[KeyQuickDrive] = quickDrive.SerializedData; } File.WriteAllText(FileUtils.EnsureUnique(Path.Combine(directory, fileName)), data.ToString(Formatting.None)); }
public static string Process([NotNull] string str, [NotNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { if (startProperties == null) { throw new ArgumentNullException(nameof(startProperties)); } if (str == null) { throw new ArgumentNullException(nameof(str)); } return(ReplayNameRegex.Replace(str, match => { var value = GetValue(startProperties, result, match.Groups[1].Value)?.Trim(); if (string.IsNullOrEmpty(value)) { return "-"; } foreach (var c in match.Groups[2].Success ? match.Groups[2].Value.ToLowerInvariant() : string.Empty) { switch (c) { case 'l': value = value.ToLowerInvariant(); break; case 'u': value = value.ToUpperInvariant(); break; case '0': value = value.Substring(0, 1); break; default: Logging.Warning("Unsupported modifier: " + c); break; } } return value; })); }
async void IGameUi.Show(Game.StartProperties properties) { _resultShown = false; if (Model.Renderer != null) { Model.Renderer.SetCameraHigher = false; } await Task.Delay(1000); ProgressBar.Visibility = Visibility.Visible; LoadingText.Visibility = Visibility.Collapsed; PlayerNamePanel.Visibility = Visibility.Collapsed; GameResultOk.Visibility = Visibility.Hidden; LoadingPanel.SetValue(VisibilityAnimation.VisibleProperty, true); await Task.Delay(2000); DisableRenderer(); }
public static string GetType(Game.StartProperties startProperties, [CanBeNull] Game.Result result) { // TODO: drag mode if (startProperties.ModeProperties is Game.DriftProperties) { return("Drift"); } if (startProperties.ModeProperties is Game.TimeAttackProperties) { return("Time Attack"); } if (startProperties.ModeProperties is Game.HotlapProperties) { return("Hotlap"); } if (startProperties.ModeProperties is Game.OnlineProperties) { return("Online"); } if (startProperties.ModeProperties is Game.PracticeProperties) { return("Practice"); } if (result?.Sessions?.Length == 1) { return("Race"); } if (result?.Sessions?.Length > 1) { return("Weekend"); } return(startProperties.ModeProperties is Game.RaceProperties ? "Race" : "Something Unspeakable"); }
private static string GetValue(Game.StartProperties startProperties, [CanBeNull] Game.Result result, string key) { if (startProperties.BasicProperties == null) { return(null); } switch (key) { case "type": return(GetType(startProperties, result)); case "car": return(CarsManager.Instance.GetById(startProperties.BasicProperties.CarId)?.DisplayName); case "car.id": return(startProperties.BasicProperties.CarId); case "track": var track = TracksManager.Instance.GetById(startProperties.BasicProperties.TrackId); var config = startProperties.BasicProperties.TrackConfigurationId != null ? track?.GetLayoutByLayoutId(startProperties.BasicProperties.TrackConfigurationId) : track; return(config?.Name); case "track.id": return(startProperties.BasicProperties.TrackId); case "date": return(startProperties.StartTime.ToString(CultureInfo.CurrentCulture)); case "date_ac": return(GetAcDate(startProperties.StartTime)); default: return(null); } }
public GameStartedArgs([NotNull] Game.StartProperties startProperties) { StartProperties = startProperties; }
private async Task Join(object o) { var carEntry = CarsView?.CurrentItem as CarEntry; if (carEntry == null) return; var carId = carEntry.CarObject.Id; var correctId = CarIds.FirstOrDefault(x => string.Equals(x, carId, StringComparison.OrdinalIgnoreCase)); if (BookingMode && !ReferenceEquals(o, ActualJoin) && !ReferenceEquals(o, ForceJoin)) { if (_factory == null) { Logging.Error("Booking: UI factory is missing"); return; } PrepareBookingUi(); ProcessBookingResponse(await Task.Run(() => KunosApiProvider.TryToBook(Ip, PortC, Password, correctId, carEntry.AvailableSkin?.Id, DriverName.GetOnline(), ""))); return; } DisposeHelper.Dispose(ref _ui); IsBooked = false; BookingErrorMessage = null; var properties = new Game.StartProperties(new Game.BasicProperties { CarId = carId, CarSkinId = carEntry.AvailableSkin?.Id, TrackId = Track?.Id, TrackConfigurationId = Track?.LayoutId }, null, null, null, new Game.OnlineProperties { RequestedCar = correctId, ServerIp = Ip, ServerName = DisplayName, ServerPort = PortT, ServerHttpPort = PortC, Guid = SteamIdHelper.Instance.Value, Password = Password }); await GameWrapper.StartAsync(properties); var whatsGoingOn = properties.GetAdditional<AcLogHelper.WhatsGoingOn>(); WrongPassword = whatsGoingOn?.Type == AcLogHelper.WhatsGoingOnType.OnlineWrongPassword; if (whatsGoingOn == null) RecentManager.Instance.AddRecentServer(OriginalInformation); }
public static Task <Game.Result> StartAsync(Game.StartProperties properties) { return(StartAsync(properties, GameMode.Race)); }
public static Task StartReplayAsync(Game.StartProperties properties) { return(StartAsync(properties, GameMode.Replay)); }
public static Task StartBenchmarkAsync(Game.StartProperties properties) { return(StartAsync(properties, GameMode.Benchmark)); }
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; } } }
public GameEndedArgs([NotNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { StartProperties = startProperties; Result = result; }
protected GameCommandExecutorBase(Game.StartProperties properties) { _properties = properties; }
private static void StartAsync_Prepare(Game.StartProperties properties) { if (!_nationCodesProviderSet) { _nationCodesProviderSet = true; try { Game.NationCodeProvider = NationCodeProvider.Instance; } catch (Exception e) { Logging.Unexpected(e); } } AcSettingsHolder.Graphics.FixShadowMapBias(); CarCustomDataHelper.Revert(); if (SettingsHolder.Drive.CheckAndFixControlsOrder) { try { AcSettingsHolder.Controls.FixControllersOrder(); } catch (Exception e) { VisualCppTool.OnException(e, null); } } if (SettingsHolder.Common.FixResolutionAutomatically) { Logging.Debug("Trying to fix resolution just in case…"); AcSettingsHolder.Video.EnsureResolutionIsCorrect(); } properties.SetAdditional(new TrackDetails()); properties.SetAdditional( new WeatherProceduralHelper(properties.ConditionProperties != null && properties.ConditionProperties.RoadTemperature == null)); properties.SetAdditional(new WeatherSpecificLightingHelper()); if (SettingsHolder.Drive.WeatherSpecificClouds) { properties.SetAdditional(new WeatherSpecificCloudsHelper()); } if (SettingsHolder.Drive.WeatherSpecificTyreSmoke) { properties.SetAdditional(new WeatherSpecificTyreSmokeHelper()); } if (File.Exists(properties.GetAdditional <CustomTrackState>()?.Filename)) { properties.SetAdditional(new CustomTrackPropertiesHelper(properties.GetAdditional <CustomTrackState>()?.Filename ?? string.Empty)); } if (SettingsHolder.Live.RsrEnabled && SettingsHolder.Live.RsrDisableAppAutomatically) { PrepareRaceModeRsr(properties); } var carId = properties.BasicProperties?.CarId; if (carId != null) { if (SettingsHolder.Drive.CamberExtravaganzaIntegration) { CamberExtravaganzaHelper.UpdateDatabase(carId); } if (SettingsHolder.Drive.SidekickIntegration) { SidekickHelper.UpdateSidekickDatabase(carId); } if (SettingsHolder.Drive.SidekickOdometerExportValues) { SidekickHelper.OdometerExport(carId); } if (SettingsHolder.Drive.RaceEssentialsIntegration) { RaceEssentialsHelper.UpdateRaceEssentialsDatabase(carId, false); } if (SettingsHolder.Drive.StereoOdometerExportValues) { StereoOdometerHelper.Export(carId); } if (PatchHelper.IsFeatureSupported(PatchHelper.FeatureNeedsOdometerValue)) { var car = CarsManager.Instance.GetById(carId); if (car != null) { properties.SetAdditional(new DrivenDistance(car.TotalDrivenDistance)); } } } properties.SetAdditional(new ModeSpecificPresetsHelper()); properties.SetAdditional(new WeatherSpecificVideoSettingsHelper()); properties.SetAdditional(new CarSpecificControlsPresetHelper()); properties.SetAdditional(new CarRaceTextures()); if (PatchHelper.GetInstalledVersion() != null) { properties.SetAdditional(new AcPatchTrackOutline()); } properties.SetAdditional(new ExtraHotkeysRaceHelper()); if (SettingsHolder.Drive.CopyFilterToSystemForOculus && (AcSettingsHolder.Video.CameraMode.Id == "OCULUS" || AcSettingsHolder.Video.CameraMode.Id == "OPENVR")) { properties.SetAdditional(new CopyFilterToSystemForOculusHelper()); } }
public GameFinishedArgs([NotNull] Game.StartProperties startProperties, Game.Result result) { StartProperties = startProperties; Result = result; }
public ReplayCommandExecutor(Game.StartProperties properties) : base(properties) { }
private async Task Join(object o) { var carEntry = SelectedCarEntry; if (carEntry == null || Cars == null) { return; } var correctId = GetCorrectId(carEntry.Id); if (correctId == null) { Logging.Error("Can’t find correct ID"); return; } if (!IsBookedForPlayer && BookingMode && !ReferenceEquals(o, ActualJoin) && !ReferenceEquals(o, ForceJoin)) { if (_factory == null) { Logging.Error("Booking: UI factory is missing"); return; } PrepareBookingUi(); ProcessBookingResponse(await Task.Run(() => KunosApiProvider.TryToBook(Ip, PortHttp, Password, correctId, carEntry.AvailableSkin?.Id, DriverName.GetOnline(), ""))); return; } DisposeHelper.Dispose(ref _ui); IsBooked = false; BookingErrorMessage = null; var properties = new Game.StartProperties(new Game.BasicProperties { CarId = carEntry.Id, CarSkinId = carEntry.AvailableSkin?.Id, TrackId = Track?.Id, TrackConfigurationId = Track?.LayoutId }, null, null, null, new Game.OnlineProperties { RequestedCar = correctId, ServerIp = Ip, ServerName = DisplayName, ServerPort = PortRace, ServerHttpPort = PortHttp, Guid = SteamIdHelper.Instance.Value, Password = Password }); var now = DateTime.Now; await GameWrapper.StartAsync(properties); var whatsGoingOn = properties.GetAdditional <WhatsGoingOn>(); WrongPassword = whatsGoingOn?.Type == WhatsGoingOnType.OnlineWrongPassword; if (whatsGoingOn == null) { LastConnected = now; FileBasedOnlineSources.AddRecent(this).Forget(); UpdateStats(); } }
private static BaseFinishedData GetFinishedData(Game.StartProperties properties, Game.Result result) { var conditions = properties?.GetAdditional <PlaceConditions>(); var takenPlace = conditions?.GetTakenPlace(result) ?? PlaceConditions.UnremarkablePlace; Logging.Debug($"Place conditions: {conditions?.GetDescription()}, result: {result.GetDescription()}"); if (result.GetExtraByType <Game.ResultExtraDrift>(out var drift)) { return(new DriftFinishedData { Points = drift.Points, MaxCombo = drift.MaxCombo, MaxLevel = drift.MaxLevel, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraTimeAttack>(out var timeAttack)) { var bestLapTime = result.Sessions?.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); return(new TimeAttackFinishedData { Points = timeAttack.Points, Laps = result.Sessions?.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0) ?? 0, BestLapTime = bestLapTime == TimeSpan.Zero ? null : bestLapTime, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraBestLap>(out var bestLap) && bestLap.IsNotCancelled && result.Sessions?.Length == 1 && result.Players?.Length == 1) { var bestLapTime = result.Sessions.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); var sectorsPerSections = result.Sessions.SelectMany(x => from lap in x.Laps where lap.CarNumber == 0 select lap.SectorsTime).ToList(); var theoreticallLapTime = sectorsPerSections.FirstOrDefault()?.Select((x, i) => sectorsPerSections.Select(y => y[i]).Min()).Sum(); return(result.Sessions[0].Name == AppStrings.Rsr_SessionName ? new RsrFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace } : new HotlapFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace }); } var isOnline = properties?.ModeProperties is Game.OnlineProperties; var playerName = isOnline && SettingsHolder.Drive.DifferentPlayerNameOnline ? SettingsHolder.Drive.PlayerNameOnline : SettingsHolder.Drive.PlayerName; if (result.Sessions?.Length == 1 && result.Sessions[0].Name == Game.TrackDaySessionName && result.Players?.Length > 1) { var session = result.Sessions[0]; var playerLaps = session.LapsTotalPerCar?[0] ?? 1; session.LapsTotalPerCar = session.LapsTotalPerCar?.Select(x => Math.Min(x, playerLaps)).ToArray(); session.Laps = session.Laps?.Where(x => x.LapId < playerLaps).ToArray(); session.BestLaps = session.BestLaps?.Select(x => { if (x.LapId < playerLaps) { return(x); } var best = session.Laps?.Where(y => y.CarNumber == x.CarNumber).MinEntryOrDefault(y => y.Time); if (best == null) { return(null); } return(new Game.ResultBestLap { Time = best.Time, LapId = best.LapId, CarNumber = x.CarNumber }); }).NonNull().ToArray(); } var dragExtra = result.GetExtraByType <Game.ResultExtraDrag>(); var sessionsData = result.Sessions?.Select(session => { int[] takenPlaces; SessionFinishedData data; if (dragExtra != null) { data = new DragFinishedData { BestReactionTime = dragExtra.ReactionTime, Total = dragExtra.Total, Wins = dragExtra.Wins, Runs = dragExtra.Runs, }; var delta = dragExtra.Wins * 2 - dragExtra.Runs; takenPlaces = new[] { delta >= 0 ? 0 : 1, delta <= 0 ? 0 : 1 }; } else { data = new SessionFinishedData(session.Name?.ApartFromLast(@" Session")); takenPlaces = session.GetTakenPlacesPerCar(); } var sessionBestLap = session.BestLaps?.MinEntryOrDefault(x => x.Time); var sessionBest = sessionBestLap?.Time; data.PlayerEntries = ( from player in result.Players let car = CarsManager.Instance.GetById(player.CarId ?? "") let carSkin = car?.GetSkinById(player.CarSkinId ?? "") select new { Player = player, Car = car, CarSkin = carSkin } ).Select((entry, i) => { var bestLapTime = session.BestLaps?.Where(x => x.CarNumber == i).MinEntryOrDefault(x => x.Time)?.Time; var laps = session.Laps?.Where(x => x.CarNumber == i).Select(x => new SessionFinishedData.PlayerLapEntry { LapNumber = x.LapId + 1, Sectors = x.SectorsTime, Cuts = x.Cuts, TyresShortName = x.TyresShortName, Total = x.Time, DeltaToBest = bestLapTime.HasValue ? x.Time - bestLapTime.Value : (TimeSpan?)null, DeltaToSessionBest = sessionBest.HasValue ? x.Time - sessionBest.Value : (TimeSpan?)null, }).ToArray(); var lapTimes = laps?.Skip(1).Select(x => x.Total.TotalSeconds).Where(x => x > 10d).ToList(); double?progress, spread; if (lapTimes == null || lapTimes.Count < 2) { progress = null; spread = null; } else { var firstHalf = lapTimes.Count / 2; var firstMedian = lapTimes.Take(firstHalf).Median(); var secondMedian = lapTimes.Skip(firstHalf).Median(); progress = 1d - secondMedian / firstMedian; spread = (lapTimes.Max() - lapTimes.Min()) / bestLapTime?.TotalSeconds; } return(new SessionFinishedData.PlayerEntry { Name = i == 0 ? playerName : entry.Player.Name, IsPlayer = i == 0, Index = i, Car = entry.Car, CarSkin = entry.CarSkin, TakenPlace = i < takenPlaces?.Length ? takenPlaces[i] + 1 : DefinitelyNonPrizePlace, PrizePlace = takenPlaces?.Length > 1, LapsCount = session.LapsTotalPerCar?.ArrayElementAtOrDefault(i) ?? 0, BestLapTime = bestLapTime, DeltaToSessionBest = sessionBestLap?.CarNumber == i ? null : bestLapTime - sessionBest, TotalTime = session.Laps?.Where(x => x.CarNumber == i).Select(x => x.SectorsTime.Sum()).Sum(), Laps = laps, LapTimeProgress = progress, LapTimeSpread = spread }); }).OrderBy(x => x.TakenPlace).ToList(); if (data.PlayerEntries.Count > 0) { var maxLaps = data.PlayerEntries.Select(x => x.Laps.Length).Max(); var bestTotalTime = data.PlayerEntries.Where(x => x.Laps.Length == maxLaps).MinEntryOrDefault(x => x.TotalTime ?? TimeSpan.MaxValue); foreach (var entry in data.PlayerEntries) { var lapsDelta = maxLaps - entry.Laps.Length; if (bestTotalTime == entry) { entry.TotalTimeDelta = "-"; } else if (lapsDelta > 0) { entry.TotalTimeDelta = $"+{lapsDelta} {PluralizingConverter.Pluralize(lapsDelta, "lap")}"; } else { var t = entry.TotalTime - bestTotalTime?.TotalTime; var v = t?.ToMillisecondsString(); entry.TotalTimeDelta = t == TimeSpan.Zero ? "" : v != null ? $"+{v}" : null; } } } var bestProgress = (from player in data.PlayerEntries where player.LapTimeProgress > 0.03 orderby player.LapTimeProgress descending select player).FirstOrDefault(); var bestConsistent = (from player in data.PlayerEntries where player.LapTimeSpread < 0.02 orderby player.LapTimeSpread descending select player).FirstOrDefault(); data.RemarkableNotes = new[] { sessionBestLap == null ? null : new SessionFinishedData.RemarkableNote("[b]Best lap[/b] made by ", data.PlayerEntries.GetByIdOrDefault(sessionBestLap.CarNumber), null), new SessionFinishedData.RemarkableNote("[b]The Best Off-roader Award[/b] goes to ", (from player in data.PlayerEntries let cuts = (double)player.Laps.Sum(x => x.Cuts) / player.Laps.Length where cuts > 1.5 orderby cuts descending select player).FirstOrDefault(), null), new SessionFinishedData.RemarkableNote("[b]Remarkable progress[/b] shown by ", bestProgress, null), new SessionFinishedData.RemarkableNote("[b]The most consistent[/b] is ", bestConsistent, null), }.Where(x => x?.Player != null).ToList(); return(data); }).ToList(); return(sessionsData?.Count == 1 ? (BaseFinishedData)sessionsData.First() : sessionsData?.Any() == true ? new SessionsFinishedData(sessionsData) : null); }
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; } } }