public async Task <string> InstallCustom(string id, IProgress <double?> progress = null, CancellationToken cancellation = default(CancellationToken)) { var destination = FilesStorage.Instance.GetDirectory("Locales", id); var data = await CmApiProvider.GetDataAsync(@"locales/get/base", progress, cancellation); if (cancellation.IsCancellationRequested || data == null) { return(null); } progress?.Report(null); using (var memory = new MemoryStream(data)) using (var updateZip = new ZipArchive(memory)) { foreach (var entry in updateZip.Entries) { using (var stream = entry.Open()) { var filename = Path.Combine(destination, entry.Name); if (File.Exists(filename)) { continue; } await FileUtils.WriteAllBytesAsync(filename, stream, cancellation); if (cancellation.IsCancellationRequested) { return(null); } } } } return(destination); }
public static async Task FixMissingDefaultPpFilter(CancellationToken cancellation) { var original = await CmApiProvider.GetStaticDataBytesAsync("pp_default", TimeSpan.FromDays(3), cancellation : cancellation); if (cancellation.IsCancellationRequested) { return; } await Task.Run(() => { cancellation.ThrowIfCancellationRequested(); if (original == null) { throw new InformativeException("Can’t load original filter"); } using (var stream = new MemoryStream(original)) using (var zip = ZipArchive.Open(stream)) { var entry = zip.Entries.FirstOrDefault(x => x.Key == @"default.ini"); if (entry == null) { throw new Exception("Invalid data"); } File.WriteAllBytes(PpFiltersManager.Instance.DefaultFilename, entry.OpenEntryStream().ReadAsBytesAndDispose()); } }, cancellation); }
private async Task <string> GetLatestVersion() { if (IsGetting) { return(null); } IsGetting = true; try { var data = await CmApiProvider.GetStringAsync("data/manifest"); if (data == null) { LatestError = ToolsStrings.BaseUpdater_CannotDownloadInformation; return(null); } return(VersionFromData(data)); } catch (Exception e) { LatestError = ToolsStrings.BaseUpdater_CannotDownloadInformation; Logging.Warning("Cannot get data/manifest.json: " + e); return(null); } finally { IsGetting = false; } }
public static async Task Play(BeepingNoiseType type) { switch (type) { case BeepingNoiseType.Disabled: break; case BeepingNoiseType.System: SystemSounds.Exclamation.Play(); break; case BeepingNoiseType.Custom: try { var data = await CmApiProvider.GetStaticDataBytesAsync("audio_error", TimeSpan.FromDays(3)); if (data != null) { using (var stream = new MemoryStream(data)) using (var zip = ZipArchive.Open(stream)) { var entry = zip.Entries.FirstOrDefault(x => x.Key == @"error.wav"); if (entry == null) { throw new Exception("Invalid data"); } using (var s = entry.OpenEntryStream()) { new SoundPlayer(s).Play(); } } } } catch (Exception e) { Logging.Warning(e); } break; } }
private async Task <string> LoadWinWrapper(CancellationToken cancellation) { var wrapperFilename = FilesStorage.Instance.GetFilename("Server Wrapper", "AcServerWrapper.exe"); var data = await CmApiProvider.GetStaticDataAsync("ac_server_wrapper"); if (cancellation.IsCancellationRequested || data == null) { return(null); } if (data.Item2) { // Freshly loaded var wrapperBytes = await FileUtils.ReadAllBytesAsync(data.Item1); if (cancellation.IsCancellationRequested) { return(null); } await Task.Run(() => { using (var stream = new MemoryStream(wrapperBytes, false)) using (var archive = new ZipArchive(stream)){ try { File.WriteAllBytes(wrapperFilename, archive.GetEntry("acServerWrapper.exe").Open().ReadAsBytesAndDispose()); } catch (Exception e) { Logging.Warning(e); } } }); } return(File.Exists(wrapperFilename) ? wrapperFilename : null); }
public static async Task DownloadCarAsync([NotNull] string id, string version = null) { try { var entry = await CmApiProvider.GetContentAsync <AcContentEntry>($"car/{id}"); if (entry != null) { if (version != null && entry.UiVersion != version && entry.OriginVersion != version) { throw new InformativeException($"Can’t download car “{id}”", $"Not the required version: indexed is {entry.UiVersion ?? entry.OriginVersion}, while required is {version}."); } if (!entry.ImmediateDownload && entry.OriginUrl != null && (Keyboard.Modifiers & ModifierKeys.Control) == 0) { WindowsHelper.ViewInBrowser(entry.OriginUrl); } else { await ContentInstallationManager.Instance.InstallAsync(entry.DownloadUrl, new ContentInstallationParams(false) { DisplayName = entry.UiName, Version = entry.UiVersion, InformationUrl = entry.OriginUrl }); } } else { throw new InformativeException($"Can’t download car “{id}”", "Attempt to find a description failed."); } } catch (Exception e) { NonfatalError.Notify($"Can’t download car “{id}”", e); } }
public async Task <byte[]> GetModel(string key) { if (key != ExtraModels.KeyCrewExtra) { return(null); } using (var dialog = new WaitingDialog()) { dialog.Report(ControlsStrings.Common_Downloading); var data = await CmApiProvider.GetStaticDataBytesAsync("cs_crew", TimeSpan.FromDays(3), dialog, dialog.CancellationToken); if (data == null) { return(null); } return(await Task.Run(() => { using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { return archive.GetEntry("Crew.kn5")?.Open().ReadAsBytesAndDispose(); } })); } }
public async Task <byte[]> GetModel(string key) { if (key != ExtraModels.KeyCrewExtra) { return(null); } var temporary = FilesStorage.Instance.GetTemporaryFilename("Crew.kn5"); if (!File.Exists(temporary)) { using (var dialog = new WaitingDialog()) { dialog.Report(ControlsStrings.Common_Downloading); var data = await CmApiProvider.GetDataAsync("static/get/cs_crew", dialog, dialog.CancellationToken); if (data == null) { return(null); } await Task.Run(() => { using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { archive.GetEntry("Crew.kn5").ExtractToFile(temporary); } }); } } return(await FileUtils.ReadAllBytesAsync(temporary).ConfigureAwait(false)); }
private async Task <bool> LoadAndPrepare() { #if !FORCE_UPDATE || !DEBUG if (!MainExecutingFile.IsPacked) { NonfatalError.Notify(ToolsStrings.AppUpdater_CannotUpdateApp, ToolsStrings.AppUpdater_UnpackedVersionMessage); LatestError = ToolsStrings.AppUpdater_UnpackedVersionMessage; return(false); } #endif if (_isPreparing) { return(false); } _isPreparing = true; UpdateIsReady = null; try { var data = await CmApiProvider.GetDataAsync($"app/get/{Branch}"); if (data == null) { throw new InformativeException(ToolsStrings.AppUpdater_CannotLoad, ToolsStrings.Common_MakeSureInternetWorks); } string preparedVersion = null; await Task.Run(() => { if (File.Exists(UpdateLocation)) { File.Delete(UpdateLocation); } using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { preparedVersion = VersionFromData(archive.GetEntry(@"Manifest.json").Open().ReadAsStringAndDispose()); archive.GetEntry(@"Content Manager.exe").ExtractToFile(UpdateLocation); Logging.Write($"New version {preparedVersion} was extracted to “{UpdateLocation}”"); } }); UpdateIsReady = preparedVersion; return(true); } catch (UnauthorizedAccessException) { NonfatalError.Notify(ToolsStrings.AppUpdater_AccessIsDenied, ToolsStrings.AppUpdater_AccessIsDenied_Commentary); LatestError = ToolsStrings.AppUpdater_AccessIsDenied_Short; } catch (Exception e) { NonfatalError.Notify(ToolsStrings.AppUpdater_CannotLoad, ToolsStrings.AppUpdater_CannotLoad_Commentary, e); LatestError = ToolsStrings.AppUpdater_CannotLoadShort; } finally { _isPreparing = false; } return(false); }
public async Task <IEnumerable <PluginEntry> > DownloadAndParseList() { try { var loaded = await CmApiProvider.GetStringAsync("plugins/list"); return(loaded == null ? null : JsonConvert.DeserializeObject <PluginEntry[]>(loaded).Where(x => x.IsAllRight)); } catch (Exception e) { NonfatalError.NotifyBackground("Can’t download plugins list", e); return(null); } }
public async Task <IEnumerable <PluginEntry> > DownloadAndParseList() { try { var loaded = await CmApiProvider.GetStringAsync("plugins/list"); return(loaded == null ? null : JsonConvert.DeserializeObject <PluginEntry[]>(loaded).Where(x => x.IsAllRight)); } catch (Exception e) { Logging.Warning("Cannot download plugins list: " + e); return(null); } }
private async Task LoadBackgroundAsync() { var data = await CmApiProvider.GetStaticDataBytesAsync("damagedisplayer_bg", TimeSpan.MaxValue); if (data != null) { using (var stream = new MemoryStream(data)) using (var zip = new ZipArchive(stream, ZipArchiveMode.Read)) { BackgroundImageProgress.IsActive = false; BackgroundImage.Source = zip.GetEntry(@"image.jpg")?.Open().ReadAsBytesAndDispose(); } } }
public async Task InstallPlugin(PluginEntry plugin, IProgress <AsyncProgressEntry> progress = null, CancellationToken cancellation = default(CancellationToken)) { var destination = GetPluginDirectory(plugin.Id); try { plugin.IsInstalling = true; var data = await CmApiProvider.GetDataAsync($"plugins/get/{plugin.Id}", progress, cancellation); if (data == null || cancellation.IsCancellationRequested) { return; } await Task.Run(() => { if (Directory.Exists(destination)) { FileUtils.Recycle(destination); } using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { archive.ExtractToDirectory(destination); } }, cancellation); if (cancellation.IsCancellationRequested) { return; } plugin.InstalledVersion = plugin.Version; File.WriteAllText(Path.Combine(destination, ManifestFileName), JsonConvert.SerializeObject(plugin)); if (plugin.IsEnabled) { PluginEnabled?.Invoke(this, new PluginEventArgs { PluginId = plugin.Id }); } } catch (Exception e) when(e.IsCancelled()) { } catch (Exception e) { NonfatalError.Notify(ToolsStrings.Plugins_CannotInstall, e); } finally { plugin.IsInstalling = false; } }
private async Task LoadBackgroundAsync() { var data = await CmApiProvider.GetStaticDataBytesAsync("patch_img_about", TimeSpan.MaxValue); if (data != null) { using (var stream = new MemoryStream(data)) using (var zip = new ZipArchive(stream, ZipArchiveMode.Read)) { _imageData = zip.GetEntry(@"image.jpg")?.Open().ReadAsBytesAndDispose(); _imageMessage = zip.GetEntry(@"about.txt")?.Open().ReadAsBytesAndDispose().ToUtf8String(); BackgroundImageProgress.IsActive = false; BackgroundImage.Source = _imageData; } } }
private static async Task EnsureStylesUpdated() { try { var data = await CmApiProvider.GetStaticDataBytesIfUpdatedAsync(DataId, TimeSpan.FromDays(30)); if (data != null) { using (var stream = new MemoryStream(data, false)) { SetStylesFromArchive(stream); } } } catch (Exception e) { Logging.Warning(e.Message); } }
private static async Task <byte[]> GetFlamesTexturesAsync(IProgress <AsyncProgressEntry> progress = null, CancellationToken cancellation = default(CancellationToken)) { if (_flamesTextures == null) { progress?.Report(AsyncProgressEntry.FromStringIndetermitate("Loading flames textures…")); _flamesTextures = await CmApiProvider.GetStaticDataBytesAsync("flames", TimeSpan.FromDays(3), cancellation : cancellation); if (cancellation.IsCancellationRequested) { return(null); } } return(_flamesTextures); }
protected override async Task <bool> CheckAndUpdateIfNeededInner() { if (InstalledVersion == null) { return(false); } var installedVersion = File.Exists(GetPackageFilename(SettingsHolder.Locale.LocaleName)) ? InstalledVersion : @"0"; var data = await CmApiProvider.GetDataAsync($"locales/update/{SettingsHolder.Locale.LocaleName}/{installedVersion}"); if (data == null) { LatestError = ToolsStrings.BaseUpdater_CannotDownloadInformation; Logging.Warning("Cannot get locales/update"); return(false); } if (data.Length == 0) { return(false); } try { LocalePackageManifest manifest; using (var memory = new MemoryStream(data)) using (var updateZip = new ZipArchive(memory)) { manifest = LocalePackageManifest.FromArchive(updateZip); if (manifest == null) { throw new Exception("Manifest is missing"); } } var package = GetPackageFilename(manifest.Id); await FileUtils.WriteAllBytesAsync(package, data); Logging.Write("Locale updated"); InstalledVersion = manifest.Version; return(true); } catch (Exception e) { Logging.Warning("Cannot update locale: " + e); return(false); } }
private static async Task <byte[]> LoadPackageTimeout(string langId, string version = "0") { if (!SettingsHolder.Locale.UpdateOnStart) { return(null); } using (var cancellation = new CancellationTokenSource()) { cancellation.CancelAfter(500); var data = await CmApiProvider.GetDataAsync($"locales/update/{langId}/{version}", cancellation : cancellation.Token); if (cancellation.IsCancellationRequested) { Logging.Write("Timeout exceeded"); } return(data == null || data.Length == 0 ? null : data); } }
private static async Task InstallShowroom(string showroomName, string showroomId, CarUpdatePreviewsDialog instance = null) { if (instance != null) { instance._mode = UpdatePreviewMode.Options; await Task.Delay(100); } using (var dialog = new WaitingDialog(showroomName)) { dialog.Report(ControlsStrings.Common_Downloading); var destination = FileUtils.GetShowroomsDirectory(AcRootDirectory.Instance.Value); var data = await CmApiProvider.GetDataAsync($"static/get/{showroomId}", dialog, dialog.CancellationToken); if (data == null) { dialog.Close(); NonfatalError.Notify(string.Format(AppStrings.CarPreviews_CannotDownloadShowroom, showroomName), ToolsStrings.Common_CannotDownloadFile_Commentary); return; } dialog.Content = ControlsStrings.Common_Installing; try { await Task.Run(() => { using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { archive.ExtractToDirectory(destination); } }); } catch (Exception e) { dialog.Close(); NonfatalError.Notify(string.Format(AppStrings.CarPreviews_CannotInstallShowroom, showroomName), e); return; } await Task.Delay(1000); if (instance != null) { instance.SelectedShowroom = ShowroomsManager.Instance.GetById(showroomId) ?? instance.SelectedShowroom; } } }
private async Task LoadStatsAsync() { try { var data = _achievements ?? (_achievements = await CmApiProvider.GetAsync <Dictionary <string, double> >("achievements/get")); if (data == null) { throw new Exception("Failed to load data"); } await SpecialEventsManager.Instance.EnsureLoadedAsync(); foreach (var eventObject in SpecialEventsManager.Instance.Loaded) { eventObject.PlaceStats = data.Where(x => x.Key.StartsWith(eventObject.Id + "_")).OrderBy(x => x.Key) .Select(x => x.Value).ToArray(); } } catch (Exception e) { Logging.Warning(e); } }
private static async Task DownloadAndInstall(CancellationToken token) { var directory = _directory ?? MainExecutingFile.Directory; try { var data = await CmApiProvider.GetStaticDataAsync("visual_cpp", TimeSpan.FromDays(1), cancellation : token); if (data == null) { ManualInstallation(null, directory); } else { await Task.Run(() => { using (var archive = ZipFile.OpenRead(data.Item1)) { foreach (var file in archive.Entries) { var completeFileName = Path.Combine(directory, file.FullName); if (file.Name == "" || File.Exists(completeFileName)) { continue; } FileUtils.EnsureFileDirectoryExists(completeFileName); file.ExtractToFile(completeFileName, true); } } }); FileUtils.TryToDelete(data.Item1); if (ModernDialog.ShowMessage("The package is installed. Now, app needs to be restarted. Restart it now?", "The package is installed", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { WindowsHelper.RestartCurrentApplication(); } } } catch (Exception e) when(e.IsCancelled()) { } catch (Exception e) { ManualInstallation(e, directory); } }
private static async Task LoadAvailableIdsAsyncInner() { try { var ids = await CmApiProvider.GetContentAsync <Dictionary <string, string[]> >(); if (ids == null) { Logging.Warning("Can’t load lists of available-to-download IDs"); return; } AvailableCarIds = ids.GetValueOrDefault("cars"); AvailableTrackIds = ids.GetValueOrDefault("tracks"); AvailableIdsLoaded?.Invoke(null, EventArgs.Empty); } catch (Exception e) { Logging.Warning(e); } finally { _availableLoadingTask = null; _availableIdsLoaded = true; } }
private async void LoadOtherLocales() { _online = _online ?? await CmApiProvider.GetAsync <LocalePackageManifest[]>("locales/list"); if (_online == null) { return; } foreach (var entry in _online) { if (Locales.Any(x => string.Equals(x.Id, entry.Id, StringComparison.OrdinalIgnoreCase))) { continue; } // TODO: check if there is an update Locales.Insert(Locales.Count - 1, new LocaleEntry(entry.Id, entry.Version, entry.Coverity, entry.Size)); } LoadCurrentLocale(); }
private async Task <bool> LoadAndInstall() { if (_isInstalling) { return(false); } _isInstalling = true; try { var data = await CmApiProvider.GetDataAsync("data/latest"); if (data == null) { throw new InformativeException(ToolsStrings.AppUpdater_CannotLoad, ToolsStrings.Common_MakeSureInternetWorks); } string installedVersion = null; await Task.Run(() => { var location = FilesStorage.Instance.Combine(FilesStorage.DataDirName); Directory.Delete(location, true); using (var stream = new MemoryStream(data, false)) using (var archive = new ZipArchive(stream)) { installedVersion = VersionFromData(archive.GetEntry(@"Manifest.json").Open().ReadAsStringAndDispose()); archive.ExtractToDirectory(location); } }); InstalledVersion = installedVersion; Logging.Write("Data loaded: " + InstalledVersion); return(true); } catch (Exception e) { NonfatalError.Notify(ToolsStrings.ContentSyncronizer_CannotLoadContent, ToolsStrings.ContentSyncronizer_CannotLoadContent_Commentary, e); } finally { _isInstalling = false; } return(false); }
private async Task <string> LoadLinux64Wrapper(CancellationToken cancellation) { return((await CmApiProvider.GetStaticDataAsync("ac_server_wrapper-linux-x64"))?.Item1); }
public async Task Update(UpdateMode mode, bool background = false, bool fast = false) { if (_updating) { return; } _updating = true; _pingId++; var driversCount = -1; var resultStatus = ServerStatus.Ready; try { // If it’s a background update, don’t change anything in UI to avoid flashing if (!background) { CurrentDrivers = null; Status = ServerStatus.Loading; IsAvailable = false; } // Reset some update-state values PrepareErrorsList(); // Nothing loaded at all! var informationUpdated = false; if (!IsFullyLoaded) { UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingActualInformation, 0.1); ServerInformationComplete loaded; try { loaded = await GetInformationDirectly(); } catch (HttpRequestException e) { if (e.InnerException is WebException webException) { _updateWebException = webException; } else { _updateException = e; } resultStatus = ServerStatus.Error; return; } catch (WebException e) { _updateWebException = e; resultStatus = ServerStatus.Error; return; } var update = UpdateValues(loaded, false, true); if (update != null) { resultStatus = update.Value; if (update != ServerStatus.MissingContent) { // Loaded data isn’t for this server (port by which it was loaded differs). // Won’t even set drivers count in this case, whole data is obviously wrong. return; } } driversCount = loaded.Clients; // Set this flag to True so we won’t use GetInformationDirectly() again later informationUpdated = true; } // Extended mode for server wrapping thing var informationLoadedExtended = false; ServerCarsInformation carsInformation = null; if (DetailsPort != null) { try { var extended = await GetExtendedInformationDirectly(); var update = UpdateValues(extended, false, true); if (update != null) { resultStatus = update.Value; if (update != ServerStatus.MissingContent) { UpdateValuesExtended(null); return; } } UpdateValuesExtended(extended); driversCount = extended.Clients; carsInformation = extended.Players; informationLoadedExtended = true; } catch (Exception e) { Logging.Warning(e); DetailsPort = null; UpdateValuesExtended(null); return; } } else if (DetailsId != null) { try { var extended = await CmApiProvider.GetOnlineDataAsync(DetailsId); if (extended != null) { Country = extended.Country?.FirstOrDefault() ?? Country; CountryId = extended.Country?.ArrayElementAtOrDefault(1) ?? CountryId; Sessions?.ForEach((x, i) => x.Duration = extended.Durations?.ElementAtOrDefault(i) ?? x.Duration); } UpdateValuesExtended(extended); } catch (Exception e) { Logging.Warning(e); UpdateValuesExtended(null); return; } } else { UpdateValuesExtended(null); } // Update information if (!informationLoadedExtended && (mode != UpdateMode.Lite || !(Sessions?.Count > 0) // if there are no sessions (!), maybe information is damaged, let’s re-download )) { UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingActualInformation, 0.2); ServerInformationComplete loaded; try { // If informationUpdated is True and settings set to update-information-directly mode, this method // will return 0. loaded = await GetInformation(informationUpdated); } catch (WebException e) { _updateWebException = e; resultStatus = ServerStatus.Error; return; } if (loaded != null) { if (loaded.Ip == Ip && loaded.PortHttp == PortHttp || informationUpdated || loaded.LoadedDirectly) { // If loaded information is compatible with existing, use it immediately. Otherwise — apparently, // server changed — we’ll try to load an actual data directly from it later, but only if it wasn’t // loaded just before that and loaded information wasn’t loaded from it. var update = UpdateValues(loaded, false, true); if (update != null) { resultStatus = update.Value; if (update != ServerStatus.MissingContent) { return; } } driversCount = loaded.Clients; } else { ServerInformation directlyLoaded; try { directlyLoaded = await GetInformationDirectly(); } catch (WebException e) { _updateWebException = e; resultStatus = ServerStatus.Error; return; } var update = UpdateValues(directlyLoaded, false, true); if (update != null) { resultStatus = update.Value; if (update != ServerStatus.MissingContent) { return; } } driversCount = loaded.Clients; } } } // Load players list if (carsInformation == null) { UpdateProgress = new AsyncProgressEntry(ToolsStrings.Online_LoadingPlayersList, 0.4); try { carsInformation = await KunosApiProvider.GetCarsInformationAsync(Ip, PortHttp); } catch (WebException e) { _updateWebException = e; resultStatus = ServerStatus.Error; return; } } if (!BookingMode) { CurrentDriversCount = carsInformation.Cars.Count(x => x.IsConnected); driversCount = -1; } var currentDrivers = (BookingMode ? carsInformation.Cars : carsInformation.Cars.Where(x => x.IsConnected)) .Select(x => { var driver = CurrentDrivers?.FirstOrDefault(y => y.SameAs(x)) ?? new CurrentDriver(x, RequiredCspVersion != 0); return(driver); }) .ToList(); if (CurrentDrivers == null || !CurrentDrivers.SequenceEqual(currentDrivers)) { CurrentDrivers = currentDrivers; var count = 0; var booked = false; foreach (var x in currentDrivers) { if (x.IsConnected) { count++; } if (x.IsBookedForPlayer) { booked = true; SetSelectedCarEntry(Cars?.GetByIdOrDefault(x.CarId, StringComparison.OrdinalIgnoreCase)); } } ConnectedDrivers = count; IsBookedForPlayer = booked; } if (Cars == null) { Logging.Unexpected(); _updateDriversMissing = true; resultStatus = ServerStatus.Error; return; } for (int i = 0, c = Cars.Count; i < c; i++) { var entry = Cars[i]; var wrapper = entry.CarWrapper; CarObject car; // Load car if not loaded if (wrapper != null) { if (wrapper.IsLoaded) { car = (CarObject)wrapper.Value; } else { UpdateProgress = new AsyncProgressEntry(string.Format(ToolsStrings.Online_LoadingCars, wrapper.Id), 0.5 + 0.4 * i / c); await Task.Delay(fast? 10 : 50); car = (CarObject)await wrapper.LoadedAsync(); } car.SubscribeWeak(OnContentNameChanged); } else { car = null; } // Load skin if (car?.SkinsManager.IsLoaded == false) { UpdateProgress = new AsyncProgressEntry(string.Format(ToolsStrings.Online_LoadingSkins, car.DisplayName), 0.5 + 0.4 * (0.5 + i) / c); await Task.Delay(fast? 10 : 50); await car.SkinsManager.EnsureLoadedAsync(); } // Set next available skin if (CurrentSessionType == Game.SessionType.Booking) { entry.SetAvailableSkinId(car?.SelectedSkin?.Id, null); entry.Total = 0; entry.Available = 0; entry.IsAvailable = true; } else { var cars = carsInformation.Cars.Where(x => x.IsEntryList && string.Equals(x.CarId, entry.Id, StringComparison.OrdinalIgnoreCase)).ToList(); ServerActualCarInformation availableSkin; if (BookingMode) { availableSkin = cars.FirstOrDefault(x => x.IsRequestedGuid); entry.Total = 0; entry.Available = 0; entry.IsAvailable = true; } else { availableSkin = cars.FirstOrDefault(y => !y.IsConnected); entry.Total = cars.Count; entry.Available = cars.Count(y => !y.IsConnected); entry.IsAvailable = entry.Available > 0; } entry.SetAvailableSkinId(availableSkin?.CarSkinId, RequiredCspVersion == 0 ? null : availableSkin?.CspParams); } } var missingContentUpdate = UpdateMissingContentExtended(resultStatus == ServerStatus.MissingContent); if (missingContentUpdate.HasValue) { resultStatus = missingContentUpdate.Value; } if (IsBookedForPlayer) { FixedCar = true; } else { FixedCar = false; LoadSelectedCar(); } // Ping server if (Ping == null || mode == UpdateMode.Full || !SettingsHolder.Online.PingOnlyOnce) { if (mode == UpdateMode.Lite) { await TryToPing(); } else { TryToPing().Ignore(); } } } catch (Exception e) { _updateException = e; resultStatus = ServerStatus.Error; Logging.Error(e); } finally { if (driversCount != -1) { CurrentDriversCount = driversCount; } UpdateProgress = AsyncProgressEntry.Ready; Status = !SettingsHolder.Online.LoadServersWithMissingContent && resultStatus == ServerStatus.MissingContent ? ServerStatus.Error : resultStatus; UpdateMissingContent(); UpdateErrorsList(); AvailableUpdate(); _updating = false; } }