Пример #1
0
        private async void ShotAsync(Action <IProgress <Tuple <string, double?> >, CancellationToken> action)
        {
            if (_busy)
            {
                return;
            }
            _busy = true;

            try {
                using (var waiting = new WaitingDialog {
                    WindowStartupLocation = WindowStartupLocation.CenterScreen,
                    Owner = null
                }) {
                    waiting.Report(AsyncProgressEntry.Indetermitate);

                    var cancellation = waiting.CancellationToken;
                    Renderer.IsPaused = true;

                    try {
                        await Task.Run(() => {
                            // ReSharper disable once AccessToDisposedClosure
                            action(waiting, cancellation);
                        });
                    } finally {
                        Renderer.IsPaused = false;
                    }
                }
            } catch (Exception e) {
                NonfatalError.Notify("Can’t build image", e);
            } finally {
                _busy = false;
                UpdateSize();
            }
        }
Пример #2
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();
                        }
                }));
            }
        }
Пример #3
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));
        }
Пример #4
0
        protected override async Task ExecuteInner() {
            try {
                using (var waiting = new WaitingDialog()) {
                    waiting.Report("Solving the issue…");
                    await _execute(waiting.CancellationToken);
                }
            } catch (TaskCanceledException) {
                return;
            } catch (Exception e) {
                NonfatalError.Notify("Can’t solve the issue", e);
                return;
            }

            if (_entry != null) {
                NonfatalError.Instance.Errors.Remove(_entry);
            }
        }
Пример #5
0
        private static async Task <IReadOnlyList <UpdatePreviewError> > Run([NotNull] CarObject car, [CanBeNull] string skinId,
                                                                            [CanBeNull] IReadOnlyList <ToUpdatePreview> toUpdate, [CanBeNull] string presetFilename)
        {
            var carKn5 = FileUtils.GetMainCarFilename(car.Location, car.AcdData);

            if (!File.Exists(carKn5))
            {
                ModernDialog.ShowMessage("Model not found");
                return(null);
            }

            await PrepareAsync();

            Kn5 kn5;

            using (var waiting = new WaitingDialog()) {
                waiting.Report("Loading model…");
                kn5 = await Task.Run(() => Kn5.FromFile(carKn5));
            }

            using (var renderer = new DarkKn5ObjectRenderer(CarDescription.FromKn5(kn5, car.Location, car.AcdData))
            {
                AutoRotate = false,
                AutoAdjustTarget = false,
                AsyncTexturesLoading = true,
                AsyncOverridesLoading = true,
                AutoloadCarLights = false,
                AutoloadShowroomLights = false
            }) {
                var wrapper = new CmPreviewsFormWrapper(car, renderer, skinId, presetFilename);

                if (toUpdate != null)
                {
                    wrapper.SetToUpdate(toUpdate);
                }

                wrapper.Form.Icon = AppIconService.GetAppIcon();
                wrapper.Run();

                return(wrapper.GetErrors());
            }
        }
Пример #6
0
        protected override async Task ExecuteInner()
        {
            try {
                using (var waiting = new WaitingDialog()) {
                    waiting.Report("Solving the issue…");
                    await _execute(waiting.CancellationToken);
                }
            } catch (TaskCanceledException) {
                return;
            } catch (Exception e) {
                NonfatalError.Notify("Can’t solve the issue", e);
                return;
            }

            Solved = true;

            if (_entry != null)
            {
                NonfatalError.Instance.Errors.Remove(_entry);
            }
        }
Пример #7
0
        public static async Task Run(TrackObjectBase track) {
            var modelsFilename = track.ModelsFilename;
            string kn5Filename = null;
            if (!File.Exists(modelsFilename)) {
                modelsFilename = null;
                kn5Filename = Path.Combine(track.Location, track.Id + ".kn5");
                if (!File.Exists(kn5Filename)) {
                    ModernDialog.ShowMessage("Model not found");
                    return;
                }
            }

            Kn5 kn5;
            using (var waiting = new WaitingDialog()) {
                waiting.Report("Loading model…");
                kn5 = await Task.Run(() => modelsFilename != null ? Kn5.FromModelsIniFile(modelsFilename) : Kn5.FromFile(kn5Filename));
            }

            using (var renderer = new TrackMapPreparationRenderer(kn5)) {
                var wrapper = new TrackMapRendererWrapper(track, renderer);
                wrapper.Form.Icon = AppIconService.GetAppIcon();
                wrapper.Run();
            }
        }
