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));