public async Task LaunchAsync() { if (State == ApplicationState.Patching) { App.Current.Logger.Info(nameof(MainWindowViewModel), "Cancelling launch"); _LaunchCancellationTokenSource?.Cancel(); return; } UploadErrorButtonVisible = false; IsChangelogVisible = false; _ActivityCount += 1; App.Current.Logger.Info(nameof(MainWindowViewModel), "Starting launch procedure"); try { _LaunchCancellationTokenSource = new CancellationTokenSource(); App.Current.Logger.Info(nameof(MainWindowViewModel), "Saving client settings"); await Task.Run(() => { Properties.Settings.Default.EnglishPatchEnabled = ArksLayerEnglishPatchEnabled; Properties.Settings.Default.TelepipeProxyEnabled = ArksLayerTelepipeProxyEnabled; Properties.Settings.Default.ModFilesEnabled = ModFilesEnabled; Properties.Settings.Default.Save(); }); while (true) { try { _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); var newPhases = new ObservableCollection <PhaseState>(); var pso2DirectoriesPhase = new PSO2DirectoriesPhase(InstallConfiguration); var pso2DirectoriesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_PSO2Directories" }; newPhases.Add(pso2DirectoriesPhaseState); ModFilesPhase modFilesPhase = null; PhaseState modFilesPhaseState = null; if (Properties.Settings.Default.ModFilesEnabled) { modFilesPhase = new ModFilesPhase(InstallConfiguration); modFilesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_ModFiles" }; newPhases.Add(modFilesPhaseState); } var deleteCensorFilePhase = new DeleteCensorFilePhase(InstallConfiguration); var deleteCensorFilePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_DeleteCensorFile" }; newPhases.Add(deleteCensorFilePhaseState); var downloadConfigurationState = new PhaseState { TitleKey = "MainWindow_Phase_DownloadConfiguration" }; newPhases.Add(downloadConfigurationState); var patchCacheState = new PhaseState { TitleKey = "MainWindow_Phase_PatchCache" }; newPhases.Add(patchCacheState); var comparePhase = new ComparePhase(InstallConfiguration); var comparePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_Compare" }; newPhases.Add(comparePhaseState); { var compareProgressControl = new ProgressControl(); compareProgressControl.SetBinding(ProgressControl.ProgressProperty, new Binding { Source = comparePhase.Progress, Path = new PropertyPath(nameof(comparePhase.Progress.Progress)), Mode = BindingMode.OneWay }); compareProgressControl.SetBinding(ProgressControl.IsIndeterminateProperty, new Binding { Source = comparePhase.Progress, Path = new PropertyPath(nameof(comparePhase.Progress.IsIndeterminate)), Mode = BindingMode.OneWay }); comparePhaseState.Child = compareProgressControl; } var verifyFilesPhase = new VerifyFilesPhase(InstallConfiguration); var verifyFilesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_VerifyFiles" }; newPhases.Add(verifyFilesPhaseState); { var verifyFilesControl = new ProgressControl(); verifyFilesControl.SetBinding(ProgressControl.ProgressProperty, new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.Progress)), Mode = BindingMode.OneWay }); verifyFilesControl.SetBinding(ProgressControl.IsIndeterminateProperty, new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.IsIndeterminate)), Mode = BindingMode.OneWay }); var verifyFilesControlMessageBinding = new MultiBinding { Converter = StringFormatValueConverter.Instance }; verifyFilesControlMessageBinding.Bindings.Add(new LocaleBindingExtension("MainWindow_Phase_VerifyFiles_Message")); verifyFilesControlMessageBinding.Bindings.Add(new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.CompletedCount)), Mode = BindingMode.OneWay }); verifyFilesControlMessageBinding.Bindings.Add(new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.TotalCount)), Mode = BindingMode.OneWay }); verifyFilesControl.SetBinding(ProgressControl.MessageProperty, verifyFilesControlMessageBinding); verifyFilesPhaseState.Child = verifyFilesControl; } var pluginInfoState = new PhaseState { TitleKey = "MainWindow_Phase_PluginInfo" }; newPhases.Add(pluginInfoState); var pso2hPhase = new PSO2hPhase(InstallConfiguration, ArksLayerEnglishPatchEnabled || ArksLayerTelepipeProxyEnabled); var pso2hPhaseState = new PhaseState { TitleKey = ArksLayerEnglishPatchEnabled || ArksLayerTelepipeProxyEnabled ? "MainWindow_Phase_PSO2h_TitleEnabled" : "MainWindow_Phase_PSO2h_TitleDisabled" }; newPhases.Add(pso2hPhaseState); var telepipeProxyPhase = new TelepipeProxyPhase(InstallConfiguration, ArksLayerTelepipeProxyEnabled); var telepipeProxyPhaseState = new PhaseState { TitleKey = ArksLayerTelepipeProxyEnabled ? "MainWindow_Phase_TelepipeProxy_TitleEnabled" : "MainWindow_Phase_TelepipeProxy_TitleDisabled" }; newPhases.Add(telepipeProxyPhaseState); var englishPatchPhase = new EnglishPatchPhase(InstallConfiguration, ArksLayerEnglishPatchEnabled); var englishPatchPhaseState = new PhaseState { TitleKey = ArksLayerEnglishPatchEnabled ? "MainWindow_Phase_EnglishPatch_TitleEnabled" : "MainWindow_Phase_EnglishPatch_TitleDisabled" }; newPhases.Add(englishPatchPhaseState); LargeAddressAwarePhase largeAddressAwarePhase = null; PhaseState largeAddressAwarePhaseState = null; if (Properties.Settings.Default.LargeAddressAwareEnabled) { largeAddressAwarePhase = new LargeAddressAwarePhase(InstallConfiguration); largeAddressAwarePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_LargeAddressAware" }; newPhases.Add(largeAddressAwarePhaseState); } var launchPSO2State = new PhaseState { TitleKey = "MainWindow_Phase_LaunchPSO2" }; newPhases.Add(launchPSO2State); Phases = newPhases; _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(PSO2DirectoriesPhase)}"); await _AttemptPhase(pso2DirectoriesPhaseState, () => pso2DirectoriesPhase.RunAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); if (modFilesPhase != null && modFilesPhaseState != null) { App.Current.Logger.Info("Launch", $"Running {nameof(ModFilesPhase)}"); await _AttemptPhase(modFilesPhaseState, () => modFilesPhase.RunAsync(_LaunchCancellationTokenSource.Token)); } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(DeleteCensorFilePhase)}"); await _AttemptPhase(deleteCensorFilePhaseState, () => deleteCensorFilePhase.RunAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", "Fetching download configuration"); var downloadConfiguration = await _AttemptPhase(downloadConfigurationState, () => DownloadConfiguration.CreateDefaultAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", "Connecting to patch cache database"); var patchCache = await _AttemptPhase(patchCacheState, () => PatchCache.CreateAsync(InstallConfiguration)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); // loop this block so files that were updated while a possibly long // verify phase took place are not missed while (true) { comparePhaseState.State = PhaseControl.State.Queued; verifyFilesPhaseState.State = PhaseControl.State.Queued; _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(ComparePhase)}"); var toUpdate = await _AttemptPhase(comparePhaseState, () => comparePhase.RunAsync(downloadConfiguration, patchCache, _LaunchCancellationTokenSource.Token)); if (toUpdate.Length == 0) { verifyFilesPhaseState.State = PhaseControl.State.Success; break; } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(VerifyFilesPhase)}"); await _AttemptPhase(verifyFilesPhaseState, () => verifyFilesPhase.RunAsync(toUpdate, patchCache, _LaunchCancellationTokenSource.Token)); } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", "Fetching plugin info"); var pluginInfo = await _AttemptPhase(pluginInfoState, () => PluginInfo.FetchAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(PSO2hPhase)}"); await _AttemptPhase(pso2hPhaseState, () => pso2hPhase.RunAsync(pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(TelepipeProxyPhase)}"); await _AttemptPhase(telepipeProxyPhaseState, () => telepipeProxyPhase.RunAsync(pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Current.Logger.Info("Launch", $"Running {nameof(EnglishPatchPhase)}"); await _AttemptPhase(englishPatchPhaseState, () => englishPatchPhase.RunAsync(patchCache, pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); if (largeAddressAwarePhaseState != null && largeAddressAwarePhase != null) { App.Current.Logger.Info("Launch", $"Running {nameof(LargeAddressAwarePhase)}"); await _AttemptPhase(largeAddressAwarePhaseState, () => largeAddressAwarePhase.RunAsync(_LaunchCancellationTokenSource.Token)); } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); // cancellation no longer works after this point App.Current.Logger.Info("Launch", "Starting PSO2"); await _AttemptPhase(launchPSO2State, async() => { var startInfo = new ProcessStartInfo() { FileName = InstallConfiguration.PSO2Executable, Arguments = "+0x33aca2b9", UseShellExecute = false }; startInfo.EnvironmentVariables["-pso2"] = "+0x01e3f1e9"; await Task.Run(() => { var process = new Process() { StartInfo = startInfo }; process.Start(); process.WaitForExit(); }); }); App.Current.Logger.Info("Launch", "PSO2 launch process ended"); } catch (OperationCanceledException) { App.Current.Logger.Info("Launch", "Launch cancelled"); return; } catch (Exception ex) { App.Current.Logger.Info("Launch", "Error during launch phases", ex); UploadErrorButtonVisible = true; try { await Task.Delay(TimeSpan.FromSeconds(10), _LaunchCancellationTokenSource.Token); } catch (OperationCanceledException) { } continue; } break; } } finally { _ActivityCount -= 1; _LaunchCancellationTokenSource = null; } }
public async Task LaunchAsync(bool shouldLaunchPSO2 = true) { IsLaunchingPSO2 = shouldLaunchPSO2; if (State == ApplicationState.Patching) { App.Logger.Info(nameof(MainWindowViewModel), "Cancelling launch"); _LaunchCancellationTokenSource?.Cancel(); return; } UploadErrorButtonVisible = false; IsChangelogVisible = false; _ActivityCount += 1; App.Logger.Info(nameof(MainWindowViewModel), "Starting launch procedure"); try { _LaunchCancellationTokenSource = new CancellationTokenSource(); App.Logger.Info(nameof(MainWindowViewModel), "Saving client settings"); await Task.Run(() => { Properties.Settings.Default.EnglishPatchEnabled = ArksLayerEnglishPatchEnabled; Properties.Settings.Default.TelepipeProxyEnabled = ArksLayerTelepipeProxyEnabled; Properties.Settings.Default.ModFilesEnabled = ModFilesEnabled; Properties.Settings.Default.Save(); }); bool shouldRetry = true; while (shouldRetry) { try { _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); var newPhases = new ObservableCollection <PhaseState>(); var pso2DirectoriesPhase = new PSO2DirectoriesPhase(InstallConfiguration); var pso2DirectoriesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_PSO2Directories" }; newPhases.Add(pso2DirectoriesPhaseState); ModFilesPhase modFilesPhase = null; PhaseState modFilesPhaseState = null; if (Properties.Settings.Default.ModFilesEnabled) { modFilesPhase = new ModFilesPhase(InstallConfiguration); modFilesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_ModFiles" }; newPhases.Add(modFilesPhaseState); } var deleteCensorFilePhase = new DeleteCensorFilePhase(InstallConfiguration); var deleteCensorFilePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_DeleteCensorFile" }; newPhases.Add(deleteCensorFilePhaseState); var downloadConfigurationState = new PhaseState { TitleKey = "MainWindow_Phase_DownloadConfiguration" }; newPhases.Add(downloadConfigurationState); var patchCacheState = new PhaseState { TitleKey = "MainWindow_Phase_PatchCache" }; newPhases.Add(patchCacheState); var comparePhase = new ComparePhase(InstallConfiguration); var comparePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_Compare" }; newPhases.Add(comparePhaseState); { var compareProgressControl = new ProgressControl(); compareProgressControl.SetBinding(ProgressControl.ProgressProperty, new Binding { Source = comparePhase.Progress, Path = new PropertyPath(nameof(comparePhase.Progress.Progress)), Mode = BindingMode.OneWay }); compareProgressControl.SetBinding(ProgressControl.IsIndeterminateProperty, new Binding { Source = comparePhase.Progress, Path = new PropertyPath(nameof(comparePhase.Progress.IsIndeterminate)), Mode = BindingMode.OneWay }); comparePhaseState.Child = compareProgressControl; } var verifyFilesPhase = new VerifyFilesPhase(InstallConfiguration); var verifyFilesPhaseState = new PhaseState { TitleKey = "MainWindow_Phase_VerifyFiles" }; newPhases.Add(verifyFilesPhaseState); { var verifyFilesControl = new ProgressControl(); verifyFilesControl.SetBinding(ProgressControl.ProgressProperty, new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.Progress)), Mode = BindingMode.OneWay }); verifyFilesControl.SetBinding(ProgressControl.IsIndeterminateProperty, new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.IsIndeterminate)), Mode = BindingMode.OneWay }); var verifyFilesControlMessageBinding = new MultiBinding { Converter = StringFormatValueConverter.Instance }; verifyFilesControlMessageBinding.Bindings.Add(new LocaleBindingExtension("MainWindow_Phase_VerifyFiles_Message")); verifyFilesControlMessageBinding.Bindings.Add(new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.CompletedCount)), Mode = BindingMode.OneWay }); verifyFilesControlMessageBinding.Bindings.Add(new Binding { Source = verifyFilesPhase.Progress, Path = new PropertyPath(nameof(verifyFilesPhase.Progress.TotalCount)), Mode = BindingMode.OneWay }); verifyFilesControl.SetBinding(ProgressControl.MessageProperty, verifyFilesControlMessageBinding); verifyFilesPhaseState.Child = verifyFilesControl; } var pluginInfoState = new PhaseState { TitleKey = "MainWindow_Phase_PluginInfo" }; newPhases.Add(pluginInfoState); var pso2hPhase = new PSO2hPhase(InstallConfiguration, ArksLayerEnglishPatchEnabled || ArksLayerTelepipeProxyEnabled); var pso2hPhaseState = new PhaseState { TitleKey = ArksLayerEnglishPatchEnabled || ArksLayerTelepipeProxyEnabled ? "MainWindow_Phase_PSO2h_TitleEnabled" : "MainWindow_Phase_PSO2h_TitleDisabled" }; newPhases.Add(pso2hPhaseState); var telepipeProxyPhase = new TelepipeProxyPhase(InstallConfiguration, ArksLayerTelepipeProxyEnabled); var telepipeProxyPhaseState = new PhaseState { TitleKey = ArksLayerTelepipeProxyEnabled ? "MainWindow_Phase_TelepipeProxy_TitleEnabled" : "MainWindow_Phase_TelepipeProxy_TitleDisabled" }; newPhases.Add(telepipeProxyPhaseState); var englishPatchPhase = new EnglishPatchPhase(InstallConfiguration, ArksLayerEnglishPatchEnabled); var englishPatchPhaseState = new PhaseState { TitleKey = ArksLayerEnglishPatchEnabled ? "MainWindow_Phase_EnglishPatch_TitleEnabled" : "MainWindow_Phase_EnglishPatch_TitleDisabled" }; newPhases.Add(englishPatchPhaseState); LargeAddressAwarePhase largeAddressAwarePhase = null; PhaseState largeAddressAwarePhaseState = null; if (Properties.Settings.Default.LargeAddressAwareEnabled) { largeAddressAwarePhase = new LargeAddressAwarePhase(InstallConfiguration); largeAddressAwarePhaseState = new PhaseState { TitleKey = "MainWindow_Phase_LargeAddressAware" }; newPhases.Add(largeAddressAwarePhaseState); } var launchPSO2State = new PhaseState { TitleKey = "MainWindow_Phase_LaunchPSO2" }; if (IsLaunchingPSO2) { newPhases.Add(launchPSO2State); } Phases = newPhases; _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(PSO2DirectoriesPhase)}"); await _AttemptPhase(pso2DirectoriesPhaseState, () => pso2DirectoriesPhase.RunAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); if (modFilesPhase != null && modFilesPhaseState != null) { App.Logger.Info("Launch", $"Running {nameof(ModFilesPhase)}"); await _AttemptPhase(modFilesPhaseState, () => modFilesPhase.RunAsync(_LaunchCancellationTokenSource.Token)); } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(DeleteCensorFilePhase)}"); await _AttemptPhase(deleteCensorFilePhaseState, () => deleteCensorFilePhase.RunAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", "Fetching download configuration"); var downloadConfiguration = await _AttemptPhase(downloadConfigurationState, () => DownloadConfiguration.CreateDefaultAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", "Connecting to patch cache database"); using (var patchCache = await _AttemptPhase(patchCacheState, () => PatchCache.CreateAsync(InstallConfiguration))) { _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); // loop this block so files that were updated while a possibly long // verify phase took place are not missed while (true) { comparePhaseState.State = PhaseControl.State.Queued; verifyFilesPhaseState.State = PhaseControl.State.Queued; _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(ComparePhase)}"); var toUpdate = await _AttemptPhase(comparePhaseState, () => comparePhase.RunAsync(downloadConfiguration, patchCache, _LaunchCancellationTokenSource.Token)); if (toUpdate.Length == 0) { verifyFilesPhaseState.State = PhaseControl.State.Success; break; } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(VerifyFilesPhase)}"); await _AttemptPhase(verifyFilesPhaseState, () => verifyFilesPhase.RunAsync(toUpdate, patchCache, _LaunchCancellationTokenSource.Token)); } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); try { App.Logger.Info("Launch", "Fetching plugin info"); var pluginInfo = await _AttemptPhase(pluginInfoState, () => PluginInfo.FetchAsync(_LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(PSO2hPhase)}"); await _AttemptPhase(pso2hPhaseState, () => pso2hPhase.RunAsync(pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(TelepipeProxyPhase)}"); await _AttemptPhase(telepipeProxyPhaseState, () => telepipeProxyPhase.RunAsync(pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); App.Logger.Info("Launch", $"Running {nameof(EnglishPatchPhase)}"); await _AttemptPhase(englishPatchPhaseState, () => englishPatchPhase.RunAsync(patchCache, pluginInfo, _LaunchCancellationTokenSource.Token)); _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); } catch (OperationCanceledException) { throw; } catch (Exception ex) { App.Logger.Error("Launch", "Error in Arks-Layer tasks", ex); // only bother the user about this stuff if anything related to arks-layer is currently enabled // (currently this wont attempt to clean up anything arks-layer related so if someone was to decide // they no longer want to use the one of the plugins here, the disabling of them would not work) if (ArksLayerEnglishPatchEnabled || ArksLayerTelepipeProxyEnabled) { var skipArksLayerResult = MessageBox.Show( LocaleManager.Instance["MainWindow_ArksLayerErrorMessage"], LocaleManager.Instance["PSRTAstra"], MessageBoxButton.YesNo, MessageBoxImage.Exclamation); if (skipArksLayerResult == MessageBoxResult.No) { shouldRetry = false; throw; } } } if (largeAddressAwarePhaseState != null && largeAddressAwarePhase != null) { App.Logger.Info("Launch", $"Running {nameof(LargeAddressAwarePhase)}"); await _AttemptPhase(largeAddressAwarePhaseState, () => largeAddressAwarePhase.RunAsync(_LaunchCancellationTokenSource.Token)); } } _LaunchCancellationTokenSource.Token.ThrowIfCancellationRequested(); if (!IsLaunchingPSO2) { break; } // cancellation no longer works after this point App.Logger.Info("Launch", "Starting PSO2"); await _AttemptPhase(launchPSO2State, async() => { var startInfo = new ProcessStartInfo() { FileName = InstallConfiguration.PSO2Executable, Arguments = "+0x33aca2b9", UseShellExecute = false }; startInfo.EnvironmentVariables["-pso2"] = "+0x01e3f1e9"; await Task.Run(() => { var process = new Process() { StartInfo = startInfo }; process.Start(); process.WaitForExit(); }); }); App.Logger.Info("Launch", "PSO2 launch process ended"); if (Properties.Settings.Default.CloseOnLaunchEnabled) { App.Current.Shutdown(); } } // only properly cancel the launch if it was canceled by us catch (OperationCanceledException ex) when(_LaunchCancellationTokenSource.IsCancellationRequested) { App.Logger.Info("Launch", "Launch cancelled", ex); } catch (Exception ex) { App.Logger.Error("Launch", "Error during launch phases", ex); UploadErrorButtonVisible = true; if (shouldRetry) { try { await Task.Delay(TimeSpan.FromSeconds(10), _LaunchCancellationTokenSource.Token); } catch (OperationCanceledException) { App.Logger.Info("Launch", "Launch was canceled during the auto-restart period"); } } continue; } break; } } finally { _ActivityCount -= 1; _LaunchCancellationTokenSource = null; } }