Пример #8
0
        public static async Task JoinInvitation([NotNull] string ip, int port, [CanBeNull] string password)
        {
            OnlineManager.EnsureInitialized();

            var list    = OnlineManager.Instance.List;
            var source  = new FakeSource(ip, port);
            var wrapper = new OnlineSourceWrapper(list, source);

            ServerEntry server;

            using (var waiting = new WaitingDialog()) {
                waiting.Report(ControlsStrings.Common_Loading);

                await wrapper.EnsureLoadedAsync();

                server = list.GetByIdOrDefault(source.Id);
                if (server == null)
                {
                    throw new Exception(@"Unexpected");
                }
            }

            if (password != null)
            {
                server.Password = password;
            }

            var content = new OnlineServer(server)
            {
                Margin  = new Thickness(0, 0, 0, -38),
                ToolBar = { FitWidth = true },

                // Values taken from ModernDialog.xaml
                // TODO: Extract them to some style?
                Title = { FontSize = 24, FontWeight = FontWeights.Light, Margin = new Thickness(6, 0, 0, 8) }
            };

            content.Title.SetValue(TextOptions.TextFormattingModeProperty, TextFormattingMode.Ideal);

            var dlg = new ModernDialog {
                ShowTitle          = false,
                Content            = content,
                MinHeight          = 400,
                MinWidth           = 450,
                MaxHeight          = 99999,
                MaxWidth           = 700,
                Padding            = new Thickness(0),
                ButtonsMargin      = new Thickness(8),
                SizeToContent      = SizeToContent.Manual,
                ResizeMode         = ResizeMode.CanResizeWithGrip,
                LocationAndSizeKey = @".OnlineServerDialog"
            };

            dlg.SetBinding(Window.TitleProperty, new Binding {
                Path   = new PropertyPath(nameof(server.DisplayName)),
                Source = server
            });

            dlg.ShowDialog();
            await wrapper.ReloadAsync(true);
        }
Пример #9
0
        public async Task ReplaceSound(CarObject donor)
        {
            if (string.Equals(donor.Id, Id, StringComparison.OrdinalIgnoreCase))
            {
                NonfatalError.Notify(ToolsStrings.Car_ReplaceSound_CannotReplace, "Source and destination are the same.");
                return;
            }

            try {
                using (var waiting = new WaitingDialog()) {
                    waiting.Report();

                    var guids     = donor.GuidsFilename;
                    var soundbank = donor.SoundbankFilename;

                    var newGuilds    = GuidsFilename;
                    var newSoundbank = SoundbankFilename;

                    await Task.Run(() => {
                        var destinations = new[] { newGuilds, newSoundbank }.Where(File.Exists).Select(x => new {
                            Original = x,
                            Backup   = FileUtils.EnsureUnique($"{x}.bak")
                        }).ToList();

                        foreach (var oldFile in destinations)
                        {
                            File.Move(oldFile.Original, oldFile.Backup);
                        }

                        try {
                            if (File.Exists(guids) && File.Exists(soundbank))
                            {
                                File.Copy(soundbank, newSoundbank);
                                File.WriteAllText(newGuilds, File.ReadAllText(guids).Replace(donor.Id, Id));
                            }
                            else if (File.Exists(soundbank) && donor.Author == AcCommonObject.AuthorKunos)
                            {
                                File.Copy(soundbank, newSoundbank);
                                File.WriteAllText(newGuilds, File.ReadAllLines(FileUtils.GetSfxGuidsFilename(AcRootDirectory.Instance.RequireValue))
                                                  .Where(x => !x.Contains(@"} bank:/") || x.Contains(@"} bank:/common") ||
                                                         x.EndsWith(@"} bank:/" + donor.Id))
                                                  .Where(x => !x.Contains(@"} event:/") || x.Contains(@"} event:/cars/" + donor.Id + @"/"))
                                                  .JoinToString(Environment.NewLine).Replace(donor.Id, Id));
                            }
                            else
                            {
                                throw new InformativeException(ToolsStrings.Car_ReplaceSound_WrongCar, ToolsStrings.Car_ReplaceSound_WrongCar_Commentary);
                            }
                        } catch (Exception) {
                            foreach (var oldFile in destinations)
                            {
                                if (File.Exists(oldFile.Original))
                                {
                                    File.Delete(oldFile.Original);
                                }
                                File.Move(oldFile.Backup, oldFile.Original);
                            }
                            throw;
                        }

                        FileUtils.Recycle(destinations.Select(x => x.Backup).ToArray());
                    });
                }
            } catch (Exception e) {
                NonfatalError.Notify(ToolsStrings.Car_ReplaceSound_CannotReplace, ToolsStrings.Car_ReplaceSound_CannotReplace_Commentary, e);
            }
        }
