/// <summary> /// USER SELECTION ARRAY WILL BREAK AT THE FIRST ERROR /// This won't happen for other type of extraction like in diff mode where we have to skip errors /// </summary> /// <param name="selection"></param> /// <returns></returns> public static async Task GetUserSelection(IList selection) { _timer = Stopwatch.StartNew(); ImageBoxVm.imageBoxViewModel.Reset(); AvalonEditVm.avalonEditViewModel.Reset(); ExtractStopVm.stopViewModel.IsEnabled = true; ExtractStopVm.extractViewModel.IsEnabled = false; StatusBarVm.statusBarViewModel.Set(string.Empty, Properties.Resources.Loading); Tasks.TokenSource = new CancellationTokenSource(); await Task.Run(() => { foreach (var item in selection) { if (Tasks.TokenSource.IsCancellationRequested) { throw new TaskCanceledException(Properties.Resources.Canceled); } Thread.Sleep(10); // this is actually useful because it smh unfreeze the ui so the user can cancel even tho it's a Task so... if (item is ListBoxViewModel selected) { if (Globals.CachedPakFiles.TryGetValue(selected.PakEntry.PakFileName, out var r)) { string mount = r.MountPoint; switch (selected.PakEntry.GetExtension()) { case ".ini": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; using var reader = new StreamReader(asset); AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), selected.PakEntry.GetNameWithExtension(), AvalonEditVm.IniHighlighter); break; } case ".uproject": case ".uplugin": case ".upluginmanifest": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; using var reader = new StreamReader(asset); AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), selected.PakEntry.GetNameWithExtension()); break; } case ".locmeta": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocMetaReader(asset), Formatting.Indented), selected.PakEntry.GetNameWithExtension()); break; } case ".locres": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocResReader(asset).Entries, Formatting.Indented), selected.PakEntry.GetNameWithExtension()); break; } case ".udic": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FOodleDictionaryArchive(asset).Header, Formatting.Indented), selected.PakEntry.GetNameWithExtension()); break; } case ".bin": { if ( !selected.PakEntry.Name.Equals("FortniteGame/AssetRegistry.bin") && // this file is 85mb... selected.PakEntry.Name.Contains("AssetRegistry")) // only parse AssetRegistry (basically the ones in dynamic paks) { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FAssetRegistryState(asset), Formatting.Indented), selected.PakEntry.GetNameWithExtension()); } break; } case ".png": { using var asset = GetMemoryStream(mount + selected.PakEntry.GetPathWithoutExtension()); asset.Position = 0; ImageBoxVm.imageBoxViewModel.Set(SKBitmap.Decode(asset), selected.PakEntry.GetNameWithExtension()); break; } case ".ushaderbytecode": case ".pck": break; default: AvalonEditVm.avalonEditViewModel.Set(GetJsonProperties(selected.PakEntry, mount, true), selected.PakEntry.GetNameWithExtension()); break; } if (Properties.Settings.Default.AutoExport) { Export(selected.PakEntry, true); } } } } }).ContinueWith(t => { _timer.Stop(); ExtractStopVm.stopViewModel.IsEnabled = false; ExtractStopVm.extractViewModel.IsEnabled = true; if (t.Exception != null) { Tasks.TaskCompleted(t.Exception); } else { StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.TimeElapsed, _timer.ElapsedMilliseconds), Properties.Resources.Success); } }, TaskScheduler.FromCurrentSynchronizationContext()); }
/// <summary> /// USER SELECTION ARRAY WILL BREAK AT THE FIRST ERROR /// This won't happen for other type of extraction like in diff mode where we have to skip errors /// </summary> /// <param name="selection"></param> /// <returns></returns> public static async Task GetUserSelection(IList selection) { _timer = Stopwatch.StartNew(); ImageBoxVm.imageBoxViewModel.Reset(); AvalonEditVm.avalonEditViewModel.Reset(); ExtractStopVm.stopViewModel.IsEnabled = true; ExtractStopVm.extractViewModel.IsEnabled = false; StatusBarVm.statusBarViewModel.Set(string.Empty, Properties.Resources.Loading); Tasks.TokenSource = new CancellationTokenSource(); await Task.Run(() => { foreach (var item in selection) { if (Tasks.TokenSource.IsCancellationRequested) { throw new TaskCanceledException(Properties.Resources.Canceled); } Thread.Sleep(10); // this is actually useful because it smh unfreeze the ui so the user can cancel even tho it's a Task so... if (item is ListBoxViewModel selected) { FFileIoStoreReader io = null; if (Globals.CachedPakFiles.TryGetValue(selected.ReaderEntry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(selected.ReaderEntry.ContainerName, out io)) { string mount = r != null ? r.MountPoint : io !.MountPoint; string ext = selected.ReaderEntry.GetExtension(); switch (ext) { case ".ini": case ".txt": case ".bat": case ".xml": case ".h": case ".uproject": case ".uplugin": case ".upluginmanifest": case ".csv": case ".json": { IHighlightingDefinition syntax = ext switch { ".ini" => AvalonEditVm.IniHighlighter, ".txt" => AvalonEditVm.IniHighlighter, ".bat" => AvalonEditVm.IniHighlighter, ".csv" => AvalonEditVm.IniHighlighter, ".xml" => AvalonEditVm.XmlHighlighter, ".h" => AvalonEditVm.CppHighlighter, _ => AvalonEditVm.JsonHighlighter }; using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; using var reader = new StreamReader(asset); AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), mount + selected.ReaderEntry.Name, syntax); break; } case ".locmeta": { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocMetaReader(asset), Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".locres": { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocResReader(asset).Entries, Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".udic": { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FOodleDictionaryArchive(asset).Header, Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".bin": { if ( !selected.ReaderEntry.Name.Equals("FortniteGame/AssetRegistry.bin") && // this file is 85mb... selected.ReaderEntry.Name.Contains("AssetRegistry")) // only parse AssetRegistry (basically the ones in dynamic paks) { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FAssetRegistryState(asset), Formatting.Indented), mount + selected.ReaderEntry.Name); } break; } case ".bnk": case ".pck": { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; WwiseReader bnk = new WwiseReader(new BinaryReader(asset)); Application.Current.Dispatcher.Invoke(delegate { DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {selected.ReaderEntry.GetNameWithExtension()}"); if (!FWindows.IsWindowOpen <Window>(Properties.Resources.AudioPlayer)) { new AudioPlayer().LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile()); } else { ((AudioPlayer)FWindows.GetOpenedWindow <Window>(Properties.Resources.AudioPlayer)).LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile()); } }); break; } case ".png": { using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; ImageBoxVm.imageBoxViewModel.Set(SKBitmap.Decode(asset), mount + selected.ReaderEntry.Name); break; } case ".ushaderbytecode": break; default: AvalonEditVm.avalonEditViewModel.Set(GetJsonProperties(selected.ReaderEntry, mount, true), mount + selected.ReaderEntry.Name); break; } if (Properties.Settings.Default.AutoExport) { Export(selected.ReaderEntry, true); } } } } }).ContinueWith(t => { _timer.Stop(); ExtractStopVm.stopViewModel.IsEnabled = false; ExtractStopVm.extractViewModel.IsEnabled = true; if (t.Exception != null) { Tasks.TaskCompleted(t.Exception); } else { StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.TimeElapsed, _timer.ElapsedMilliseconds), Properties.Resources.Success); } }, TaskScheduler.FromCurrentSynchronizationContext()); }