public static void Set(this PakPropertiesViewModel vm, FFileIoStoreReader ioReader) { Application.Current.Dispatcher.Invoke(delegate { vm.PakName = ioReader.FileName; vm.Version = ((int)ioReader.TocResource.Header.Version).ToString(); vm.MountPoint = ioReader.MountPoint; vm.AesKey = ioReader.AesKey?.ToStringKey(); vm.Guid = ioReader.EncryptionKeyGuid.Hex; vm.FileCount = ioReader.Count.ToString(); }); }
/// <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()); }
public static async Task PopulateMenu() { PopulateBase(); await Task.Run(async() => { if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath)) { await Application.Current.Dispatcher.InvokeAsync(delegate { var launcher = new FLauncher(); bool?result = launcher.ShowDialog(); if (result.HasValue && result.Value) { Properties.Settings.Default.PakPath = launcher.Path; Properties.Settings.Default.Save(); } }); } // Add Pak Files if (Properties.Settings.Default.PakPath.EndsWith("-fn.manifest")) { ManifestInfo manifestInfo = await ManifestGrabber.TryGetLatestManifestInfo().ConfigureAwait(false); if (manifestInfo == null) { throw new Exception("Failed to load latest manifest."); } DirectoryInfo chunksDir = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks")); string manifestPath = Path.Combine(chunksDir.FullName, manifestInfo.Filename); byte[] manifestData; if (File.Exists(manifestPath)) { manifestData = await File.ReadAllBytesAsync(manifestPath); } else { manifestData = await manifestInfo.DownloadManifestDataAsync().ConfigureAwait(false); await File.WriteAllBytesAsync(manifestPath, manifestData).ConfigureAwait(false); } Manifest manifest = new Manifest(manifestData, new ManifestOptions { ChunkBaseUri = new Uri("http://download.epicgames.com/Builds/Fortnite/CloudDir/ChunksV3/", UriKind.Absolute), ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks")) }); int pakFiles = 0; foreach (FileManifest fileManifest in manifest.FileManifests) { if (!_pakFileRegex.IsMatch(fileManifest.Name)) { continue; } var pakStream = fileManifest.GetStream(); if (pakStream.Length == 365) { continue; } var pakFileName = fileManifest.Name.Replace('/', '\\'); if (pakFileName.EndsWith(".pak")) { PakFileReader pakFile = new PakFileReader(pakFileName, pakStream); if (pakFiles++ == 0) { // define the current game thank to the pak path Folders.SetGameName(pakFileName); Globals.Game.Version = pakFile.Info.Version; Globals.Game.SubVersion = pakFile.Info.SubVersion; } await Application.Current.Dispatcher.InvokeAsync(delegate { MenuItems.pakFiles.Add(new PakMenuItemViewModel { PakFile = pakFile, IsEnabled = false }); }); } else if (pakFileName.EndsWith(".ucas")) { var utocStream = manifest.FileManifests.FirstOrDefault(x => x.Name.Equals(fileManifest.Name.Replace(".ucas", ".utoc"))); var ioStore = new FFileIoStoreReader(pakFileName.SubstringAfterLast('\\'), pakFileName.SubstringBeforeLast('\\'), utocStream.GetStream(), pakStream); await Application.Current.Dispatcher.InvokeAsync(delegate { MenuItems.pakFiles.Add(new PakMenuItemViewModel { IoStore = ioStore, IsEnabled = false }); }); } } } else if (Properties.Settings.Default.PakPath.EndsWith("-val.manifest")) { ValorantAPIManifest manifest = await ValorantAPIManifest.DownloadAndParse(Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))).ConfigureAwait(false); if (manifest == null) { throw new Exception("Failed to load latest manifest."); } for (int i = 0; i < manifest.Paks.Length; i++) { ValorantPak pak = manifest.Paks[i]; var pakFileName = @$ "ShooterGame\Content\Paks\{pak.Name}"; PakFileReader pakFile = new PakFileReader(pakFileName, manifest.GetPakStream(i)); if (i == 0) { // define the current game thank to the pak path Folders.SetGameName(pakFileName); Globals.Game.Version = pakFile.Info.Version; Globals.Game.SubVersion = pakFile.Info.SubVersion; } await Application.Current.Dispatcher.InvokeAsync(delegate { MenuItems.pakFiles.Add(new PakMenuItemViewModel { PakFile = pakFile, IsEnabled = false }); }); } }
public IoPackageReader(BinaryReader uasset, Stream ubulk, FIoGlobalData globalData, FFileIoStoreReader reader, bool onlyInfo = false) { Loader = uasset; _ubulk = ubulk; GlobalData = globalData; Summary = new FPackageSummary(this); var nameMap = new List <FNameEntrySerialized>(); var nameHashes = new List <ulong>(); if (Summary.NameMapNamesSize > 0) { Loader.BaseStream.Position = Summary.NameMapNamesOffset; var nameMapNames = Loader.ReadBytes(Summary.NameMapNamesSize); Loader.BaseStream.Position = Summary.NameMapHashesOffset; var nameMapHashes = Loader.ReadBytes(Summary.NameMapHashesSize); FNameEntrySerialized.LoadNameBatch(nameMap, nameHashes, nameMapNames, nameMapHashes); } NameMap = nameMap.ToArray(); Loader.BaseStream.Position = Summary.ImportMapOffset; var importMapCount = (Summary.ExportMapOffset - Summary.ImportMapOffset) / /*sizeof(FPackageObjectIndex)*/ sizeof(ulong); ImportMap = new FPackageObjectIndex[importMapCount]; for (int i = 0; i < importMapCount; i++) { ImportMap[i] = new FPackageObjectIndex(Loader); } Loader.BaseStream.Position = Summary.ExportMapOffset; var exportMapCount = (Summary.ExportBundlesOffset - Summary.ExportMapOffset) / FExportMapEntry.SIZE; ExportMap = new FExportMapEntry[exportMapCount]; for (int i = 0; i < exportMapCount; i++) { ExportMap[i] = new FExportMapEntry(this); } if (!onlyInfo) { ReadContent(); } }
public IoPackageReader(Stream uasset, Stream ubulk, FIoGlobalData globalData, FFileIoStoreReader reader, bool onlyInfo = false) : this(new BinaryReader(uasset), ubulk, globalData, reader, onlyInfo) { }
private async Task Backup() { StatusBarVm.statusBarViewModel.Reset(); await Task.Run(() => { DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[BackupMenuItemViewModel]", "[Create]", $"{_backupFileName} is about to be created"); StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}", Properties.Resources.Loading); using FileStream fileStream = new FileStream(_backupFilePath, FileMode.Create); using LZ4EncoderStream compressionStream = LZ4Stream.Encode(fileStream, LZ4Level.L00_FAST); using BinaryWriter writer = new BinaryWriter(compressionStream); foreach (PakFileReader pakFile in MenuItems.pakFiles.GetPakFileReaders()) { if (pakFile.Info.bEncryptedIndex && pakFile.AesKey == null) { continue; } if (!Globals.CachedPakFiles.ContainsKey(pakFile.FileName)) { pakFile.ReadIndex(pakFile.AesKey); Globals.CachedPakFiles[pakFile.FileName] = pakFile; StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.MountedPakTo, pakFile.FileName, pakFile.MountPoint), Properties.Resources.Loading); } foreach (var(_, entry) in pakFile) { // uasset or umap or idk writer.Write(entry.Offset); writer.Write(entry.Size); writer.Write(entry.UncompressedSize); writer.Write(entry.Encrypted); writer.Write(entry.StructSize); writer.Write(pakFile.MountPoint + entry.Name); writer.Write(entry.CompressionMethodIndex); // uexp if (entry.Uexp != null && entry.Uexp is FPakEntry uexp) { writer.Write(uexp.Offset); writer.Write(uexp.Size); writer.Write(uexp.UncompressedSize); writer.Write(uexp.Encrypted); writer.Write(uexp.StructSize); writer.Write(pakFile.MountPoint + entry.Uexp.Name); writer.Write(uexp.CompressionMethodIndex); } // ubulk if (entry.Ubulk != null && entry.Ubulk is FPakEntry ubulk) { writer.Write(ubulk.Offset); writer.Write(ubulk.Size); writer.Write(ubulk.UncompressedSize); writer.Write(ubulk.Encrypted); writer.Write(ubulk.StructSize); writer.Write(pakFile.MountPoint + entry.Ubulk.Name); writer.Write(ubulk.CompressionMethodIndex); } } } FFileIoStoreReader globalReader = null; foreach (FFileIoStoreReader ioStore in MenuItems.pakFiles.GetIoStoreReaders()) { if (ioStore.IsEncrypted && ioStore.AesKey == null) { continue; } if (!Globals.CachedIoStores.ContainsKey(ioStore.FileName)) { if (ioStore.FileName.Contains("global.ucas", StringComparison.OrdinalIgnoreCase)) { globalReader = ioStore; continue; } if (!ioStore.ReadDirectoryIndex()) { continue; } Globals.CachedIoStores[ioStore.FileName] = ioStore; StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.MountedPakTo, ioStore.FileName, ioStore.MountPoint), Properties.Resources.Loading); } foreach (var(_, entry) in ioStore) { // uasset or umap or idk writer.Write(entry.Offset); writer.Write(entry.Length); writer.Write(entry.UncompressedSize); writer.Write(entry.Encrypted); writer.Write(entry.StructSize); writer.Write(ioStore.MountPoint + entry.Name); writer.Write(entry.CompressionMethodIndex); // uexp if (entry.Uexp != null && entry.Uexp is FIoStoreEntry uexp) { writer.Write(uexp.Offset); writer.Write(uexp.Length); writer.Write(uexp.UncompressedSize); writer.Write(uexp.Encrypted); writer.Write(uexp.StructSize); writer.Write(ioStore.MountPoint + entry.Uexp.Name); writer.Write(uexp.CompressionMethodIndex); } // ubulk if (entry.Ubulk != null && entry.Ubulk is FIoStoreEntry ubulk) { writer.Write(ubulk.Offset); writer.Write(ubulk.Length); writer.Write(ubulk.UncompressedSize); writer.Write(ubulk.Encrypted); writer.Write(ubulk.StructSize); writer.Write(ioStore.MountPoint + entry.Ubulk.Name); writer.Write(ubulk.CompressionMethodIndex); } } } }).ContinueWith(t => { if (t.Exception != null) { Tasks.TaskCompleted(t.Exception); } else if (new FileInfo(_backupFilePath).Length > 0) { DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[BackupMenuItemViewModel]", "[Create]", $"{_backupFileName} successfully created"); StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.CreateSuccess, _backupFileName), Properties.Resources.Success); Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.CreateSuccess, _backupFileName), "/FModel;component/Resources/check-circle.ico", _backupFilePath); } else { File.Delete(_backupFilePath); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[BackupMenuItemViewModel]", "[Create]", $"{_backupFileName} is empty, hence deleted"); StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.CreateError, _backupFileName), Properties.Resources.Error); Globals.gNotifier.ShowCustomMessage(Properties.Resources.Error, string.Format(Properties.Resources.CreateError, _backupFileName), "/FModel;component/Resources/alert.ico"); } }, TaskScheduler.FromCurrentSynchronizationContext()); }