Пример #10
0
            private async Task <IReadOnlyList <UpdatePreviewError> > RunReady()
            {
                _checksum = _options.GetChecksum();
                Logging.Debug(_checksum);

                _finished = false;
                _i        = _j = 0;

                _waiting = new WaitingDialog {
                    CancellationText = "Stop"
                };

                var singleMode = _entries.Count == 1;

                _verySingleMode = singleMode && _entries[0].Skins?.Count == 1;
                var recycled = 0;

                if (!_verySingleMode)
                {
                    _waiting.SetImage(null);

                    if (SettingsHolder.CustomShowroom.PreviewsRecycleOld)
                    {
                        _waiting.SetMultiline(true);
                    }
                }

                var step    = 1d / _entries.Count;
                var postfix = string.Empty;

                _started = Stopwatch.StartNew();

                _dispatcherTimer = new DispatcherTimer(TimeSpan.FromSeconds(0.5), DispatcherPriority.Background, TimerCallback,
                                                       Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher);
                _dispatcherTimer.Start();

                for (_j = 0; _j < _entries.Count; _j++)
                {
                    if (Cancel())
                    {
                        return(_errors);
                    }

                    var entry    = _entries[_j];
                    var progress = step * _j;

                    _currentCar   = entry.Car;
                    _currentSkins = entry.Skins;

                    if (_currentSkins == null)
                    {
                        _waiting.Report(new AsyncProgressEntry("Loading skins…" + postfix, _verySingleMode ? 0d : progress));
                        _waiting.SetDetails(GetDetails(_j, _currentCar, null, null));

                        await _currentCar.SkinsManager.EnsureLoadedAsync();

                        if (Cancel())
                        {
                            return(_errors);
                        }

                        _currentSkins = _currentCar.EnabledOnlySkins.ToList();
                        UpdateApproximate(_currentSkins.Count);
                    }

                    var halfstep = step * 0.5 / _currentSkins.Count;
                    for (_i = 0; _i < _currentSkins.Count; _i++)
                    {
                        if (Cancel())
                        {
                            return(_errors);
                        }

                        _currentSkin = _currentSkins[_i];
                        _waiting.SetDetails(GetDetails(_j, _currentCar, _currentSkin, _currentSkins.Count - _i));

                        var subprogress = progress + step * (0.1 + 0.8 * _i / _currentSkins.Count);
                        var filename    = Path.Combine(_currentSkin.Location, _options.PreviewName);
                        if (SettingsHolder.CustomShowroom.PreviewsRecycleOld && File.Exists(filename))
                        {
                            if (++recycled > 5)
                            {
                                _recyclingWarning = true;
                            }

                            _waiting.Report(new AsyncProgressEntry($"Recycling current preview for {_currentSkin.DisplayName}…" + postfix,
                                                                   _verySingleMode ? 0d : subprogress));
                            await Task.Run(() => FileUtils.Recycle(filename));
                        }

                        _waiting.Report(new AsyncProgressEntry($"Updating skin {_currentSkin.DisplayName}…" + postfix,
                                                               _verySingleMode ? 0d : subprogress + halfstep));

                        try {
                            await _updater.ShotAsync(_currentCar.Id, _currentSkin.Id, filename, _currentCar.AcdData,
                                                     GetInformation(_currentCar, _currentSkin, _presetName, _checksum), PreviewReadyCallback);

                            _shotSkins++;
                        } catch (Exception e) {
                            if (_errors.All(x => x.ToUpdate != entry))
                            {
                                Logging.Warning(e);
                                _errors.Add(new UpdatePreviewError(entry, e.Message, null));
                            }
                        }
                    }
                }

                _dispatcherTimer?.Stop();
                _waiting.Report(new AsyncProgressEntry("Saving…" + postfix, _verySingleMode ? 0d : 0.999999d));
                await _updater.WaitForProcessing();

                _finished = true;

                if (_errors.Count > 0)
                {
                    NonfatalError.Notify("Can’t update previews:\n"
                                         + _errors.Select(x => @"• " + x.Message.ToSentence()).JoinToString(";" + Environment.NewLine));
                }

                return(_errors);
            }
