event triggered game directory

This commit is contained in:
Asval 2024-05-25 19:51:43 +02:00
parent ed575429b1
commit 11bad8687e
6 changed files with 83 additions and 73 deletions

@ -1 +1 @@
Subproject commit 0c12be3c624d0e75b18b0a03915442610de54672
Subproject commit 4e955153559be8dc156d15fc93ff8c1016d3ebfe

View File

@ -38,8 +38,8 @@ public class FStatus : ViewModel
UpdateStatusLabel(label);
}
public void UpdateStatusLabel(string label)
public void UpdateStatusLabel(string label, string prefix = null)
{
Label = Kind == EStatusKind.Loading ? $"{Kind} {label}".Trim() : Kind.ToString();
Label = Kind == EStatusKind.Loading ? $"{prefix ?? Kind.ToString()} {label}".Trim() : Kind.ToString();
}
}

View File

@ -8,7 +8,6 @@ using FModel.Framework;
using FModel.Services;
using FModel.Settings;
using FModel.ViewModels.ApiEndpoints.Models;
using Serilog;
namespace FModel.ViewModels;

View File

@ -1,10 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using CUE4Parse.Compression;
using CUE4Parse.Encryption.Aes;
using CUE4Parse.UE4.Objects.Core.Misc;
using CUE4Parse.UE4.VirtualFileSystem;
using FModel.Extensions;
using FModel.Framework;
using FModel.Services;
@ -12,7 +17,6 @@ using FModel.Settings;
using FModel.ViewModels.Commands;
using FModel.Views;
using FModel.Views.Resources.Controls;
using MessageBox = AdonisUI.Controls.MessageBox;
using MessageBoxButton = AdonisUI.Controls.MessageBoxButton;
using MessageBoxImage = AdonisUI.Controls.MessageBoxImage;
@ -78,6 +82,24 @@ public class ApplicationViewModel : ViewModel
}
CUE4Parse = new CUE4ParseViewModel();
CUE4Parse.Provider.VfsRegistered += (sender, count) =>
{
if (sender is not IAesVfsReader reader) return;
Status.UpdateStatusLabel($"{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");
CUE4Parse.GameDirectory.Verify(reader);
};
CUE4Parse.Provider.VfsUnmounted += (sender, _) =>
{
if (sender is not IAesVfsReader reader) return;
CUE4Parse.GameDirectory.Disable(reader);
};
CustomDirectories = new CustomDirectoriesViewModel();
SettingsView = new SettingsViewModel();
AesManager = new AesManagerViewModel(CUE4Parse);
@ -155,7 +177,17 @@ public class ApplicationViewModel : ViewModel
CUE4Parse.ClearProvider();
await ApplicationService.ThreadWorkerView.Begin(cancellationToken =>
{
CUE4Parse.LoadVfs(cancellationToken, AesManager.AesKeys);
// TODO: refactor after release, select updated keys only
var aes = AesManager.AesKeys.Select(x =>
{
cancellationToken.ThrowIfCancellationRequested(); // cancel if needed
var k = x.Key.Trim();
if (k.Length != 66) k = Constants.ZERO_64_CHAR;
return new KeyValuePair<FGuid, FAesKey>(x.Guid, new FAesKey(k));
});
CUE4Parse.LoadVfs(aes);
AesManager.SetAesKeys();
});
RaisePropertyChanged(nameof(GameDisplayName));

View File

