public PatchProvider(MonoBehaviour behaviour, PatchCache cache) { this.behaviour = behaviour; #if SAFETY_CHECK this.cache = cache; #endif }
public MenuRenderer(Wad wad, DrawScreen screen) { this.wad = wad; this.screen = screen; cache = new PatchCache(wad); }
public OpeningSequenceRenderer(Wad wad, DrawScreen screen, SfmlRenderer parent) { this.screen = screen; this.parent = parent; cache = new PatchCache(wad); }
public OpeningSequenceRenderer(DrawScreen screen, IRenderer parent) { this.screen = screen; this.parent = parent; this.cache = new PatchCache(); }
// Static Query Methods public static void QueryPatchDirs(PatchCache cache, DirectoryInfo patchDir) { if (cache.Initialized || !patchDir.Exists) { return; } var patches = cache.KipPatches; string type = null; if (StrEquals(AmsNsoPatchDir, patchDir.Name)) { patches = cache.NsoPatches; type = "NSO"; } else if (StrEquals(AmsNroPatchDir, patchDir.Name)) { patches = cache.NroPatches; type = "NRO"; } else if (StrEquals(AmsKipPatchDir, patchDir.Name)) { patches = cache.KipPatches; type = "KIP"; } else { return; } foreach (var modDir in patchDir.EnumerateDirectories()) { patches.Add(new Mod <DirectoryInfo>(modDir.Name, modDir)); Logger.Info?.Print(LogClass.ModLoader, $"Found {type} patch '{modDir.Name}'"); } }
public FinaleRenderer(CommonResource resource, DrawScreen screen) { this.flats = resource.Flats; this.sprites = resource.Sprites; this.screen = screen; this.scale = screen.Width / 320; this.cache = new PatchCache(); }
public async Task RunAsync(PatchCache patchCache, PluginInfo pluginInfo, CancellationToken ct = default) { if (_Enabled) { await _InstallAsync(patchCache, pluginInfo, ct); } else { await _RemoveAsync(ct); } }
public FinaleRenderer(CommonResource resource, DrawScreen screen) { wad = resource.Wad; flats = resource.Flats; sprites = resource.Sprites; this.screen = screen; scale = screen.Width / 320; cache = new PatchCache(wad); }
public FinaleRenderer(GameContent content, DrawScreen screen) { wad = content.Wad; flats = content.Flats; sprites = content.Sprites; this.screen = screen; scale = screen.Width / 320; cache = new PatchCache(wad); }
private async Task _InstallAsync(PatchCache patchCache, PluginInfo pluginInfo, CancellationToken ct = default) { App.Logger.Info(nameof(EnglishPatchPhase), "Verifying translation plugins and data"); await pluginInfo.BlockTranslation.ValidateAsync(_InstallConfiguration, ct); await pluginInfo.ItemTranslation.ValidateAsync(_InstallConfiguration, ct); await pluginInfo.TitleTranslation.ValidateAsync(_InstallConfiguration, ct); await pluginInfo.TextTranslation.ValidateAsync(_InstallConfiguration, ct); }
public IntermissionRenderer(Wad wad, DrawScreen screen) { this.wad = wad; this.screen = screen; cache = new PatchCache(wad); minus = Patch.FromWad(wad, "WIMINUS"); numbers = new Patch[10]; for (var i = 0; i < 10; i++) { numbers[i] = Patch.FromWad(wad, "WINUM" + i); } percent = Patch.FromWad(wad, "WIPCNT"); colon = Patch.FromWad(wad, "WICOLON"); scale = screen.Width / 320; }
public IntermissionRenderer(DrawScreen screen) { this.screen = screen; this.cache = new PatchCache(); this.minus = Patch.FromWad("WIMINUS"); this.numbers = new Patch[10]; for (var i = 0; i < 10; i++) { this.numbers[i] = Patch.FromWad("WINUM" + i); } this.percent = Patch.FromWad("WIPCNT"); this.colon = Patch.FromWad("WICOLON"); this.scale = screen.Width / 320; }
static bool TryQuery(ModCache mods, PatchCache patches, ulong?titleId, DirectoryInfo dir, DirectoryInfo searchDir) { if (StrEquals(AmsContentsDir, dir.Name)) { if (titleId.HasValue) { QueryContentsDir(mods, dir, (ulong)titleId); return(true); } } else if (IsPatchesDir(dir.Name)) { QueryPatchDirs(patches, dir, searchDir); return(true); } return(false); }
static bool TryQuery(DirectoryInfo searchDir, PatchCache patches, Dictionary <ulong, ModCache> modCaches) { if (IsContentsDir(searchDir.Name)) { foreach (var(titleId, cache) in modCaches) { QueryContentsDir(cache, searchDir, titleId); } return(true); } else if (IsPatchesDir(searchDir.Name)) { QueryPatchDirs(patches, searchDir); return(true); } return(false); }
public MenuRenderer(DrawScreen screen) { this.screen = screen; this.cache = new PatchCache(); }
public async Task RunAsync(PatchInfo[] toUpdate, PatchCache patchCache, CancellationToken ct = default) { Progress.Progress = 0; Progress.IsIndeterminate = true; Progress.CompletedCount = 0; Progress.TotalCount = 0; if (toUpdate.Length == 0) { return; } var state = new ProcessState { AtomicIndex = 0, AtomicCompletedCount = 0, AtomicProcessCount = 0, UpdateBuckets = new ConcurrentQueue <List <PatchCacheEntry> >() }; var processCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct); Progress.TotalCount = toUpdate.Length; App.Logger.Info(nameof(VerifyFilesPhase), "Starting processing threads"); Progress.IsIndeterminate = false; // TODO: processor affinity? var threadTasks = Enumerable.Range(0, Environment.ProcessorCount) .Select(i => ConcurrencyUtils.RunOnDedicatedThreadAsync(() => { Interlocked.Increment(ref state.AtomicProcessCount); try { App.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} started"); _Process(state, toUpdate, processCancellationTokenSource.Token); } catch (OperationCanceledException) { App.Logger.Error(nameof(VerifyFilesPhase), $"Processing thread {i} canceled"); processCancellationTokenSource.Cancel(); throw; } catch (Exception ex) { App.Logger.Error(nameof(VerifyFilesPhase), $"Exception in processing thread {i}", ex); processCancellationTokenSource.Cancel(); throw; } finally { Interlocked.Decrement(ref state.AtomicProcessCount); App.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} ended"); } }, $"{nameof(VerifyFilesPhase)}({i})")).ToArray(); await Task.Run(async() => { while (state.AtomicProcessCount > 0 || state.UpdateBuckets.Count != 0) { await Task.Delay(250, ct); Progress.Progress = state.AtomicCompletedCount / (double)toUpdate.Length; Progress.CompletedCount = state.AtomicCompletedCount; if (state.UpdateBuckets.Count == 0) { continue; } while (state.UpdateBuckets.TryDequeue(out var list)) { if (list.Count > 0) { await patchCache.InsertUnderTransactionAsync(list); } } } }); Progress.IsIndeterminate = true; App.Logger.Info(nameof(VerifyFilesPhase), "Joining processing threads"); try { await Task.WhenAll(threadTasks); } catch (Exception ex) { App.Logger.Error(nameof(VerifyFilesPhase), "Error verifying files", ex); throw; } }
// Assumes searchDirPaths don't overlap public static void CollectMods(Dictionary <ulong, ModCache> modCaches, PatchCache patches, params string[] searchDirPaths) {
public async Task RunAsync(PatchInfo[] toUpdate, PatchCache patchCache, CancellationToken ct = default) { Progress.Progress = 0; Progress.IsIndeterminate = true; Progress.CompletedCount = 0; Progress.TotalCount = 0; if (toUpdate.Length == 0) { return; } var state = new ProcessState { AtomicIndex = 0, AtomicCompletedCount = 0, AtomicProcessCount = 0, UpdateBuckets = new ConcurrentQueue <List <PatchCacheEntry> >() }; var exceptions = new ConcurrentBag <Exception>(); var errorCancellationTokenSource = new CancellationTokenSource(); var processCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(errorCancellationTokenSource.Token, ct); Progress.TotalCount = toUpdate.Length; App.Current.Logger.Info(nameof(VerifyFilesPhase), "Starting processing threads"); Progress.IsIndeterminate = false; // TODO: processor affinity? var threads = Enumerable.Range(0, Environment.ProcessorCount).Select(i => { var thread = new Thread(() => { Interlocked.Increment(ref state.AtomicProcessCount); try { App.Current.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} started"); _ProcessAsync(state, toUpdate, processCancellationTokenSource.Token).GetAwaiter().GetResult(); } catch (OperationCanceledException ex) { App.Current.Logger.Error(nameof(VerifyFilesPhase), $"Processing thread {i} canceled", ex); } catch (Exception ex) { App.Current.Logger.Error(nameof(VerifyFilesPhase), $"Exception in processing thread {i}", ex); exceptions.Add(ex); errorCancellationTokenSource.Cancel(); } finally { Interlocked.Decrement(ref state.AtomicProcessCount); App.Current.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} ended"); } }); thread.Name = $"{nameof(VerifyFilesPhase)}({i})"; thread.Start(); return(thread); }).ToArray(); await Task.Run(async() => { while (state.AtomicProcessCount > 0 || state.UpdateBuckets.Count != 0) { await Task.Delay(250, ct); Progress.Progress = state.AtomicCompletedCount / (double)toUpdate.Length; Progress.CompletedCount = state.AtomicCompletedCount; if (state.UpdateBuckets.Count == 0) { continue; } while (state.UpdateBuckets.TryDequeue(out var list)) { if (list.Count > 0) { await patchCache.InsertUnderTransactionAsync(list); } } } }); Progress.IsIndeterminate = true; App.Current.Logger.Info(nameof(VerifyFilesPhase), "Joining processing threads"); foreach (var t in threads) { await Task.Factory.StartNew(() => t.Join(), TaskCreationOptions.LongRunning); } if (exceptions.Count > 0) { var aggregate = new AggregateException("Error verifying files", exceptions); App.Current.Logger.Error(nameof(VerifyFilesPhase), "Error verifying files", aggregate); throw aggregate; } }
public void Clear() { AppMods.Clear(); Patches = new PatchCache(); }
public ModLoader() { AppMods = new Dictionary <ulong, ModCache>(); Patches = new PatchCache(); }
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; } }
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; } }
private async Task _InstallAsync(PatchCache patchCache, PluginInfo pluginInfo, CancellationToken ct = default) { App.Current.Logger.Info(nameof(EnglishPatchPhase), "Downloading english translation information"); var translation = await TranslationInfo.FetchEnglishAsync(ct); App.Current.Logger.Info(nameof(EnglishPatchPhase), "Getting data from patch cache"); var cacheData = await patchCache.SelectAllAsync(); string CreateRelativePath(string path) { var root = new Uri(_InstallConfiguration.PSO2BinDirectory); var relative = root.MakeRelativeUri(new Uri(path)); return(relative.OriginalString); } bool Verify(string path, string hash) { var relative = CreateRelativePath(path); var info = new FileInfo(path); if (info.Exists == false) { return(false); } if (cacheData.ContainsKey(relative) == false) { return(false); } var data = cacheData[relative]; if (data.Hash != hash) { return(false); } if (data.LastWriteTime != info.LastWriteTimeUtc.ToFileTimeUtc()) { return(false); } return(true); } using (var client = new ArksLayerHttpClient()) { async Task VerifyAndDownlodRar(string path, string downloadHash, Uri downloadPath) { if (Verify(path, downloadHash) == false) { App.Current.Logger.Info(nameof(EnglishPatchPhase), $"Downloading \"{Path.GetFileName(downloadPath.LocalPath)}\""); using (var response = await client.GetAsync(downloadPath)) using (var stream = await response.Content.ReadAsStreamAsync()) using (var archive = RarArchive.Open(stream)) { foreach (var file in archive.Entries.Where(e => !e.IsDirectory)) { var filePath = Path.Combine(_InstallConfiguration.ArksLayer.PatchesDirectory, file.Key); using (var fs = File.Create(filePath, 4096, FileOptions.Asynchronous)) await file.OpenEntryStream().CopyToAsync(fs); await patchCache.InsertUnderTransactionAsync(new[] { new PatchCacheEntry() { Name = CreateRelativePath(filePath), Hash = downloadHash, LastWriteTime = new FileInfo(filePath).LastWriteTimeUtc.ToFileTimeUtc() } }); } } } } await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishBlockPatch, translation.BlockMD5, new Uri(translation.BlockPatch)); await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishItemPatch, translation.ItemMD5, new Uri(translation.ItemPatch)); await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishTextPatch, translation.TextMD5, new Uri(translation.TextPatch)); await VerifyAndDownlodRar(_InstallConfiguration.ArksLayer.EnglishTitlePatch, translation.TitleMD5, new Uri(translation.TitlePatch)); } App.Current.Logger.Info(nameof(EnglishPatchPhase), "Validating plugin dlls"); await pluginInfo.PSO2BlockRenameDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2BlockRenameDll, ct); await pluginInfo.PSO2ItemTranslatorDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2ItemTranslatorDll, ct); await pluginInfo.PSO2TitleTranslatorDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2TitleTranslatorDll, ct); await pluginInfo.PSO2RAISERSystemDll.ValidateFileAsync(_InstallConfiguration.ArksLayer.PluginPSO2RAISERSystemDll, ct); }
public static void CollectMods(ModCache mods, PatchCache patches, ulong?titleId, params string[] searchDirPaths) {
public async Task <PatchInfo[]> RunAsync(DownloadConfiguration downloadConfiguration, PatchCache patchCache, CancellationToken ct = default) { Progress.Progress = 0; Progress.IsIndeterminate = true; App.Logger.Info(nameof(ComparePhase), "Fetching patches"); var patches = await PatchInfo.FetchPatchInfosAsync(_InstallConfiguration, downloadConfiguration, ct); App.Logger.Info(nameof(ComparePhase), "Fetching cache data"); var cacheData = await patchCache.SelectAllAsync(); App.Logger.Info(nameof(ComparePhase), "Pre-fetching file times"); var preFetchedFileTimes = await Task.Run(() => _PreFetchFileTimes()); var workingPatches = patches .Select(p => new UpdateInfo { PatchInfo = p, ShouldUpdate = true, LastWriteFileTime = preFetchedFileTimes.ContainsKey(p.Name) ? preFetchedFileTimes[p.Name] : 0 }) .ToArray(); var nextIndexAtomic = 0; var progressValueAtomic = 0; var errorTokenSource = new CancellationTokenSource(); var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct, errorTokenSource.Token); App.Logger.Info(nameof(ComparePhase), "Comparing files"); Progress.IsIndeterminate = false; void ProcessLoop() { try { var pso2ExecutableFileName = Path.GetFileName(_InstallConfiguration.PSO2Executable); while (true) { var index = Interlocked.Increment(ref nextIndexAtomic) - 1; if (index >= workingPatches.Length) { return; } combinedTokenSource.Token.ThrowIfCancellationRequested(); try { ref var patch = ref workingPatches[index]; var relativeFilePath = patch.PatchInfo.Name .Substring(0, patch.PatchInfo.Name.Length - 4) .Replace('/', Path.DirectorySeparatorChar) .ToLower(); var filePath = Path.Combine(_InstallConfiguration.PSO2BinDirectory, relativeFilePath); var fileName = Path.GetFileName(relativeFilePath); // skip this if mod files are not enabled so they are marked as invalid if (Properties.Settings.Default.ModFilesEnabled) { // skip file if a file with the same name exists in the mods folder if (Path.GetDirectoryName(filePath).ToLower() == _InstallConfiguration.DataWin32Directory.ToLower()) { var modFilePath = Path.Combine(_InstallConfiguration.ModsDirectory, fileName); if (File.Exists(modFilePath)) { patch.ShouldUpdate = false; continue; } } } if (!cacheData.ContainsKey(patch.PatchInfo.Name)) { continue; } var cacheEntry = cacheData[patch.PatchInfo.Name]; if (patch.PatchInfo.Hash != cacheEntry.Hash) { continue; } // skip pso2.exe if the file is large address aware patched if (fileName == pso2ExecutableFileName && File.Exists(filePath) && Properties.Settings.Default.LargeAddressAwareEnabled && LargeAddressAware.IsLargeAddressAwarePactchApplied(_InstallConfiguration, patch.PatchInfo.Hash)) { patch.ShouldUpdate = false; continue; } if (patch.LastWriteFileTime == 0) { patch.LastWriteFileTime = new FileInfo(filePath).LastWriteTimeUtc.ToFileTimeUtc(); } patch.ShouldUpdate = patch.LastWriteFileTime != cacheEntry.LastWriteTime; } finally { Interlocked.Increment(ref progressValueAtomic); } } }