From b88109ba09b99fb72563870bb5e1f4eebcafb4ee Mon Sep 17 00:00:00 2001 From: Krowe Moh <27891447+Krowe-moh@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:44:29 +1000 Subject: [PATCH 1/2] Added "Cloud" Archives --- FModel/MainWindow.xaml.cs | 1 + .../ApiEndpoints/Models/FModelResponse.cs | 5 ++ FModel/ViewModels/CUE4ParseViewModel.cs | 59 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index fbed15d4..b9b79b37 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -116,6 +116,7 @@ public partial class MainWindow await Task.WhenAll( _applicationView.CUE4Parse.VerifyConsoleVariables(), _applicationView.CUE4Parse.VerifyOnDemandArchives(), + _applicationView.CUE4Parse.VerifyCloudArchives(), _applicationView.CUE4Parse.InitMappings(), ApplicationViewModel.InitDetex(), ApplicationViewModel.InitVgmStream(), diff --git a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs index 598f070c..d9fd084f 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/FModelResponse.cs @@ -30,6 +30,11 @@ public class ManifestInfoDilly [J] public string DownloadUrl { get; private set; } } +public class CloudContent +{ + public string ManifestPath { get; private set; } +} + public class Donator { [J] public string Username { get; private set; } diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 07772cc3..f7155852 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -75,6 +75,7 @@ using FModel.Extensions; using FModel.Framework; using FModel.Services; using FModel.Settings; +using FModel.ViewModels.ApiEndpoints.Models; using FModel.Views; using FModel.Views.Resources.Controls; using FModel.Views.Snooper; @@ -88,6 +89,7 @@ using Svg.Skia; using UE4Config.Parsing; using Application = System.Windows.Application; using FGuid = CUE4Parse.UE4.Objects.Core.Misc.FGuid; +using Version = System.Version; namespace FModel.ViewModels; @@ -372,6 +374,22 @@ public class CUE4ParseViewModel : ViewModel } } + private void RegisterArchivesFromManifest(DefaultFileProvider provider, FBuildPatchAppManifest manifest) + { + 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(); + + Parallel.ForEach(archiveFiles.Where(x => !x.FileName.EndsWith(".uondemandtoc", StringComparison.OrdinalIgnoreCase)), fileManifest => + { + provider.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()], + it => new FRandomAccessStreamArchive(it, manifest.FindFile(it)!.GetStream(), provider.Versions)); + }); + } + + /// /// load virtual files system from GameDirectory /// @@ -551,6 +569,47 @@ public class CUE4ParseViewModel : ViewModel }); } + public Task VerifyCloudArchives() + { + if (Provider is not DefaultFileProvider p || !Provider.ProjectName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase)) + return Task.CompletedTask; + + var cloudContentPath = Path.Combine(UserSettings.Default.GameDirectory, "..\\..\\..\\Cloud\\cloudcontent.json"); + if (!File.Exists(cloudContentPath)) + return Task.CompletedTask; + + return Task.Run(async () => + { + var startTs = Stopwatch.GetTimestamp(); + + var cloudContent = JsonConvert.DeserializeObject(await File.ReadAllTextAsync(cloudContentPath)); + if (cloudContent is null || string.IsNullOrEmpty(cloudContent.ManifestPath)) + return; + + var manifestBytes = await _chunkClient.GetByteArrayAsync("https://egdownload.fastly-edge.com/" + cloudContent.ManifestPath); + + var manifestOptions = new ManifestParseOptions + { + ChunkCacheDirectory = CacheManager.ChunksDirectory, + ManifestCacheDirectory = CacheManager.ManifestsDirectory, + ChunkBaseUrl = "https://egdownload.fastly-edge.com/Builds/Fortnite/CloudDir/", + Decompressor = Compression.Decompressor, + Client = _chunkClient, + CacheChunksAsIs = false + }; + + var contentManifest = FBuildPatchAppManifest.Deserialize(manifestBytes, manifestOptions); + + RegisterArchivesFromManifest(p, contentManifest); + + var cloudCount = await Provider.MountAsync(); + var elapsedTime = Stopwatch.GetElapsedTime(startTs); + + FLogger.Append(ELog.Information, () => + FLogger.Text($"{cloudCount} cloud archive{(cloudCount > 1 ? "s" : "")} streamed via epicgames.com in {elapsedTime.TotalMilliseconds:F1}ms", Constants.WHITE, true)); + }); + } + public int LocalizedResourcesCount { get; set; } public bool LocalResourcesDone { get; set; } public bool HotfixedResourcesDone { get; set; } From c1c578a818ee139cec0f4ad7ed39ff9e911d1a04 Mon Sep 17 00:00:00 2001 From: Krowe Moh <27891447+Krowe-moh@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:45:39 +1000 Subject: [PATCH 2/2] useless check --- FModel/ViewModels/CUE4ParseViewModel.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index f7155852..7b22009d 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -379,10 +379,9 @@ public class CUE4ParseViewModel : ViewModel 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(); + x.FileName.EndsWith(".utoc", StringComparison.OrdinalIgnoreCase))).ToList(); - Parallel.ForEach(archiveFiles.Where(x => !x.FileName.EndsWith(".uondemandtoc", StringComparison.OrdinalIgnoreCase)), fileManifest => + Parallel.ForEach(archiveFiles, fileManifest => { provider.RegisterVfs(fileManifest.FileName, [fileManifest.GetStream()], it => new FRandomAccessStreamArchive(it, manifest.FindFile(it)!.GetStream(), provider.Versions));