public static async Task PopulateMenu() { PopulateBase(); await Task.Run(() => { if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath)) { Application.Current.Dispatcher.Invoke(delegate { var launcher = new FLauncher(); if ((bool)launcher.ShowDialog()) { Properties.Settings.Default.PakPath = launcher.Path; Properties.Settings.Default.Save(); } }); } // define the current game thank to the pak path Folders.SetGameName(Properties.Settings.Default.PakPath); // Add Pak Files if (Directory.Exists(Properties.Settings.Default.PakPath)) { string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"); for (int i = 0; i < paks.Length; i++) { if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i]))) { PakFileReader pakFile = new PakFileReader(paks[i]); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}"); if (i == 0) { Globals.Game.Version = pakFile.Info.Version; Globals.Game.SubVersion = pakFile.Info.SubVersion; } Application.Current.Dispatcher.Invoke(delegate { MenuItems.pakFiles.Add(new PakMenuItemViewModel { PakFile = pakFile, IsEnabled = false }); }); } else { FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(paks[i])), FColors.Red, true); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", paks[i]); } } } }); }
public UObject(IoPackageReader reader, string type, bool structFallback = false) { Dict = new Dictionary <string, object>(); var header = new FUnversionedHeader(reader); if (header.HasValues) { using var it = new FIterator(header); if (header.HasNonZeroValues) { FUnversionedType unversionedType = reader.GetOrCreateSchema(type); var num = 1; do { var(val, isNonZero) = it.Current; if (unversionedType.Properties.TryGetValue(val, out var props)) { var propertyTag = new FPropertyTag(props); if (isNonZero) { var key = Dict.ContainsKey(props.Name) ? $"{props.Name}_NK{num++:00}" : props.Name; var obj = BaseProperty.ReadAsObject(reader, propertyTag, propertyTag.Type, ReadType.NORMAL); Dict[key] = obj; } else { var key = Dict.ContainsKey(props.Name) ? $"{props.Name}_NK{num++:00}" : props.Name; var obj = BaseProperty.ReadAsZeroObject(reader, propertyTag, propertyTag.Type); Dict[key] = obj; } } else { Dict[val.ToString()] = null; } } while (it.MoveNext()); } else { #if DEBUG FConsole.AppendText(string.Concat("\n", type ?? "Unknown", ": ", reader.Summary.Name.String), "#CA6C6C", true); do { FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); }while (it.MoveNext()); #endif } } if (!structFallback && reader.ReadInt32() != 0 /* && reader.Position + 16 <= maxSize*/) { reader.Position += FGuid.SIZE; } }
public static void Save(this ImageBoxViewModel vm, bool autoSave) { Application.Current.Dispatcher.Invoke(delegate { if (vm.Image != null) { if (autoSave) { string path = Properties.Settings.Default.OutputPath + "\\Icons\\" + Path.ChangeExtension(vm.Name, ".png"); using var fileStream = new FileStream(path, FileMode.Create); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(vm.Image)); encoder.Save(fileStream); if (File.Exists(path)) { DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.Name} successfully saved"); FConsole.AppendText(string.Format(Properties.Resources.SaveSuccess, Path.ChangeExtension(vm.Name, ".png")), FColors.Green, true); } } else { var saveFileDialog = new SaveFileDialog { Title = Properties.Resources.Save, FileName = Path.ChangeExtension(vm.Name, ".png"), InitialDirectory = Properties.Settings.Default.OutputPath + "\\Icons\\", Filter = Properties.Resources.PngFilter }; if ((bool)saveFileDialog.ShowDialog()) { using var fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(vm.Image)); encoder.Save(fileStream); if (File.Exists(saveFileDialog.FileName)) { DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.Name} successfully saved"); Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.ImageSaved, string.Empty, saveFileDialog.FileName); } } } } else { Globals.gNotifier.ShowCustomMessage(Properties.Resources.Error, Properties.Resources.NoImageToSave); } });
internal UDataTable(IoPackageReader reader, IReadOnlyDictionary <int, PropertyInfo> properties, string type) { var baseObj = new UObject(reader, properties, type: type); if (!baseObj.TryGetValue("RowStruct", out var rowStructProp) || !(rowStructProp is ObjectProperty rowStruct) || !rowStruct.Value.IsImport) { return; } var rowStructimportIndex = rowStruct.Value.AsImport; if (rowStructimportIndex >= reader.ImportMap.Length) { return; } var rowStructimport = reader.ImportMap[rowStructimportIndex]; if (rowStructimport.Type != EType.ScriptImport || !Globals.GlobalData.ScriptObjectByGlobalId.TryGetValue(rowStructimport, out var rowStrucDesc) || rowStrucDesc.Name.IsNone) { return; } if (!Globals.TypeMappings.TryGetValue(rowStrucDesc.Name.String, out var rowProperties)) { FConsole.AppendText($"{reader.Summary.Name.String} can't be parsed yet (RowType: {rowStrucDesc.Name.String})", FColors.Red, true); return; } var NumRows = reader.ReadInt32(); RowMap = new Dictionary <string, object>(); for (var i = 0; i < NumRows; i++) { var num = 1; var RowName = reader.ReadFName().String ?? ""; var baseName = RowName; while (RowMap.ContainsKey(RowName)) { RowName = $"{baseName}_NK{num++:00}"; } RowMap[RowName] = new UObject(reader, rowProperties, true, rowStrucDesc.Name.String); } }
public static async Task <bool> Load(bool forceReload = false) { if (Globals.Game.ActualGame == EGame.Fortnite) { Mapping[] benMappings = await MappingsData.GetData().ConfigureAwait(false); if (benMappings != null) { foreach (Mapping mapping in benMappings) { if (mapping.Meta.CompressionMethod == "Brotli") { DirectoryInfo chunksDir = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks")); string mappingPath = Path.Combine(chunksDir.FullName, mapping.FileName); byte[] mappingsData; if (!forceReload && File.Exists(mappingPath)) { mappingsData = await File.ReadAllBytesAsync(mappingPath); } else { mappingsData = await Endpoints.GetRawDataAsync(new Uri(mapping.Url)).ConfigureAwait(false); await File.WriteAllBytesAsync(mappingPath, mappingsData).ConfigureAwait(false); } FConsole.AppendText($"Mappings pulled from {mapping.FileName}", FColors.Yellow, true); Globals.Usmap = new Usmap(mappingsData); return(true); } } } var latestUsmaps = new DirectoryInfo(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks")).GetFiles("*.usmap"); if (Globals.Usmap == null && latestUsmaps.Length > 0) { var latestUsmapInfo = latestUsmaps.OrderBy(f => f.LastWriteTime).Last(); byte[] mappingsData = await File.ReadAllBytesAsync(latestUsmapInfo.FullName); FConsole.AppendText($"Mappings pulled from {latestUsmapInfo.Name}", FColors.Yellow, true); Globals.Usmap = new Usmap(mappingsData); return(true); } } return(false); }
public static void Save(this AvalonEditViewModel vm, bool autoSave) { Application.Current.Dispatcher.Invoke(delegate { if (vm.HasData()) { if (autoSave) { string path = Properties.Settings.Default.OutputPath + "\\JSONs" + vm.OwnerPath + "\\"; string file = Folders.GetUniqueFilePath(path + Path.ChangeExtension(vm.OwnerName, ".json")); Directory.CreateDirectory(path); File.WriteAllText(file, vm.Document.Text); if (File.Exists(file)) { DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.OwnerName} successfully saved"); FConsole.AppendText(string.Format(Properties.Resources.SaveSuccess, Path.GetFileName(file)), FColors.Green, true); } } else { Directory.CreateDirectory(Properties.Settings.Default.OutputPath + "\\JSONs" + vm.OwnerPath); var saveFileDialog = new SaveFileDialog { Title = Properties.Resources.Save, FileName = Path.ChangeExtension(vm.OwnerName, ".json"), InitialDirectory = Properties.Settings.Default.OutputPath + "\\JSONs" + vm.OwnerPath, Filter = Properties.Resources.JsonFilter }; if ((bool)saveFileDialog.ShowDialog()) { File.WriteAllText(saveFileDialog.FileName, vm.Document.Text); if (File.Exists(saveFileDialog.FileName)) { DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.OwnerName} successfully saved"); Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.DataSaved, string.Empty, saveFileDialog.FileName); } } } } else { Globals.gNotifier.ShowCustomMessage(Properties.Resources.Error, Properties.Resources.NoDataToSave); } }); }
public static async Task ShowGMessages() { Dictionary <string, GlobalMessage[]> globalMessages = await GetGlobalMessages().ConfigureAwait(false); if (globalMessages.Any()) { string version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); if (globalMessages.ContainsKey(version)) { if (!string.IsNullOrEmpty(globalMessages[version][0].Message)) { foreach (GlobalMessage gm in globalMessages[version]) { FConsole.AppendText(gm.Message, gm.Color, gm.NewLine); } } } } }
public UObject(IoPackageReader reader, IReadOnlyDictionary <int, PropertyInfo> properties, bool structFallback = false, string type = null) { Dict = new Dictionary <string, object>(); var header = new FUnversionedHeader(reader); using var it = new FIterator(header); #if DEBUG var headerWritten = false; do { if (properties.ContainsKey(it.Current.Val)) { continue; } if (!headerWritten) { headerWritten = true; FConsole.AppendText(string.Concat("\n", type ?? "Unknown", ": ", reader.Summary.Name.String), "#CA6C6C", true); } FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); }while (it.MoveNext()); it.Reset(); #endif var num = 1; do { var(val, isNonZero) = it.Current; if (properties.TryGetValue(val, out var propertyInfo)) { if (propertyInfo.Name == "AuthoredVFXData_ByPart" || propertyInfo.Name == "RequestedDataStores") { continue; } if (isNonZero) { var obj = BaseProperty.ReadAsObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type), ReadType.NORMAL); var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; Dict[key] = obj; } else { var obj = BaseProperty.ReadAsZeroObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type)); var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; Dict[key] = obj; } } else { Dict[val.ToString()] = null; } } while (it.MoveNext()); if (!structFallback && reader.ReadInt32() != 0 /* && reader.Position + 16 <= maxSize*/) { new FGuid(reader); } }
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(".manifest")) { ManifestInfo manifestInfo = await ManifestGrabber.TryGetLatestManifestInfo().ConfigureAwait(false); byte[] manifestData = await manifestInfo.DownloadManifestDataAsync().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 pakFileName = fileManifest.Name.Replace('/', '\\'); PakFileReader pakFile = new PakFileReader(pakFileName, fileManifest.GetStream()); 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 (Directory.Exists(Properties.Settings.Default.PakPath)) { // define the current game thank to the pak path Folders.SetGameName(Properties.Settings.Default.PakPath); string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"); for (int i = 0; i < paks.Length; i++) { if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i]))) { PakFileReader pakFile = new PakFileReader(paks[i]); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}"); if (i == 0) { 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 { FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(paks[i])), FColors.Red, true); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", paks[i]); } } } }); }
private Dictionary <string, FPakEntry> GetOldFiles(EPakLoader mode) { var diff = new Dictionary <string, FPakEntry>(); var ofd = new OpenFileDialog() { Title = Properties.Resources.SelectFile, InitialDirectory = Properties.Settings.Default.OutputPath + "\\Backups\\", Filter = Properties.Resources.FbkpFilter, Multiselect = false }; if ((bool)ofd.ShowDialog()) { string n = Path.GetFileName(ofd.FileName); StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.Analyzing, n), Properties.Resources.Processing); DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", "[Loader]", $"Backup file is {n}"); var oldFilesTemp = new Dictionary <string, FPakEntry>(); using FileStream fileStream = new FileStream(ofd.FileName, FileMode.Open); BinaryReader checkReader = new BinaryReader(fileStream); bool isLz4 = checkReader.ReadUInt32() == 0x184D2204u; fileStream.Seek(0, SeekOrigin.Begin); var target = new MemoryStream(); if (isLz4) { using LZ4DecoderStream compressionStream = LZ4Stream.Decode(fileStream); compressionStream.CopyTo(target); } else { fileStream.CopyTo(target); } using (target) { target.Position = 0; using BinaryReader reader = new BinaryReader(target); while (reader.BaseStream.Position < reader.BaseStream.Length) { // we must follow this order long offset = reader.ReadInt64(); long size = reader.ReadInt64(); long uncompressedSize = reader.ReadInt64(); bool encrypted = reader.ReadBoolean(); long structSize = reader.ReadInt32(); string name = reader.ReadString(); int compressionMethodIndex = reader.ReadInt32(); // we only need name and uncompressedSize to compare FPakEntry entry = new FPakEntry("CatsWillDominateTheWorld.pak", name, offset, size, uncompressedSize, new byte[20], null, 0, (uint)compressionMethodIndex, 0); oldFilesTemp[entry.Name] = entry; } } var newFiles = new Dictionary <string, FPakEntry>(); foreach (var fileReader in Globals.CachedPakFiles) { foreach (var files in fileReader.Value) { newFiles.Add(files.Key, files.Value); } } Paks.Merge(oldFilesTemp, out var oldFiles, string.Empty); switch (mode) { case EPakLoader.New: foreach (var kvp in newFiles) { if (!oldFiles.TryGetValue(kvp.Key, out var entry)) { diff.Add(kvp.Key, kvp.Value); } } break; case EPakLoader.Modified: foreach (var kvp in newFiles) { if (oldFiles.TryGetValue(kvp.Key, out var entry)) { if (entry.UncompressedSize != kvp.Value.UncompressedSize) { diff.Add(kvp.Key, kvp.Value); } } } break; case EPakLoader.NewModified: foreach (var kvp in newFiles) { if (oldFiles.TryGetValue(kvp.Key, out var entry)) { if (entry.UncompressedSize != kvp.Value.UncompressedSize) { diff.Add(kvp.Key, kvp.Value); } } else { diff.Add(kvp.Key, kvp.Value); } } break; } var deleted = oldFiles.Where(kvp => !newFiles.TryGetValue(kvp.Key, out var _) && kvp.Key.StartsWith("/FortniteGame/Content/Athena/Items/Cosmetics/")).ToDictionary(x => x.Key, x => x.Value); if (deleted.Count > 0) { FConsole.AppendText(Properties.Resources.RemovedRenamedCosmetics, FColors.Red, true); foreach (var kvp in deleted) { FConsole.AppendText($" - {kvp.Value.Name.Substring(1)}", FColors.LightGray, true); } } } return(diff); }
public UObject(IoPackageReader reader, IReadOnlyDictionary <int, PropertyInfo> properties, bool structFallback = false, string type = null) { Dict = new Dictionary <string, object>(); var header = new FUnversionedHeader(reader); using var it = new FIterator(header); #if DEBUG var headerWritten = false; do { if (properties.ContainsKey(it.Current.Val)) { continue; } if (!headerWritten) { headerWritten = true; FConsole.AppendText(string.Concat("\n", type ?? "Unknown", ": ", reader.Summary.Name.String), "#CA6C6C", true); } FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); }while (it.MoveNext()); it.Reset(); #endif var num = 1; do { var(val, isNonZero) = it.Current; if (properties.TryGetValue(val, out var propertyInfo)) { if (isNonZero) { var obj = BaseProperty.ReadAsObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type), ReadType.NORMAL); var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; Dict[key] = obj; } else { var obj = BaseProperty.ReadAsZeroObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type)); var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; Dict[key] = obj; } } else { Dict[val.ToString()] = null; if (!isNonZero) { // We are lucky: We don't know this property but it also has no content DebugHelper.WriteLine($"{type ?? "Unknown"}: Unknown property for {GetType().Name} with value {val} but it's zero so we are good"); } else { DebugHelper.WriteLine($"{type ?? "Unknown"}: Unknown property for {GetType().Name} with value {val}. Can't proceed serialization (Serialized {Dict.Count} properties till now)"); //throw new FileLoadException($"Unknown property for {GetType().Name} with value {val}. Can't proceed serialization"); } } } while (it.MoveNext()); if (!structFallback && reader.ReadInt32() != 0 /* && reader.Position + 16 <= maxSize*/) { new FGuid(reader); } }
public static async Task PopulateMenu() { await Application.Current.Dispatcher.InvokeAsync(delegate { 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://epicgames-download1.akamaized.net/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 }); }); } } FConsole.AppendText($"Fortnite-Manifest version: {manifest.Version}-{manifest.CL}", FColors.Yellow, true); } else if (Properties.Settings.Default.PakPath.EndsWith("-val.manifest")) { //var manifest = await ValorantAPIManifestV1.DownloadAndParse(Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))).ConfigureAwait(false); var manifest = await ValorantAPIManifestV2.DownloadAndParse(Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))).ConfigureAwait(false); if (manifest == null) { throw new Exception("Failed to load latest manifest."); } for (var i = 0; i < manifest.Paks.Length; i++) { var pak = manifest.Paks[i]; var pakFileName = @$ "ShooterGame\Content\Paks\{pak.Name}"; var pakFile = new PakFileReader(pakFileName, manifest.GetPakStream(i)); if (i == 0) { Folders.SetGame(EGame.Valorant); 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 }); }); } FConsole.AppendText($"Valorant-Manifest version: {manifest.Header.GameVersion ?? "Unknown"}", FColors.Yellow, true); }