From 71468dca231a5c327ff9f752db18ca179205926a Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 9 Feb 2025 00:41:47 +0100 Subject: [PATCH] poc pagination for large packages --- CUE4Parse | 2 +- FModel/Extensions/CUE4ParseExtensions.cs | 46 ++++++++++++++++++++++++ FModel/MainWindow.xaml.cs | 6 ++-- FModel/ViewModels/CUE4ParseViewModel.cs | 22 +++++++----- 4 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 FModel/Extensions/CUE4ParseExtensions.cs diff --git a/CUE4Parse b/CUE4Parse index 11a92870..699dbd44 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 11a92870024a088888aae79c74d8ae0c6c8af3e5 +Subproject commit 699dbd44389e3543e7c09875e0a1b518b0dd05da diff --git a/FModel/Extensions/CUE4ParseExtensions.cs b/FModel/Extensions/CUE4ParseExtensions.cs new file mode 100644 index 00000000..7254564e --- /dev/null +++ b/FModel/Extensions/CUE4ParseExtensions.cs @@ -0,0 +1,46 @@ +using System; +using CUE4Parse.FileProvider; +using CUE4Parse.FileProvider.Objects; +using CUE4Parse.UE4.Assets; + +namespace FModel.Extensions; + +public static class CUE4ParseExtensions +{ + public class LoadPackageResult + { + private const int PaginationThreshold = 5000; + private const int MaxExportPerPage = 1; + + public IPackage Package; + public bool IsPaginated => Package.ExportMapLength >= PaginationThreshold; + + public int InclusiveStart; + public int ExclusiveEnd => IsPaginated + ? Math.Min(InclusiveStart + MaxExportPerPage, Package.ExportMapLength) + : Package.ExportMapLength; + + private int CurrentPage => (InclusiveStart + 1) / MaxExportPerPage; + private int LastPage => Math.Max(1, (Package.ExportMapLength + MaxExportPerPage - 1) / MaxExportPerPage); + private int PageSize => ExclusiveEnd - InclusiveStart; + + public string TabTitleExtra => IsPaginated ? $"Page {CurrentPage}/{LastPage}" : null; + + public object GetDisplayData(bool save = false) => !save ? Package.GetExports(InclusiveStart, PageSize) : Package.GetExports(); + } + + public static LoadPackageResult GetLoadPackageResult(this IFileProvider provider, GameFile file, string objectName = null) + { + var result = new LoadPackageResult { Package = provider.LoadPackage(file) }; + if (result.IsPaginated) + { + result.InclusiveStart = result.Package.GetExportIndex(file.NameWithoutExtension); + if (objectName != null) + { + result.InclusiveStart = int.TryParse(objectName, out var index) ? index : result.Package.GetExportIndex(objectName); + } + } + + return result; + } +} diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index b4200026..23cdc2d2 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -83,9 +83,9 @@ public partial class MainWindow ).ConfigureAwait(false); #if DEBUG - // await _threadWorkerView.Begin(cancellationToken => - // _applicationView.CUE4Parse.Extract(cancellationToken, - // "Marvel/Content/Marvel/Characters/1016/1016501/Meshes/SK_1016_1016501.uasset")); + await _threadWorkerView.Begin(cancellationToken => + _applicationView.CUE4Parse.Extract(cancellationToken, + _applicationView.CUE4Parse.Provider["FortniteGame/Plugins/GameFeatures/BRMapCh6/Content/Maps/Hermes_Terrain.umap"])); // await _threadWorkerView.Begin(cancellationToken => // _applicationView.CUE4Parse.Extract(cancellationToken, // "RED/Content/Chara/ABA/Costume01/Animation/Charaselect/body/stand_body01.uasset")); diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 63a66d55..eed30718 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -571,16 +571,18 @@ public class CUE4ParseViewModel : ViewModel case "uasset": case "umap": { - var pkg = Provider.LoadPackage(entry); + var result = Provider.GetLoadPackageResult(entry); + TabControl.SelectedTab.TitleExtra = result.TabTitleExtra; + if (saveProperties || updateUi) { - TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), saveProperties, updateUi); + TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(result.GetDisplayData(saveProperties), Formatting.Indented), saveProperties, updateUi); if (saveProperties) break; // do not search for viewable exports if we are dealing with jsons } - for (var i = 0; i < pkg.ExportMapLength; i++) + for (var i = result.InclusiveStart; i < result.ExclusiveEnd; i++) { - if (CheckExport(cancellationToken, pkg, i, bulk)) + if (CheckExport(cancellationToken, result.Package, i, bulk)) break; } @@ -743,13 +745,15 @@ public class CUE4ParseViewModel : ViewModel TabControl.AddTab(entry, parentExportType); TabControl.SelectedTab.ScrollTrigger = objectName; - var pkg = Provider.LoadPackage(entry); - TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); // json - TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), false, false); + var result = Provider.GetLoadPackageResult(entry, objectName); - for (var i = 0; i < pkg.ExportMapLength; i++) + TabControl.SelectedTab.TitleExtra = result.TabTitleExtra; + TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); // json + TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(result.GetDisplayData(), Formatting.Indented), false, false); + + for (var i = result.InclusiveStart; i < result.ExclusiveEnd; i++) { - if (CheckExport(cancellationToken, pkg, i)) + if (CheckExport(cancellationToken, result.Package, i)) break; } }