@ -41,6 +41,7 @@ using CUE4Parse.GameTypes.DreamStar.Encryption.Aes;
using CUE4Parse.GameTypes.PAXDEI.Encryption.Aes;
using CUE4Parse.GameTypes.NetEase.MAR.Encryption.Aes;
using CUE4Parse.GameTypes.FSR.Encryption.Aes;
using CUE4Parse.UE4.Objects.Core.Misc;
using EpicManifestParser;
using FModel.Creator;
using FModel.Extensions;
@ -65,8 +66,6 @@ public class CUE4ParseViewModel : ViewModel
{
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
private readonly Regex _hiddenArchives = new(@"^(?!global|pakchunk.+(optional|ondemand)\-).+(pak|utoc)$", // should be universal
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private readonly Regex _fnLive = new(@"^FortniteGame(/|\\)Content(/|\\)Paks(/|\\)",
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
@ -161,16 +160,14 @@ public class CUE4ParseViewModel : ViewModel
Provider = InternalGameName switch
{
"StateOfDecay2" => new DefaultFileProvider(new DirectoryInfo(gameDirectory),
new DirectoryInfo[]
{
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"),
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks")
}, SearchOption.AllDirectories, true, versionContainer),
[
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"),
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks")
], SearchOption.AllDirectories, true, versionContainer),
"eFootball" => new DefaultFileProvider(new DirectoryInfo(gameDirectory),
new DirectoryInfo[]
{
new(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\KONAMI\\eFootball\\ST\\Download")
}, SearchOption.AllDirectories, true, versionContainer),
[
new(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\KONAMI\\eFootball\\ST\\Download")
], SearchOption.AllDirectories, true, versionContainer),
_ => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, versionContainer)
};
@ -279,14 +276,6 @@ public class CUE4ParseViewModel : ViewModel
Provider.Initialize();
Log.Information($"{Provider.Versions.Game} ({Provider.Versions.Platform}) | Archives: x{Provider.UnloadedVfs.Count} | AES: x{Provider.RequiredKeys.Count}");
foreach (var vfs in Provider.UnloadedVfs) // push files from the provider to the ui
{
cancellationToken.ThrowIfCancellationRequested();
if (!_hiddenArchives.IsMatch(vfs.Name)) continue;
GameDirectory.Add(vfs);
}
});
}
@ -294,38 +283,10 @@ public class CUE4ParseViewModel : ViewModel
/// load virtual files system from GameDirectory
/// </summary>
/// <returns></returns>
public void LoadVfs(CancellationToken token, IEnumerable<FileItem> aesKeys)
public void LoadVfs(IEnumerable<KeyValuePair<FGuid, FAesKey>> aesKeys)
{
GameDirectory.DeactivateAll();
// load files using UnloadedVfs to include non-encrypted vfs
foreach (var key in aesKeys)
{
token.ThrowIfCancellationRequested(); // cancel if needed
var k = key.Key.Trim();
if (k.Length != 66) k = Constants.ZERO_64_CHAR;
Provider.SubmitKey(key.Guid, new FAesKey(k));
}
Provider.SubmitKeys(aesKeys);
Provider.PostMount();
// files in MountedVfs will be enabled
foreach (var file in GameDirectory.DirectoryFiles)
{
token.ThrowIfCancellationRequested();
if (Provider.MountedVfs.FirstOrDefault(x => x.Name == file.Name) is not { } vfs)
{
if (Provider.UnloadedVfs.FirstOrDefault(x => x.Name == file.Name) is IoStoreReader store)
file.FileCount = (int) store.TocResource.Header.TocEntryCount - 1;
continue;
}
file.IsEnabled = true;
file.MountPoint = vfs.MountPoint;
file.FileCount = vfs.FileCount;
}
InternalGameName = Provider.InternalGameName;
var aesMax = Provider.RequiredKeys.Count + Provider.Keys.Count;

View File

@ -1,8 +1,11 @@
using FModel.Framework;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Data;
using CUE4Parse.UE4.IO;
using CUE4Parse.UE4.Objects.Core.Misc;
using CUE4Parse.UE4.VirtualFileSystem;
@ -72,6 +75,17 @@ public class FileItem : ViewModel
Length = length;
}
public FileItem(IAesVfsReader reader)
{
Name = reader.Name;
Length = reader.Length;
Guid = reader.EncryptionKeyGuid;
IsEncrypted = reader.IsEncrypted;
IsEnabled = false;
Key = string.Empty;
FileCount = reader is IoStoreReader storeReader ? (int) storeReader.TocResource.Header.TocEntryCount - 1 : 0;
}
public override string ToString()
{
return $"{Name} | {Key}";
@ -84,31 +98,35 @@ public class GameDirectoryViewModel : ViewModel
public readonly ObservableCollection<FileItem> DirectoryFiles;
public ICollectionView DirectoryFilesView { get; }
private readonly Regex _hiddenArchives = new(@"^(?!global|pakchunk.+(optional|ondemand)\-).+(pak|utoc)$", // should be universal
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
public GameDirectoryViewModel()
{
DirectoryFiles = new ObservableCollection<FileItem>();
DirectoryFilesView = new ListCollectionView(DirectoryFiles) { SortDescriptions = { new SortDescription("Name", ListSortDirection.Ascending) } };
}
public void DeactivateAll()
{
foreach (var file in DirectoryFiles)
{
file.IsEnabled = false;
}
}
public void Add(IAesVfsReader reader)
{
Application.Current.Dispatcher.Invoke(() =>
{
DirectoryFiles.Add(new FileItem(reader.Name, reader.Length)
{
Guid = reader.EncryptionKeyGuid,
IsEncrypted = reader.IsEncrypted,
IsEnabled = false,
Key = string.Empty
});
});
if (!_hiddenArchives.IsMatch(reader.Name)) return;
var fileItem = new FileItem(reader);
Application.Current.Dispatcher.Invoke(() => DirectoryFiles.Add(fileItem));
}
public void Verify(IAesVfsReader reader)
{
if (DirectoryFiles.FirstOrDefault(x => x.Name == reader.Name) is not { } file) return;
file.IsEnabled = true;
file.MountPoint = reader.MountPoint;
file.FileCount = reader.FileCount;
}
public void Disable(IAesVfsReader reader)
{
if (DirectoryFiles.FirstOrDefault(x => x.Name == reader.Name) is not { } file) return;
file.IsEnabled = false;
}
}