Пример #11
0
        public async Task <ArgumentHandleResult> ProgressRaceOnlineJoin(NameValueCollection p)
        {
            /* required arguments */
            var ip                = p.Get(@"ip");
            var httpPort          = FlexibleParser.TryParseInt(p.Get(@"httpPort"));
            var password          = p.Get(@"plainPassword");
            var encryptedPassword = p.Get(@"password");

            if (string.IsNullOrWhiteSpace(ip))
            {
                throw new InformativeException("IP is missing");
            }

            if (!httpPort.HasValue)
            {
                throw new InformativeException("HTTP port is missing or is in invalid format");
            }

            OnlineManager.EnsureInitialized();

            if (string.IsNullOrWhiteSpace(password) && !string.IsNullOrWhiteSpace(encryptedPassword))
            {
                password = OnlineServer.DecryptSharedPassword(ip, httpPort.Value, encryptedPassword);
            }

            var list    = OnlineManager.Instance.List;
            var source  = new FakeSource(ip, httpPort.Value);
            var wrapper = new OnlineSourceWrapper(list, source);

            ServerEntry server;

            using (var waiting = new WaitingDialog()) {
                waiting.Report(ControlsStrings.Common_Loading);

                await wrapper.EnsureLoadedAsync();

                server = list.GetByIdOrDefault(source.Id);
                if (server == null)
                {
                    throw new Exception(@"Unexpected");
                }
            }

            if (password != null)
            {
                server.Password = password;
            }

            var content = new OnlineServer(server)
            {
                Margin  = new Thickness(0, 0, 0, -43),
                ToolBar = { FitWidth = true },

                // Values taken from ModernDialog.xaml
                // TODO: Extract them to some style?
                Title = { FontSize = 24, FontWeight = FontWeights.Light, Margin = new Thickness(6, 0, 0, 8) }
            };

            content.Title.SetValue(TextOptions.TextFormattingModeProperty, TextFormattingMode.Ideal);

            var dlg = new ModernDialog {
                ShowTitle          = false,
                Content            = content,
                MinHeight          = 400,
                MinWidth           = 450,
                MaxHeight          = 99999,
                MaxWidth           = 700,
                Padding            = new Thickness(0),
                ButtonsMargin      = new Thickness(8),
                SizeToContent      = SizeToContent.Manual,
                ResizeMode         = ResizeMode.CanResizeWithGrip,
                LocationAndSizeKey = @".OnlineServerDialog"
            };

            dlg.SetBinding(Window.TitleProperty, new Binding {
                Path   = new PropertyPath(nameof(server.DisplayName)),
                Source = server
            });

            dlg.ShowDialog();
            await wrapper.ReloadAsync(true);

            return(ArgumentHandleResult.Successful);
        }
