From afd159eb031447c6c6125c1bc208c5508b4a5b00 Mon Sep 17 00:00:00 2001 From: Masusder <59669685+Masusder@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:52:55 +0200 Subject: [PATCH 1/7] More NFS fixes, Morph targets fix, Textures RGB fix Co-Authored-By: LongerWarrior <37636768+LongerWarrior@users.noreply.github.com> Co-Authored-By: MountainFlash <65584814+MinshuG@users.noreply.github.com> --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index c43d6707..8c8eb235 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit c43d6707cbde0305e2970d7c527e2ccd26f393c7 +Subproject commit 8c8eb2358e0d9c1b9dd9dfeed93d72ded87fce35 From c1a241af96baac476a7f30e2ba163f514f2bfc93 Mon Sep 17 00:00:00 2001 From: LongerWarrior Date: Wed, 1 Jul 2026 00:41:59 +0300 Subject: [PATCH 2/7] Lord of Mysteries initial support Wwise, Kismet, Shaders fixes --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 4 ++-- FModel/Views/SettingsView.xaml.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 8c8eb235..f90db397 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 8c8eb2358e0d9c1b9dd9dfeed93d72ded87fce35 +Subproject commit f90db3974debc3cd1253fd03c91d01a2ef1be72c diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index caf7527a..34874f13 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -1237,7 +1237,7 @@ public class CUE4ParseViewModel : ViewModel { if (!TabControl.CanAddTabs) return false; - TabControl.AddTab($"{verseDigest.ProjectName}.verse"); + TabControl.AddTab($"{verseDigest.Name}.verse"); TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("verse"); TabControl.SelectedTab.SetDocumentText(verseDigest.ReadableCode, false, false); return true; @@ -1621,7 +1621,7 @@ public class CUE4ParseViewModel : ViewModel if (dummy is not UClass || pointer.Object.Value is not UClass blueprint) continue; - cppList.Add(blueprint.DecompileBlueprintToPseudo(pkg.Mappings, cookedMetaData)); + cppList.Add(blueprint.DecompileBlueprintToPseudo(cookedMetaData)); } if (cppList.Count == 0) return false; diff --git a/FModel/Views/SettingsView.xaml.cs b/FModel/Views/SettingsView.xaml.cs index 7a4f8bf1..a076f3be 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -121,7 +121,7 @@ public partial class SettingsView { Title = "Select a mapping file", InitialDirectory = Path.Combine(UserSettings.Default.OutputDirectory, ".data"), - Filter = "USMAP Files (*.usmap)|*.usmap|All Files (*.*)|*.*" + Filter = "USMAP Files (*.usmap, *.jmap, *.jmap.gz)|*.usmap;*.jmap;*.jmap.gz|All Files (*.*)|*.*" }; if (!openFileDialog.ShowDialog().GetValueOrDefault()) From a1d5f72047157589e1a6e0668fccdd919de2f947 Mon Sep 17 00:00:00 2001 From: Masusder <59669685+Masusder@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:22:26 +0200 Subject: [PATCH 3/7] Mortal Kombat 1 and eFootbal support, Ark Survival Ascended meshes fix Ni no Kuni: Cross Worlds data decryption, PUBG update, and other fixes --- CUE4Parse | 2 +- FModel/ViewModels/GameFileViewModel.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index f90db397..c7e78422 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit f90db3974debc3cd1253fd03c91d01a2ef1be72c +Subproject commit c7e78422ec4858036c9bba5d9d3c55eb197f93c9 diff --git a/FModel/ViewModels/GameFileViewModel.cs b/FModel/ViewModels/GameFileViewModel.cs index 6bac2c92..ea33dac9 100644 --- a/FModel/ViewModels/GameFileViewModel.cs +++ b/FModel/ViewModels/GameFileViewModel.cs @@ -366,6 +366,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel case "stinfo": case "ushaderbytecode": case "upipelinecache": + case "dxbc": AssetCategory = EAssetCategory.ByteCode; break; case "wav": From d407377696467606ecb893b40d04d962c3e81bb6 Mon Sep 17 00:00:00 2001 From: LongerWarrior Date: Sat, 11 Jul 2026 01:00:56 +0300 Subject: [PATCH 4/7] Lord of Mysteries, Arena Breakout Mobile, Silver Palace support --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index c7e78422..594451f4 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit c7e78422ec4858036c9bba5d9d3c55eb197f93c9 +Subproject commit 594451f48dd16f35a1d1f1b8d27372e1c917ea73 diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 34874f13..1c05422e 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -65,6 +65,7 @@ using CUE4Parse.UE4.Wwise; using CUE4Parse.Utils; using CUE4Parse_Conversion; using CUE4Parse_Conversion.Sounds; +using CUE4Parse.GameTypes.LordOfMysteries.FileProvider; using CUE4Parse.MappingsProvider.Jmap; using CUE4Parse.MappingsProvider.Usmap; using EpicManifestParser; @@ -208,6 +209,7 @@ public class CUE4ParseViewModel : ViewModel _ when versionContainer.Game is EGame.GAME_AshEchoes => new AEDefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer), _ when versionContainer.Game is EGame.GAME_BlackStigma => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, StringComparer.Ordinal), _ when versionContainer.Game is EGame.GAME_HonorofKingsWorld => new HoKWDefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer), + _ when versionContainer.Game is EGame.GAME_LordOfMysteries => new LoMDefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer), _ => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer) }; From c5e6900bb4a8eb0bd4b2dd749cbda270ab7b6b39 Mon Sep 17 00:00:00 2001 From: Masusder <59669685+Masusder@users.noreply.github.com> Date: Tue, 14 Jul 2026 16:29:02 +0200 Subject: [PATCH 5/7] Valorant: Source (Valorant mobile) and Palworld support Co-Authored-By: LongerWarrior <37636768+LongerWarrior@users.noreply.github.com> --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 594451f4..d5dac24c 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 594451f48dd16f35a1d1f1b8d27372e1c917ea73 +Subproject commit d5dac24c9179b41d79d4da56b243baad2154a127 From 9868ff86fd8afeb6ee8d90788742cf2bd1269ce3 Mon Sep 17 00:00:00 2001 From: Marlon Date: Thu, 16 Jul 2026 12:25:13 +0200 Subject: [PATCH 6/7] bump cue4parse --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index d5dac24c..396ede2a 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit d5dac24c9179b41d79d4da56b243baad2154a127 +Subproject commit 396ede2a1d89752142c3b73dba7c908467ccf3a3 From 3d07a51d6d2cd3c5f1d00076f95a5a880f9dc475 Mon Sep 17 00:00:00 2001 From: Marlon Date: Thu, 16 Jul 2026 12:26:59 +0200 Subject: [PATCH 7/7] Fix live loading and organize cached output --- FModel/App.xaml.cs | 3 +- FModel/Framework/CacheManager.cs | 106 ++++++++++++++++++ .../ApiEndpoints/ValorantApiEndpoint.cs | 4 +- FModel/ViewModels/AssetsFolderViewModel.cs | 5 +- FModel/ViewModels/CUE4ParseViewModel.cs | 54 ++++++--- FModel/ViewModels/Commands/LoadCommand.cs | 79 ++++++------- FModel/Views/SettingsView.xaml.cs | 2 +- 7 files changed, 193 insertions(+), 60 deletions(-) create mode 100644 FModel/Framework/CacheManager.cs diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 31da19b9..36a1b8c1 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -108,7 +108,7 @@ public partial class App Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Backups")); if (createMe) Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Exports")); Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Logs")); - Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")); + CacheManager.EnsureDirectories(); const string template = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Enriched}: {Message:lj}{NewLine}{Exception}"; Log.Logger = new LoggerConfiguration() @@ -125,6 +125,7 @@ public partial class App #endif .CreateLogger(); + CacheManager.MigrateLegacyFiles(); Log.Information("Version {Version} ({CommitId})", Constants.APP_VERSION, Constants.APP_COMMIT_ID); Log.Information("{OS}", GetOperatingSystemProductName()); Log.Information("{RuntimeVer}", RuntimeInformation.FrameworkDescription); diff --git a/FModel/Framework/CacheManager.cs b/FModel/Framework/CacheManager.cs new file mode 100644 index 00000000..55b55478 --- /dev/null +++ b/FModel/Framework/CacheManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.IO; +using FModel.Settings; +using Serilog; + +namespace FModel.Framework; + +public static class CacheManager +{ + public static string DataDirectory => + Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")).FullName; + + public static string ChunksDirectory => + Directory.CreateDirectory(Path.Combine(DataDirectory, "chunks")).FullName; + + public static string ManifestsDirectory => + Directory.CreateDirectory(Path.Combine(DataDirectory, "manifests")).FullName; + + public static string MappingsDirectory => + Directory.CreateDirectory(Path.Combine(DataDirectory, "mappings")).FullName; + + public static void EnsureDirectories() + { + _ = ChunksDirectory; + _ = ManifestsDirectory; + _ = MappingsDirectory; + } + + public static void MigrateLegacyFiles() + { + EnsureDirectories(); + + var movedFiles = 0; + var skippedFiles = 0; + var sources = new HashSet(StringComparer.OrdinalIgnoreCase) + { + Path.GetFullPath(UserSettings.Default.OutputDirectory), + Path.GetFullPath(DataDirectory) + }; + + foreach (var sourceDirectory in sources) + { + foreach (var file in new DirectoryInfo(sourceDirectory).EnumerateFiles("*", SearchOption.TopDirectoryOnly)) + { + var destinationDirectory = GetDestinationDirectory(file.Name); + if (destinationDirectory is null) continue; + + var destinationPath = Path.Combine(destinationDirectory, file.Name); + if (File.Exists(destinationPath)) + { + skippedFiles++; + continue; + } + + try + { + File.Move(file.FullName, destinationPath); + UpdateMappingEndpointPath(file.FullName, destinationPath); + movedFiles++; + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Log.Warning(e, "Could not migrate cache file '{CacheFile}'", file.FullName); + } + } + } + + if (movedFiles > 0) + Log.Information("Migrated {CacheFileCount} cached file(s) into dedicated cache directories", movedFiles); + if (skippedFiles > 0) + Log.Warning("Skipped {CacheFileCount} cache migration(s) because the destination file already exists", skippedFiles); + } + + private static string GetDestinationDirectory(string fileName) + { + if (fileName.EndsWith(".jmap.gz", StringComparison.OrdinalIgnoreCase)) + return MappingsDirectory; + + return Path.GetExtension(fileName).ToLowerInvariant() switch + { + ".chunk" or ".iochunk" or ".iopart" or ".utoc" => ChunksDirectory, + ".manifest" => ManifestsDirectory, + ".usmap" or ".jmap" => MappingsDirectory, + _ => null + }; + } + + private static void UpdateMappingEndpointPath(string oldPath, string newPath) + { + if (!newPath.StartsWith(MappingsDirectory, StringComparison.OrdinalIgnoreCase)) return; + + if (UserSettings.Default.PerDirectory is null) return; + + foreach (var directorySettings in UserSettings.Default.PerDirectory.Values) + { + if (directorySettings.Endpoints is null) continue; + + foreach (var endpoint in directorySettings.Endpoints) + { + if (endpoint is not null && string.Equals(endpoint.FilePath, oldPath, StringComparison.OrdinalIgnoreCase)) + endpoint.FilePath = newPath; + } + } + } +} diff --git a/FModel/ViewModels/ApiEndpoints/ValorantApiEndpoint.cs b/FModel/ViewModels/ApiEndpoints/ValorantApiEndpoint.cs index 2a450517..7cc15660 100644 --- a/FModel/ViewModels/ApiEndpoints/ValorantApiEndpoint.cs +++ b/FModel/ViewModels/ApiEndpoints/ValorantApiEndpoint.cs @@ -78,7 +78,7 @@ public class VManifest public async ValueTask PrefetchChunk(VChunk chunk, CancellationToken cancellationToken) { - var chunkPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", $"{chunk.Id}.chunk"); + var chunkPath = Path.Combine(CacheManager.ChunksDirectory, $"{chunk.Id}.chunk"); if (File.Exists(chunkPath)) return; using var response = await _client.GetAsync(chunk.GetUrl(), cancellationToken).ConfigureAwait(false); @@ -91,7 +91,7 @@ public class VManifest public async Task GetChunkBytes(VChunk chunk, CancellationToken cancellationToken) { - var chunkPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", $"{chunk.Id}.chunk"); + var chunkPath = Path.Combine(CacheManager.ChunksDirectory, $"{chunk.Id}.chunk"); byte[] chunkBytes; if (File.Exists(chunkPath)) diff --git a/FModel/ViewModels/AssetsFolderViewModel.cs b/FModel/ViewModels/AssetsFolderViewModel.cs index c76b0ad3..70f6eeaf 100644 --- a/FModel/ViewModels/AssetsFolderViewModel.cs +++ b/FModel/ViewModels/AssetsFolderViewModel.cs @@ -288,13 +288,16 @@ public class AssetsFolderViewModel lastNode?.AssetsList.Add(entry); } + Folders.AddRange(treeItems); + if (treeItems.Count > 0) { + // Select after publishing the collection. Selecting a detached TreeItem lets WPF + // auto-select the first root (usually the synthetic "Content" bucket) instead. var projectName = ApplicationService.ApplicationView.CUE4Parse.Provider.ProjectName; (treeItems.FirstOrDefault(x => x.Header.Equals(projectName, StringComparison.OrdinalIgnoreCase)) ?? treeItems[0]).IsSelected = true; } - Folders.AddRange(treeItems); ApplicationService.ApplicationView.CUE4Parse.SearchVm.ChangeCollection(entries); foreach (var folder in Folders) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 1c05422e..364033c0 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -236,7 +236,7 @@ public class CUE4ParseViewModel : ViewModel Provider.OnDemandOptions = new IoStoreOnDemandOptions { ChunkHostUri = new Uri("https://egdownload.fastly-edge.com/", UriKind.Absolute), - ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")), + ChunkCacheDirectory = new DirectoryInfo(CacheManager.ChunksDirectory), DownloaderClient = _chunkClient }; @@ -253,11 +253,10 @@ public class CUE4ParseViewModel : ViewModel throw new FileLoadException("Could not load latest Fortnite manifest, you may have to switch to your local installation."); } - var cacheDir = Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data")).FullName; var manifestOptions = new ManifestParseOptions { - ChunkCacheDirectory = cacheDir, - ManifestCacheDirectory = cacheDir, + ChunkCacheDirectory = CacheManager.ChunksDirectory, + ManifestCacheDirectory = CacheManager.ManifestsDirectory, ChunkBaseUrl = "https://egdownload.fastly-edge.com/Builds/Fortnite/CloudDir/", Decompressor = Compression.Decompressor, Client = _chunkClient, @@ -285,25 +284,16 @@ public class CUE4ParseViewModel : ViewModel IoStoreOnDemand.Read(new StreamReader(ioStoreOnDemandFile.GetStream())); } - Parallel.ForEach(manifest.Files.Where(x => _fnLiveRegex.IsMatch(x.FileName)), fileManifest => - { - p.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()], - it => new FRandomAccessStreamArchive(it, manifest.FindFile(it)!.GetStream(), p.Versions)); - }); + RegisterFortniteLiveArchives(p, manifest, cancellationToken); var manifests = _apiEndpointView.DillyApi.GetManifests(cancellationToken); var downloadUrl = manifests.First(x => x.AppName == "Fortnite_Studio").DownloadUrl; - using var client = new HttpClient(); - var manifestBytes = client.GetByteArrayAsync(downloadUrl).GetAwaiter().GetResult(); + var manifestBytes = _chunkClient.GetByteArrayAsync(downloadUrl, cancellationToken).GetAwaiter().GetResult(); var uefnManifest = FBuildPatchAppManifest.Deserialize(manifestBytes, manifestOptions); - Parallel.ForEach(uefnManifest.Files.Where(x => _fnLiveRegex.IsMatch(x.FileName)), fileManifest => - { - p.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()], - it => new FRandomAccessStreamArchive(it, uefnManifest.FindFile(it)!.GetStream(), p.Versions)); - }); + RegisterFortniteLiveArchives(p, uefnManifest, cancellationToken); var elapsedTime = Stopwatch.GetElapsedTime(startTs); FLogger.Append(ELog.Information, () => @@ -351,6 +341,36 @@ public class CUE4ParseViewModel : ViewModel }); } + private void RegisterFortniteLiveArchives(StreamedFileProvider provider, FBuildPatchAppManifest manifest, + CancellationToken cancellationToken) + { + var archiveFiles = manifest.Files.Where(x => + _fnLiveRegex.IsMatch(x.FileName) && + (x.FileName.EndsWith(".pak", StringComparison.OrdinalIgnoreCase) || + x.FileName.EndsWith(".utoc", StringComparison.OrdinalIgnoreCase) || + x.FileName.EndsWith(".uondemandtoc", StringComparison.OrdinalIgnoreCase))).ToList(); + var parallelOptions = new ParallelOptions { CancellationToken = cancellationToken }; + + Parallel.ForEach(archiveFiles.Where(x => !x.FileName.EndsWith(".uondemandtoc", StringComparison.OrdinalIgnoreCase)), + parallelOptions, fileManifest => + { + provider.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()], + it => new FRandomAccessStreamArchive(it, manifest.FindFile(it)!.GetStream(), provider.Versions)); + }); + + // V2 on-demand TOCs are large and span many BuildPatch chunks. Reading them through CUE4Parse's synchronous + // archive interface downloads those chunks one at a time. Materialize each TOC through EpicManifestParser's + // parallel path first, then register it normally so the on-demand containers remain available. + foreach (var fileManifest in archiveFiles.Where(x => x.FileName.EndsWith(".uondemandtoc", StringComparison.OrdinalIgnoreCase))) + { + cancellationToken.ThrowIfCancellationRequested(); + using var stream = fileManifest.GetStream(); + var data = stream.SaveBytesAsync(8, cancellationToken).GetAwaiter().GetResult(); + using var archive = new FByteArchive(fileManifest.FileName, data, provider.Versions); + provider.RegisterVfs(new IoChunkToc(archive)); + } + } + /// /// load virtual files system from GameDirectory /// @@ -447,7 +467,7 @@ public class CUE4ParseViewModel : ViewModel endpoint.Path = "$.mappings.ZStandard"; } - var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data"); + var mappingsFolder = CacheManager.MappingsDirectory; var mappings = _apiEndpointView.DynamicApi.GetMappings(CancellationToken.None, endpoint.Url, endpoint.Path); if (mappings is { Length: > 0 }) { diff --git a/FModel/ViewModels/Commands/LoadCommand.cs b/FModel/ViewModels/Commands/LoadCommand.cs index f476ea24..c29a695e 100644 --- a/FModel/ViewModels/Commands/LoadCommand.cs +++ b/FModel/ViewModels/Commands/LoadCommand.cs @@ -59,50 +59,53 @@ public class LoadCommand : ViewModelCommand _applicationView.IsAssetsExplorerVisible = true; Helper.CloseWindow("Search For Packages"); // close search window if opened - await Task.WhenAll( - _applicationView.CUE4Parse.LoadLocalizedResources(), // load locres if not already loaded, - _applicationView.CUE4Parse.LoadVirtualPaths(), // load virtual paths if not already loaded - _threadWorkerView.Begin(cancellationToken => + // Populate the package tree before doing supplemental reads. For streamed providers those + // reads may download BuildPatch chunks and must not delay or hide an otherwise valid tree. + await _threadWorkerView.Begin(cancellationToken => + { + // filter what to show + _applicationView.Status.UpdateStatusLabel("Packages", "Filtering"); + switch (UserSettings.Default.LoadingMode) { - // filter what to show - _applicationView.Status.UpdateStatusLabel("Packages", "Filtering"); - switch (UserSettings.Default.LoadingMode) + case ELoadingMode.Multiple: { - case ELoadingMode.Multiple: + var l = (IList) parameter; + if (l.Count == 0) { - var l = (IList) parameter; - if (l.Count == 0) - { - UserSettings.Default.LoadingMode = ELoadingMode.All; - goto case ELoadingMode.All; - } + UserSettings.Default.LoadingMode = ELoadingMode.All; + goto case ELoadingMode.All; + } - var directoryFilesToShow = l.Cast(); - FilterDirectoryFilesToDisplay(cancellationToken, directoryFilesToShow); - break; - } - case ELoadingMode.All: - { - FilterDirectoryFilesToDisplay(cancellationToken, null); - break; - } - case ELoadingMode.AllButNew: - case ELoadingMode.AllButModified: - { - FilterNewOrModifiedFilesToDisplay(cancellationToken); - break; - } - case ELoadingMode.AllButPatched: - { - FilterPacthedFilesToDisplay(cancellationToken); - break; - } - default: throw new ArgumentOutOfRangeException(); + var directoryFilesToShow = l.Cast(); + FilterDirectoryFilesToDisplay(cancellationToken, directoryFilesToShow); + break; } + case ELoadingMode.All: + { + FilterDirectoryFilesToDisplay(cancellationToken, null); + break; + } + case ELoadingMode.AllButNew: + case ELoadingMode.AllButModified: + { + FilterNewOrModifiedFilesToDisplay(cancellationToken); + break; + } + case ELoadingMode.AllButPatched: + { + FilterPacthedFilesToDisplay(cancellationToken); + break; + } + default: throw new ArgumentOutOfRangeException(); + } - _discordHandler.UpdatePresence(_applicationView.CUE4Parse); - }) - ).ConfigureAwait(false); + _discordHandler.UpdatePresence(_applicationView.CUE4Parse); + }).ConfigureAwait(false); + + // These enrich later package reads but are not required to display the archive contents. + // Run them sequentially to avoid competing BuildPatch download bursts on Fortnite Live. + await _applicationView.CUE4Parse.LoadVirtualPaths().ConfigureAwait(false); + await _applicationView.CUE4Parse.LoadLocalizedResources().ConfigureAwait(false); #if DEBUG loadingTime.Stop(); FLogger.Append(ELog.Debug, () => diff --git a/FModel/Views/SettingsView.xaml.cs b/FModel/Views/SettingsView.xaml.cs index a076f3be..015729b5 100644 --- a/FModel/Views/SettingsView.xaml.cs +++ b/FModel/Views/SettingsView.xaml.cs @@ -120,7 +120,7 @@ public partial class SettingsView var openFileDialog = new OpenFileDialog { Title = "Select a mapping file", - InitialDirectory = Path.Combine(UserSettings.Default.OutputDirectory, ".data"), + InitialDirectory = CacheManager.MappingsDirectory, Filter = "USMAP Files (*.usmap, *.jmap, *.jmap.gz)|*.usmap;*.jmap;*.jmap.gz|All Files (*.*)|*.*" };