Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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;
            }
        }
Exemplo n.º 4
0
        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;
            }
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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);
            }
        }
Exemplo n.º 7
0
        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();
                        }
                }));
            }
        }
Exemplo n.º 8
0
        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));
        }
Exemplo n.º 9
0
        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);
        }
Exemplo n.º 10
0
        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);
            }
        }
Exemplo n.º 11
0
        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);
            }
        }
Exemplo n.º 12
0
        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();
                    }
            }
        }
Exemplo n.º 13
0
        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;
            }
        }
Exemplo n.º 14
0
        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;
                    }
            }
        }
Exemplo n.º 15
0
        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);
            }
        }
Exemplo n.º 16
0
        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);
        }
Exemplo n.º 17
0
        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);
            }
        }
Exemplo n.º 18
0
        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);
            }
        }
Exemplo n.º 19
0
        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;
                }
            }
        }
Exemplo n.º 20
0
        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);
            }
        }
Exemplo n.º 21
0
        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);
            }
        }
Exemplo n.º 22
0
        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;
            }
        }
Exemplo n.º 23
0
            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();
            }
Exemplo n.º 24
0
        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);
        }
Exemplo n.º 25
0
 private async Task <string> LoadLinux64Wrapper(CancellationToken cancellation)
 {
     return((await CmApiProvider.GetStaticDataAsync("ac_server_wrapper-linux-x64"))?.Item1);
 }
Exemplo n.º 26
0
        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;
            }
        }