Пример #12
0
        private static async Task <IReadOnlyList <UpdatePreviewError> > UpdatePreview(IReadOnlyList <ToUpdatePreview> entries, DarkPreviewsOptions options, string presetName = null,
                                                                                      DarkPreviewsUpdater updater = null)
        {
            var localUpdater = updater == null;

            if (localUpdater)
            {
                updater = new DarkPreviewsUpdater(AcRootDirectory.Instance.RequireValue, options);
            }
            else
            {
                updater.SetOptions(options);
            }

            var errors = new List <UpdatePreviewError>();

            try {
                if (options.Showroom != null && ShowroomsManager.Instance.GetById(options.Showroom) == null)
                {
                    if (options.Showroom == "at_previews" && MissingShowroomHelper != null)
                    {
                        await MissingShowroomHelper.OfferToInstall("Kunos Previews Showroom (AT Previews Special)", "at_previews",
                                                                   "http://www.assettocorsa.net/assetto-corsa-v1-5-dev-diary-part-33/");

                        if (ShowroomsManager.Instance.GetById(options.Showroom) != null)
                        {
                            goto Action;
                        }
                    }

                    throw new InformativeException("Can’t update preview", $"Showroom “{options.Showroom}” is missing");
                }

Action:
                var checksum = options.GetChecksum();

                var finished = false;
                var j        = 0;

                using (var waiting = new WaitingDialog()) {
                    var cancellation = waiting.CancellationToken;

                    var singleMode     = entries.Count == 1;
                    var verySingleMode = singleMode && entries[0].Skins?.Count == 1;
                    var recycled       = 0;

                    if (!verySingleMode)
                    {
                        waiting.SetImage(null);

                        if (SettingsHolder.CustomShowroom.PreviewsRecycleOld)
                        {
                            waiting.SetMultiline(true);
                        }
                    }

                    var step    = 1d / entries.Count;
                    var postfix = string.Empty;

                    var started = Stopwatch.StartNew();
                    var approximateSkinsPerCarCars  = 1;
                    var approximateSkinsPerCarSkins = 10;

                    Action <int> updateApproximate = skinsPerCar => {
                        approximateSkinsPerCarCars++;
                        approximateSkinsPerCarSkins += skinsPerCar;
                    };

                    Func <int, int> leftSkins = currentEntry => {
                        var skinsPerCar = (double)approximateSkinsPerCarSkins / approximateSkinsPerCarCars;

                        var result = 0d;
                        for (var k = currentEntry; k < entries.Count; k++)
                        {
                            var entry = entries[k];
                            result += entry.Skins?.Count ?? skinsPerCar;
                        }

                        return(result.RoundToInt());
                    };

                    var shotSkins        = 0;
                    var recyclingWarning = false;
                    Func <CarObject, CarSkinObject, int?, IEnumerable <string> > getDetails = (car, skin, currentEntrySkinsLeft) => {
                        var left = leftSkins(j) + (currentEntrySkinsLeft ?? approximateSkinsPerCarSkins / approximateSkinsPerCarCars);

                        // ReSharper disable once AccessToModifiedClosure
                        var speed          = shotSkins / started.Elapsed.TotalMinutes;
                        var remainingTime  = speed < 0.0001 ? "Unknown" : $"About {TimeSpan.FromMinutes(left / speed).ToReadableTime()}";
                        var remainingItems = $"About {left} {PluralizingConverter.Pluralize(left, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}";

                        return(new[] {
                            $"Car: {car?.DisplayName}",
                            $"Skin: {skin?.DisplayName ?? "?"}",
                            $"Speed: {speed:F2} {PluralizingConverter.Pluralize(10, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}/{"min"}",
                            $"Time remaining: {remainingTime}",
                            $"Items remaining: {remainingItems}",

                            // ReSharper disable once AccessToModifiedClosure
                            recyclingWarning ? "[i]Recycling seems to take too long? If so, it can always be disabled in Settings.[/i]" : null
                        }.NonNull());
                    };

                    for (j = 0; j < entries.Count; j++)
                    {
                        if (cancellation.IsCancellationRequested)
                        {
                            goto Cancel;
                        }

                        var entry    = entries[j];
                        var progress = step * j;

                        var car   = entry.Car;
                        var skins = entry.Skins;

                        if (skins == null)
                        {
                            waiting.Report(new AsyncProgressEntry("Loading skins…" + postfix, verySingleMode ? 0d : progress));
                            waiting.SetDetails(getDetails(car, null, null));

                            await car.SkinsManager.EnsureLoadedAsync();

                            if (cancellation.IsCancellationRequested)
                            {
                                goto Cancel;
                            }

                            skins = car.EnabledOnlySkins.ToList();
                            updateApproximate(skins.Count);
                        }

                        var halfstep = step * 0.5 / skins.Count;
                        for (var i = 0; i < skins.Count; i++)
                        {
                            if (cancellation.IsCancellationRequested)
                            {
                                goto Cancel;
                            }

                            var skin = skins[i];
                            waiting.SetDetails(getDetails(car, skin, skins.Count - i));

                            var subprogress = progress + step * (0.1 + 0.8 * i / skins.Count);
                            if (SettingsHolder.CustomShowroom.PreviewsRecycleOld && File.Exists(skin.PreviewImage))
                            {
                                if (++recycled > 5)
                                {
                                    recyclingWarning = true;
                                }

                                waiting.Report(new AsyncProgressEntry($"Recycling current preview for {skin.DisplayName}…" + postfix, verySingleMode ? 0d : subprogress));
                                await Task.Run(() => FileUtils.Recycle(skin.PreviewImage));
                            }

                            waiting.Report(new AsyncProgressEntry($"Updating skin {skin.DisplayName}…" + postfix, verySingleMode ? 0d : subprogress + halfstep));

                            try {
                                await updater.ShotAsync(car.Id, skin.Id, skin.PreviewImage, car.AcdData, GetInformation(car, skin, presetName, checksum),
                                                        () => {
                                    if (!verySingleMode)
                                    {
                                        ActionExtension.InvokeInMainThreadAsync(() => {
                                            // ReSharper disable once AccessToModifiedClosure
                                            if (!finished)
                                            {
                                                // ReSharper disable once AccessToDisposedClosure
                                                waiting.SetImage(skin.PreviewImage);
                                            }
                                        });
                                    }
                                });

                                shotSkins++;
                            } catch (Exception e) {
                                if (errors.All(x => x.ToUpdate != entry))
                                {
                                    errors.Add(new UpdatePreviewError(entry, e.Message, null));
                                }
                            }
                        }
                    }

                    waiting.Report(new AsyncProgressEntry("Saving…" + postfix, verySingleMode ? 0d : 0.999999d));
                    await updater.WaitForProcessing();

                    finished = true;
                }

                if (errors.Count > 0)
                {
                    NonfatalError.Notify("Can’t update previews:\n" + errors.Select(x => @"• " + x.Message.ToSentence()).JoinToString(";" + Environment.NewLine));
                }

                goto End;

Cancel:
                for (; j < entries.Count; j++)
                {
                    errors.Add(new UpdatePreviewError(entries[j], ControlsStrings.Common_Cancelled, null));
                }

End:
                return(errors);
            } catch (Exception e) {
                NonfatalError.Notify("Can’t update preview", e);
                return(null);
            } finally {
                if (localUpdater)
                {
                    updater.Dispose();
                    GC.Collect();
                }
            }
        }
