mirror of
https://github.com/4sval/FModel.git
synced 2026-08-06 03:03:04 -05:00
Optimize archive mounting startup
This commit is contained in:
parent
990c38bbcb
commit
0b507d94f8
|
|
@ -1 +1 @@
|
|||
Subproject commit cd9fa6d9c7f521370e40045d9515e982fc486bc0
|
||||
Subproject commit 25d982ecf40620038525ebd7adbd07ed644df2fe
|
||||
|
|
@ -109,6 +109,14 @@ public partial class MainWindow
|
|||
ApplicationViewModel.InitZlib()
|
||||
);
|
||||
|
||||
var auxiliaryInitialization = Task.WhenAll(
|
||||
_applicationView.CUE4Parse.InitMappings(),
|
||||
ApplicationViewModel.InitDetex(),
|
||||
ApplicationViewModel.InitVgmStream(),
|
||||
ApplicationViewModel.InitImGuiSettings(newOrUpdated),
|
||||
UserSettings.Default.DecompileLua ? ApplicationViewModel.InitUnluac() : Task.CompletedTask
|
||||
);
|
||||
|
||||
await _applicationView.CUE4Parse.Initialize();
|
||||
await _applicationView.AesManager.InitAes();
|
||||
await _applicationView.UpdateProvider(true);
|
||||
|
|
@ -119,16 +127,12 @@ public partial class MainWindow
|
|||
await Task.WhenAll(
|
||||
_applicationView.CUE4Parse.VerifyConsoleVariables(),
|
||||
_applicationView.CUE4Parse.VerifyOnDemandArchives(),
|
||||
_applicationView.CUE4Parse.InitMappings(),
|
||||
ApplicationViewModel.InitDetex(),
|
||||
ApplicationViewModel.InitVgmStream(),
|
||||
ApplicationViewModel.InitImGuiSettings(newOrUpdated),
|
||||
auxiliaryInitialization,
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (UserSettings.Default.DiscordRpc == EDiscordRpc.Always)
|
||||
_discordHandler.Initialize(_applicationView.GameDisplayName);
|
||||
}),
|
||||
UserSettings.Default.DecompileLua ? ApplicationViewModel.InitUnluac() : Task.CompletedTask
|
||||
})
|
||||
).ConfigureAwait(false);
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.IO.Compression;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using CUE4Parse_Conversion.Textures.BC;
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.Encryption.Aes;
|
||||
|
|
@ -27,6 +28,10 @@ namespace FModel.ViewModels;
|
|||
|
||||
public class ApplicationViewModel : ViewModel
|
||||
{
|
||||
private readonly object _providerStatusLock = new();
|
||||
private (string Label, string Prefix)? _pendingProviderStatus;
|
||||
private bool _providerStatusScheduled;
|
||||
|
||||
private EBuildKind _build;
|
||||
public EBuildKind Build
|
||||
{
|
||||
|
|
@ -115,13 +120,13 @@ public class ApplicationViewModel : ViewModel
|
|||
CUE4Parse.Provider.VfsRegistered += (sender, count) =>
|
||||
{
|
||||
if (sender is not IAesVfsReader reader) return;
|
||||
Status.UpdateStatusLabel($"{count} Archives ({reader.Name})", "Registered");
|
||||
QueueProviderStatus($"{count} Archives ({reader.Name})", "Registered");
|
||||
CUE4Parse.GameDirectory.Add(reader);
|
||||
};
|
||||
CUE4Parse.Provider.VfsMounted += (sender, count) =>
|
||||
{
|
||||
if (sender is not IAesVfsReader reader) return;
|
||||
Status.UpdateStatusLabel($"{count:N0} Packages ({reader.Name})", "Mounted");
|
||||
QueueProviderStatus($"{count:N0} Packages ({reader.Name})", "Mounted");
|
||||
CUE4Parse.GameDirectory.Verify(reader);
|
||||
};
|
||||
CUE4Parse.Provider.VfsUnmounted += (sender, _) =>
|
||||
|
|
@ -137,6 +142,34 @@ public class ApplicationViewModel : ViewModel
|
|||
Status.SetStatus(EStatusKind.Ready);
|
||||
}
|
||||
|
||||
private void QueueProviderStatus(string label, string prefix)
|
||||
{
|
||||
lock (_providerStatusLock)
|
||||
{
|
||||
_pendingProviderStatus = (label, prefix);
|
||||
if (_providerStatusScheduled)
|
||||
return;
|
||||
|
||||
_providerStatusScheduled = true;
|
||||
}
|
||||
|
||||
_ = Application.Current.Dispatcher.BeginInvoke(PublishProviderStatus, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
private void PublishProviderStatus()
|
||||
{
|
||||
(string Label, string Prefix)? update;
|
||||
lock (_providerStatusLock)
|
||||
{
|
||||
update = _pendingProviderStatus;
|
||||
_pendingProviderStatus = null;
|
||||
_providerStatusScheduled = false;
|
||||
}
|
||||
|
||||
if (update is { } status)
|
||||
Status.UpdateStatusLabel(status.Label, status.Prefix);
|
||||
}
|
||||
|
||||
public DirectorySettings AvoidEmptyGameDirectory(bool bAlreadyLaunched)
|
||||
{
|
||||
var gameDirectory = UserSettings.Default.GameDirectory;
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
|
||||
Provider.Initialize();
|
||||
GameDirectory.AddLooseFiles(Provider.LooseFileCount);
|
||||
GameDirectory.FlushPendingChanges();
|
||||
_wwiseProviderLazy = new Lazy<WwiseProvider>(() => new WwiseProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
_fmodProviderLazy = new Lazy<FModProvider>(() => new FModProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
_criWareProviderLazy = new Lazy<CriWareProvider>(() => new CriWareProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
|
|
@ -379,6 +380,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
Provider.SubmitKeys(aesKeys);
|
||||
Provider.PostMount();
|
||||
GameDirectory.FlushPendingChanges();
|
||||
|
||||
var aesMax = Provider.RequiredKeys.Count + Provider.Keys.Count;
|
||||
var archiveMax = Provider.UnloadedVfs.Count + Provider.MountedVfs.Count;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using FModel.Framework;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Threading;
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.UE4.IO;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
|
|
@ -123,11 +125,19 @@ public class FileItem : ViewModel
|
|||
|
||||
public partial class GameDirectoryViewModel : ViewModel
|
||||
{
|
||||
public readonly ObservableCollection<FileItem> DirectoryFiles;
|
||||
private readonly record struct FileItemUpdate(FileItem File, bool IsEnabled, string MountPoint,
|
||||
int FileCount, bool HasMountInfo);
|
||||
|
||||
public readonly RangeObservableCollection<FileItem> DirectoryFiles;
|
||||
|
||||
public ICollectionView DirectoryFilesView { get; }
|
||||
|
||||
private readonly Regex _hiddenArchives = ArchivesRegex();
|
||||
private readonly ConcurrentDictionary<IAesVfsReader, FileItem> _filesByReader =
|
||||
new(ReferenceEqualityComparer.Instance);
|
||||
private readonly ConcurrentQueue<FileItem> _pendingAdditions = new();
|
||||
private readonly ConcurrentQueue<FileItemUpdate> _pendingUpdates = new();
|
||||
private int _publishScheduled;
|
||||
|
||||
public GameDirectoryViewModel()
|
||||
{
|
||||
|
|
@ -147,7 +157,11 @@ public partial class GameDirectoryViewModel : ViewModel
|
|||
if (!_hiddenArchives.IsMatch(reader.Name)) return;
|
||||
|
||||
var fileItem = new FileItem(reader);
|
||||
Application.Current.Dispatcher.Invoke(() => DirectoryFiles.Add(fileItem));
|
||||
if (!_filesByReader.TryAdd(reader, fileItem))
|
||||
return;
|
||||
|
||||
_pendingAdditions.Enqueue(fileItem);
|
||||
SchedulePublish();
|
||||
}
|
||||
|
||||
public void AddLooseFiles(int fileCount)
|
||||
|
|
@ -155,33 +169,64 @@ public partial class GameDirectoryViewModel : ViewModel
|
|||
if (fileCount < 1)
|
||||
return;
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var looseFilesContainer = DirectoryFiles.FirstOrDefault(x => x.IsLooseFilesContainer);
|
||||
if (looseFilesContainer is not null)
|
||||
{
|
||||
looseFilesContainer.FileCount += fileCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
DirectoryFiles.Add(new FileItem("Loose Files", fileCount, 0, true));
|
||||
}
|
||||
});
|
||||
_pendingAdditions.Enqueue(new FileItem("Loose Files", fileCount, 0, true));
|
||||
SchedulePublish();
|
||||
}
|
||||
|
||||
public void Verify(IAesVfsReader reader)
|
||||
{
|
||||
if (DirectoryFiles.FirstOrDefault(x => x.Name == reader.Name) is not { } file) return;
|
||||
if (!_filesByReader.TryGetValue(reader, out var file)) return;
|
||||
|
||||
file.IsEnabled = true;
|
||||
file.MountPoint = reader.MountPoint;
|
||||
file.FileCount = reader.FileCount;
|
||||
_pendingUpdates.Enqueue(new FileItemUpdate(file, true, reader.MountPoint, reader.FileCount, true));
|
||||
SchedulePublish();
|
||||
}
|
||||
|
||||
public void Disable(IAesVfsReader reader)
|
||||
{
|
||||
if (DirectoryFiles.FirstOrDefault(x => x.Name == reader.Name) is not { } file) return;
|
||||
file.IsEnabled = false;
|
||||
if (!_filesByReader.TryGetValue(reader, out var file)) return;
|
||||
|
||||
_pendingUpdates.Enqueue(new FileItemUpdate(file, false, string.Empty, 0, false));
|
||||
SchedulePublish();
|
||||
}
|
||||
|
||||
public void FlushPendingChanges()
|
||||
{
|
||||
if (Application.Current.Dispatcher.CheckAccess())
|
||||
PublishPendingChanges();
|
||||
else
|
||||
Application.Current.Dispatcher.Invoke(PublishPendingChanges);
|
||||
}
|
||||
|
||||
private void SchedulePublish()
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _publishScheduled, 1, 0) != 0)
|
||||
return;
|
||||
|
||||
_ = Application.Current.Dispatcher.BeginInvoke(PublishPendingChanges, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
private void PublishPendingChanges()
|
||||
{
|
||||
var additions = new List<FileItem>();
|
||||
while (_pendingAdditions.TryDequeue(out var file))
|
||||
additions.Add(file);
|
||||
|
||||
if (additions.Count > 0)
|
||||
DirectoryFiles.AddRange(additions);
|
||||
|
||||
while (_pendingUpdates.TryDequeue(out var update))
|
||||
{
|
||||
update.File.IsEnabled = update.IsEnabled;
|
||||
if (!update.HasMountInfo)
|
||||
continue;
|
||||
|
||||
update.File.MountPoint = update.MountPoint;
|
||||
update.File.FileCount = update.FileCount;
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref _publishScheduled, 0);
|
||||
if (!_pendingAdditions.IsEmpty || !_pendingUpdates.IsEmpty)
|
||||
SchedulePublish();
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^(?!global|pakchunk.+(optional|ondemand)\-).+(pak|utoc)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant)]
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@
|
|||
Value="{Binding CUE4Parse.GameDirectory.DirectoryFilesView, IsAsync=True}" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
|
||||
Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.CanContentScroll"
|
||||
Value="True" />
|
||||
<Setter Property="VirtualizingPanel.IsVirtualizing"
|
||||
Value="True" />
|
||||
<Setter Property="VirtualizingPanel.VirtualizationMode"
|
||||
Value="Recycling" />
|
||||
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarExpansionMode"
|
||||
Value="NeverExpand" />
|
||||
<Setter Property="adonisExtensions:ScrollViewerExtension.VerticalScrollBarPlacement"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user