Пример #13
0
        public static async Task JoinInvitationNoUI([NotNull] string ip, int port, [CanBeNull] string password)
        {
            OnlineManager.EnsureInitialized();

            var list       = OnlineManager.Instance.List;
            var source     = new FakeSource(ip, port);
            var wrapper    = new OnlineSourceWrapper(list, source);
            var drive_opts = SettingsHolder.Drive;

            ServerEntry server;

            Logging.Write("Going through server list ...");
            using (var waiting = new WaitingDialog())
            {
                waiting.Report(ControlsStrings.Common_Loading);

                await wrapper.EnsureLoadedAsync();

                server = list.GetByIdOrDefault(source.Id);
                if (server == null)
                {
                    throw new Exception(@"Unexpected");
                }
            }

            Logging.Write("Updating server infos ...");
            await server.Update(ServerEntry.UpdateMode.Full, false, true);

            if (password != null)
            {
                server.Password = password;
            }

            //Change name here
            //We are going to use the server entry team name to match client local name.
            //Then we change the client online name to match the name required by the server.
            IReadOnlyList <ServerEntry.CurrentDriver> drivers = server.CurrentDrivers;

            Logging.Write("Going through all drivers ...");

            if (drivers == null)
            {
                throw new Exception(@"Unexpected");
            }
            foreach (var driver in drivers)
            {
                if (driver.Team == drive_opts.PlayerName)
                {
                    drive_opts.PlayerNameOnline = driver.Name;
                    break;
                }
            }

            Logging.Write("Joining server ....");
            await server.JoinCommand.ExecuteAsync(null);

            Logging.Write("Checking booking time ...");
            while (server.BookingTimeLeft > TimeSpan.Zero)
            {
                await Task.Delay(2000);
            }

            Logging.Write("Joining ...");
            await server.JoinCommand.ExecuteAsync(ServerEntry.ActualJoin);

            await wrapper.ReloadAsync(true);
        }