From dbf618e417dc59d6868686fcba5db73347bc7e46 Mon Sep 17 00:00:00 2001 From: Asval Date: Thu, 6 Feb 2025 18:22:35 +0100 Subject: [PATCH] ui now deals with GameFile instead of a bad replica that means loose files are now supported, or should be Export Raw Data shows the correct extension --- CUE4Parse | 2 +- FModel/Framework/FakeCUE4Parse.cs | 27 +++++ FModel/MainWindow.xaml | 13 ++- FModel/MainWindow.xaml.cs | 9 +- FModel/ViewModels/AssetsFolderViewModel.cs | 70 ++++++------ FModel/ViewModels/AssetsListViewModel.cs | 96 +---------------- FModel/ViewModels/CUE4ParseViewModel.cs | 101 +++++++++--------- FModel/ViewModels/Commands/CopyCommand.cs | 16 +-- FModel/ViewModels/Commands/LoadCommand.cs | 54 +++++----- .../Commands/RightClickMenuCommand.cs | 35 +++--- FModel/ViewModels/Commands/TabCommand.cs | 18 ++-- FModel/ViewModels/SearchViewModel.cs | 11 +- FModel/ViewModels/TabControlViewModel.cs | 38 ++++--- .../Resources/Controls/AvalonEditor.xaml.cs | 2 +- .../Controls/PropertiesPopout.xaml.cs | 2 +- .../FileExtensionEqualsConverter.cs | 20 ---- .../Converters/FullPathToFileConverter.cs | 21 ---- FModel/Views/Resources/Resources.xaml | 21 ++-- FModel/Views/SearchView.xaml | 13 ++- FModel/Views/SearchView.xaml.cs | 13 +-- 20 files changed, 246 insertions(+), 336 deletions(-) create mode 100644 FModel/Framework/FakeCUE4Parse.cs delete mode 100644 FModel/Views/Resources/Converters/FileExtensionEqualsConverter.cs delete mode 100644 FModel/Views/Resources/Converters/FullPathToFileConverter.cs diff --git a/CUE4Parse b/CUE4Parse index ab6dff8e..11a92870 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit ab6dff8e98e94335916a549810466eb4571a072b +Subproject commit 11a92870024a088888aae79c74d8ae0c6c8af3e5 diff --git a/FModel/Framework/FakeCUE4Parse.cs b/FModel/Framework/FakeCUE4Parse.cs new file mode 100644 index 00000000..43e53edd --- /dev/null +++ b/FModel/Framework/FakeCUE4Parse.cs @@ -0,0 +1,27 @@ +using System; +using CUE4Parse.Compression; +using CUE4Parse.FileProvider.Objects; +using CUE4Parse.UE4.Readers; + +namespace FModel.Framework; + +public class FakeGameFile : GameFile +{ + public FakeGameFile(string path) : base(path, 0) + { + + } + + public override bool IsEncrypted => false; + public override CompressionMethod CompressionMethod => CompressionMethod.None; + + public override byte[] Read() + { + throw new NotImplementedException(); + } + + public override FArchive CreateReader() + { + throw new NotImplementedException(); + } +} diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index 3eabad34..d85febbe 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -502,7 +502,14 @@ - + + + + @@ -649,11 +656,11 @@ - + - + diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index edcdd5b7..b4200026 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -6,6 +6,7 @@ using System.Windows.Controls; using System.Windows.Input; using AdonisUI.Controls; +using CUE4Parse.FileProvider.Objects; using FModel.Services; using FModel.Settings; using FModel.ViewModels; @@ -84,7 +85,7 @@ await Task.WhenAll( #if DEBUG // await _threadWorkerView.Begin(cancellationToken => // _applicationView.CUE4Parse.Extract(cancellationToken, - // "MyProject/Content/FirstPerson/Meshes/FirstPersonProjectileMesh.uasset")); + // "Marvel/Content/Marvel/Characters/1016/1016501/Meshes/SK_1016_1016501.uasset")); // await _threadWorkerView.Begin(cancellationToken => // _applicationView.CUE4Parse.Extract(cancellationToken, // "RED/Content/Chara/ABA/Costume01/Animation/Charaselect/body/stand_body01.uasset")); @@ -162,7 +163,7 @@ private async void OnAssetsListMouseDoubleClick(object sender, MouseButtonEventA { if (sender is not ListBox listBox) return; - var selectedItems = listBox.SelectedItems.Cast().ToList(); + var selectedItems = listBox.SelectedItems.Cast().ToList(); await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractSelected(cancellationToken, selectedItems); }); } @@ -266,7 +267,7 @@ private void OnFilterTextChanged(object sender, TextChangedEventArgs e) return; var filters = textBox.Text.Trim().Split(' '); - folder.AssetsList.AssetsView.Filter = o => { return o is AssetItem assetItem && filters.All(x => assetItem.FileName.Contains(x, StringComparison.OrdinalIgnoreCase)); }; + folder.AssetsList.AssetsView.Filter = o => { return o is GameFile entry && filters.All(x => entry.Name.Contains(x, StringComparison.OrdinalIgnoreCase)); }; } private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e) @@ -283,7 +284,7 @@ private async void OnPreviewKeyDown(object sender, KeyEventArgs e) switch (e.Key) { case Key.Enter: - var selectedItems = listBox.SelectedItems.Cast().ToList(); + var selectedItems = listBox.SelectedItems.Cast().ToList(); await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractSelected(cancellationToken, selectedItems); }); break; } diff --git a/FModel/ViewModels/AssetsFolderViewModel.cs b/FModel/ViewModels/AssetsFolderViewModel.cs index 8caa2302..08b8f192 100644 --- a/FModel/ViewModels/AssetsFolderViewModel.cs +++ b/FModel/ViewModels/AssetsFolderViewModel.cs @@ -4,6 +4,7 @@ using System.Text; using System.Windows; using System.Windows.Data; +using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.Versions; using CUE4Parse.UE4.VirtualFileSystem; using FModel.Framework; @@ -60,12 +61,15 @@ public FPackageFileVersion Version public RangeObservableCollection Folders { get; } public ICollectionView FoldersView { get; } - public TreeItem(string header, string archive, string mountPoint, FPackageFileVersion version, string pathHere) + public TreeItem(string header, GameFile entry, string pathHere) { Header = header; - Archive = archive; - MountPoint = mountPoint; - Version = version; + if (entry is VfsEntry vfsEntry) + { + Archive = vfsEntry.Vfs.Name; + MountPoint = vfsEntry.Vfs.MountPoint; + Version = vfsEntry.Vfs.Ver; + } PathAtThisPoint = pathHere; AssetsList = new AssetsListViewModel(); Folders = new RangeObservableCollection(); @@ -86,7 +90,7 @@ public AssetsFolderViewModel() FoldersView = new ListCollectionView(Folders) { SortDescriptions = { new SortDescription("Header", ListSortDirection.Ascending) } }; } - public void BulkPopulate(IReadOnlyCollection entries) + public void BulkPopulate(IReadOnlyCollection entries) { if (entries == null || entries.Count == 0) return; @@ -95,54 +99,48 @@ public void BulkPopulate(IReadOnlyCollection entries) { var treeItems = new RangeObservableCollection(); treeItems.SetSuppressionState(true); - var items = new List(entries.Count); foreach (var entry in entries) { - var item = new AssetItem(entry.Path, entry.IsEncrypted, entry.Offset, entry.Size, entry.Vfs.Name, entry.CompressionMethod); - items.Add(item); + TreeItem lastNode = null; + var folders = entry.Path.Split('/', StringSplitOptions.RemoveEmptyEntries); + var builder = new StringBuilder(64); + var parentNode = treeItems; + for (var i = 0; i < folders.Length - 1; i++) { - TreeItem lastNode = null; - var folders = item.FullPath.Split('/', StringSplitOptions.RemoveEmptyEntries); - var builder = new StringBuilder(64); - var parentNode = treeItems; + var folder = folders[i]; + builder.Append(folder).Append('/'); + lastNode = FindByHeaderOrNull(parentNode, folder); - for (var i = 0; i < folders.Length - 1; i++) + static TreeItem FindByHeaderOrNull(IReadOnlyList list, string header) { - var folder = folders[i]; - builder.Append(folder).Append('/'); - lastNode = FindByHeaderOrNull(parentNode, folder); - - static TreeItem FindByHeaderOrNull(IReadOnlyList list, string header) + for (var i = 0; i < list.Count; i++) { - for (var i = 0; i < list.Count; i++) - { - if (list[i].Header == header) - return list[i]; - } - - return null; + if (list[i].Header == header) + return list[i]; } - if (lastNode == null) - { - var nodePath = builder.ToString(); - lastNode = new TreeItem(folder, item.Archive, entry.Vfs.MountPoint, entry.Vfs.Ver, nodePath[..^1]); - lastNode.Folders.SetSuppressionState(true); - lastNode.AssetsList.Assets.SetSuppressionState(true); - parentNode.Add(lastNode); - } + return null; + } - parentNode = lastNode.Folders; + if (lastNode == null) + { + var nodePath = builder.ToString(); + lastNode = new TreeItem(folder, entry, nodePath[..^1]); + lastNode.Folders.SetSuppressionState(true); + lastNode.AssetsList.Assets.SetSuppressionState(true); + parentNode.Add(lastNode); } - lastNode?.AssetsList.Assets.Add(item); + parentNode = lastNode.Folders; } + + lastNode?.AssetsList.Assets.Add(entry); } Folders.AddRange(treeItems); - ApplicationService.ApplicationView.CUE4Parse.SearchVm.SearchResults.AddRange(items); + ApplicationService.ApplicationView.CUE4Parse.SearchVm.SearchResults.AddRange(entries); foreach (var folder in Folders) InvokeOnCollectionChanged(folder); diff --git a/FModel/ViewModels/AssetsListViewModel.cs b/FModel/ViewModels/AssetsListViewModel.cs index cab5ba0f..1d9083da 100644 --- a/FModel/ViewModels/AssetsListViewModel.cs +++ b/FModel/ViewModels/AssetsListViewModel.cs @@ -1,109 +1,21 @@ using System.ComponentModel; using System.Windows.Data; -using CUE4Parse.Compression; -using CUE4Parse.Utils; +using CUE4Parse.FileProvider.Objects; using FModel.Framework; namespace FModel.ViewModels; -public class AssetItem : ViewModel -{ - private string _fullPath; - public string FullPath - { - get => _fullPath; - private set => SetProperty(ref _fullPath, value); - } - - private bool _isEncrypted; - public bool IsEncrypted - { - get => _isEncrypted; - private set => SetProperty(ref _isEncrypted, value); - } - - private long _offset; - public long Offset - { - get => _offset; - private set => SetProperty(ref _offset, value); - } - - private long _size; - public long Size - { - get => _size; - private set => SetProperty(ref _size, value); - } - - private string _archive; - public string Archive - { - get => _archive; - private set => SetProperty(ref _archive, value); - } - - private CompressionMethod _compression; - public CompressionMethod Compression - { - get => _compression; - private set => SetProperty(ref _compression, value); - } - - private string _directory; - public string Directory - { - get => _directory; - private set => SetProperty(ref _directory, value); - } - - private string _fileName; - public string FileName - { - get => _fileName; - private set => SetProperty(ref _fileName, value); - } - - private string _extension; - public string Extension - { - get => _extension; - private set => SetProperty(ref _extension, value); - } - - public AssetItem(string titleExtra, AssetItem asset) : this(asset.FullPath, asset.IsEncrypted, asset.Offset, asset.Size, asset.Archive, asset.Compression) - { - FullPath += titleExtra; - } - - public AssetItem(string fullPath, bool isEncrypted = false, long offset = 0, long size = 0, string archive = "", CompressionMethod compression = CompressionMethod.None) - { - FullPath = fullPath; - IsEncrypted = isEncrypted; - Offset = offset; - Size = size; - Archive = archive; - Compression = compression; - - Directory = FullPath.SubstringBeforeLast('/'); - FileName = FullPath.SubstringAfterLast('/'); - Extension = FullPath.SubstringAfterLast('.').ToLowerInvariant(); - } - - public override string ToString() => FullPath; -} - public class AssetsListViewModel { - public RangeObservableCollection Assets { get; } + public RangeObservableCollection Assets { get; } public ICollectionView AssetsView { get; } public AssetsListViewModel() { - Assets = new RangeObservableCollection(); + Assets = new RangeObservableCollection(); AssetsView = new ListCollectionView(Assets) { - SortDescriptions = { new SortDescription("FullPath", ListSortDirection.Ascending) } + SortDescriptions = { new SortDescription("Path", ListSortDirection.Ascending) } }; } } diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 5eed6bad..fdcc086d 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -37,6 +37,7 @@ using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion; using CUE4Parse_Conversion.Sounds; +using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.Assets; using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.Utils; @@ -499,25 +500,25 @@ public Task LoadVirtualPaths() }); } - public void ExtractSelected(CancellationToken cancellationToken, IEnumerable assetItems) + public void ExtractSelected(CancellationToken cancellationToken, IEnumerable assetItems) { - foreach (var asset in assetItems) + foreach (var entry in assetItems) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - Extract(cancellationToken, asset, TabControl.HasNoTabs); + Extract(cancellationToken, entry, TabControl.HasNoTabs); } } - private void BulkFolder(CancellationToken cancellationToken, TreeItem folder, Action action) + private void BulkFolder(CancellationToken cancellationToken, TreeItem folder, Action action) { - foreach (var asset in folder.AssetsList.Assets) + foreach (var entry in folder.AssetsList.Assets) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); try { - action(asset); + action(entry); } catch { @@ -530,10 +531,10 @@ private void BulkFolder(CancellationToken cancellationToken, TreeItem folder, Ac public void ExportFolder(CancellationToken cancellationToken, TreeItem folder) { - Parallel.ForEach(folder.AssetsList.Assets, asset => + Parallel.ForEach(folder.AssetsList.Assets, entry => { cancellationToken.ThrowIfCancellationRequested(); - ExportData(asset, false); + ExportData(entry, false); }); foreach (var f in folder.Folders) ExportFolder(cancellationToken, f); @@ -554,23 +555,23 @@ public void ModelFolder(CancellationToken cancellationToken, TreeItem folder) public void AnimationFolder(CancellationToken cancellationToken, TreeItem folder) => BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Animations | EBulkType.Auto)); - public void Extract(CancellationToken cancellationToken, AssetItem asset, bool addNewTab = false, EBulkType bulk = EBulkType.None) + public void Extract(CancellationToken cancellationToken, GameFile entry, bool addNewTab = false, EBulkType bulk = EBulkType.None) { - Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", asset.FullPath); + Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", entry.Path); - if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(asset); - else TabControl.SelectedTab.SoftReset(asset); - TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(asset.Extension); + if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(entry); + else TabControl.SelectedTab.SoftReset(entry); + TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(entry.Extension); var updateUi = !HasFlag(bulk, EBulkType.Auto); var saveProperties = HasFlag(bulk, EBulkType.Properties); var saveTextures = HasFlag(bulk, EBulkType.Textures); - switch (asset.Extension) + switch (entry.Extension) { case "uasset": case "umap": { - var pkg = Provider.LoadPackage(asset.FullPath, asset.Archive); + var pkg = Provider.LoadPackage(entry); if (saveProperties || updateUi) { TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), saveProperties, updateUi); @@ -614,7 +615,7 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a case "po": case "h": { - var data = Provider.SaveAsset(asset.FullPath, asset.Archive); + var data = Provider.SaveAsset(entry); using var stream = new MemoryStream(data) { Position = 0 }; using var reader = new StreamReader(stream); @@ -624,7 +625,7 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a } case "locmeta": { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var metadata = new FTextLocalizationMetaDataResource(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(metadata, Formatting.Indented), saveProperties, updateUi); @@ -632,23 +633,23 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a } case "locres": { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var locres = new FTextLocalizationResource(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(locres, Formatting.Indented), saveProperties, updateUi); break; } - case "bin" when asset.FileName.Contains("AssetRegistry", StringComparison.OrdinalIgnoreCase): + case "bin" when entry.Name.Contains("AssetRegistry", StringComparison.OrdinalIgnoreCase): { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var registry = new FAssetRegistryState(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi); break; } - case "bin" when asset.FileName.Contains("GlobalShaderCache", StringComparison.OrdinalIgnoreCase): + case "bin" when entry.Name.Contains("GlobalShaderCache", StringComparison.OrdinalIgnoreCase): { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var registry = new FGlobalShaderCache(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi); @@ -657,26 +658,26 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a case "bnk": case "pck": { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var wwise = new WwiseReader(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi); foreach (var (name, data) in wwise.WwiseEncodedMedias) { - SaveAndPlaySound(asset.FullPath.SubstringBeforeWithLast('/') + name, "WEM", data); + SaveAndPlaySound(entry.Path.SubstringBeforeWithLast('/') + name, "WEM", data); } break; } case "wem": { - var data = Provider.SaveAsset(asset.FullPath, asset.Archive); - SaveAndPlaySound(asset.FullPath, "WEM", data); + var data = Provider.SaveAsset(entry); + SaveAndPlaySound(entry.Path, "WEM", data); break; } case "udic": { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var header = new FOodleDictionaryArchive(archive).Header; TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(header, Formatting.Indented), saveProperties, updateUi); @@ -686,15 +687,15 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a case "jpg": case "bmp": { - var data = Provider.SaveAsset(asset.FullPath, asset.Archive); + var data = Provider.SaveAsset(entry); using var stream = new MemoryStream(data) { Position = 0 }; - TabControl.SelectedTab.AddImage(asset.FileName.SubstringBeforeLast("."), false, SKBitmap.Decode(stream), saveTextures, updateUi); + TabControl.SelectedTab.AddImage(entry.NameWithoutExtension, false, SKBitmap.Decode(stream), saveTextures, updateUi); break; } case "svg": { - var data = Provider.SaveAsset(asset.FullPath, asset.Archive); + var data = Provider.SaveAsset(entry); using var stream = new MemoryStream(data) { Position = 0 }; var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(512, 512)); svg.Load(stream); @@ -706,7 +707,7 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a canvas.DrawPicture(svg.Picture, paint); } - TabControl.SelectedTab.AddImage(asset.FileName.SubstringBeforeLast("."), false, bitmap, saveTextures, updateUi); + TabControl.SelectedTab.AddImage(entry.NameWithoutExtension, false, bitmap, saveTextures, updateUi); break; } @@ -714,12 +715,12 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a case "otf": case "ttf": FLogger.Append(ELog.Warning, () => - FLogger.Text($"Export '{asset.FileName}' raw data and change its extension if you want it to be an installable font file", Constants.WHITE, true)); + FLogger.Text($"Export '{entry.Name}' raw data and change its extension if you want it to be an installable font file", Constants.WHITE, true)); break; case "ushaderbytecode": case "ushadercode": { - var archive = Provider.CreateReader(asset.FullPath, asset.Archive); + var archive = entry.CreateReader(); var ar = new FShaderCodeArchive(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(ar, Formatting.Indented), saveProperties, updateUi); @@ -728,7 +729,7 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a default: { FLogger.Append(ELog.Warning, () => - FLogger.Text($"The package '{asset.FileName}' is of an unknown type.", Constants.WHITE, true)); + FLogger.Text($"The package '{entry.Name}' is of an unknown type.", Constants.WHITE, true)); break; } } @@ -737,10 +738,12 @@ public void Extract(CancellationToken cancellationToken, AssetItem asset, bool a public void ExtractAndScroll(CancellationToken cancellationToken, string fullPath, string objectName, string parentExportType) { Log.Information("User CTRL-CLICKED to extract '{FullPath}'", fullPath); - TabControl.AddTab(new AssetItem(fullPath), parentExportType); + + var entry = Provider[fullPath]; + TabControl.AddTab(entry, parentExportType); TabControl.SelectedTab.ScrollTrigger = objectName; - var pkg = Provider.LoadPackage(fullPath); + var pkg = Provider.LoadPackage(entry); TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); // json TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), false, false); @@ -797,7 +800,7 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat { var fileName = sourceFile.SubstringAfterLast('/'); var path = Path.Combine(UserSettings.Default.TextureDirectory, - UserSettings.Default.KeepDirectoryStructure ? TabControl.SelectedTab.Asset.Directory : "", fileName!).Replace('\\', '/'); + UserSettings.Default.KeepDirectoryStructure ? TabControl.SelectedTab.Entry.Directory : "", fileName!).Replace('\\', '/'); Directory.CreateDirectory(path.SubstringBeforeLast('/')); @@ -838,7 +841,7 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat return false; } - SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Asset.FullPath.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data); + SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Entry.PathWithoutExtension).Replace('\\', '/'), audioFormat, data); return false; } case UWorld when isNone && UserSettings.Default.PreviewWorlds: @@ -900,13 +903,11 @@ public void ExtractAndScroll(CancellationToken cancellationToken, string fullPat } } - public void ShowMetadata(AssetItem asset) + public void ShowMetadata(GameFile entry) { - var package = Provider.LoadPackage(asset.FullPath, asset.Archive); + var package = Provider.LoadPackage(entry); - var a = new AssetItem(" (Metadata)", asset); - if (TabControl.CanAddTabs) TabControl.AddTab(a); - else TabControl.SelectedTab.SoftReset(a); + TabControl.AddTab($"{entry.Name} (Metadata)"); TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false); @@ -963,11 +964,9 @@ private void SaveExport(UObject export, bool updateUi = true) } private readonly object _rawData = new (); - public void ExportData(AssetItem asset, bool updateUi = true) + public void ExportData(GameFile entry, bool updateUi = true) { - // TODO: export by archive - // is that even useful? if user doesn't rename manually it's gonna overwrite the file anyway - if (Provider.TrySavePackage(asset.FullPath, out var assets)) + if (Provider.TrySavePackage(entry, out var assets)) { string path = UserSettings.Default.RawDataDirectory; Parallel.ForEach(assets, kvp => @@ -980,21 +979,21 @@ public void ExportData(AssetItem asset, bool updateUi = true) } }); - Log.Information("{FileName} successfully exported", asset.FileName); + Log.Information("{FileName} successfully exported", entry.Name); if (updateUi) { FLogger.Append(ELog.Information, () => { FLogger.Text("Successfully exported ", Constants.WHITE); - FLogger.Link(asset.FileName, path, true); + FLogger.Link(entry.Name, path, true); }); } } else { - Log.Error("{FileName} could not be exported", asset.FileName); + Log.Error("{FileName} could not be exported", entry.Name); if (updateUi) - FLogger.Append(ELog.Error, () => FLogger.Text($"Could not export '{asset.FileName}'", Constants.WHITE, true)); + FLogger.Append(ELog.Error, () => FLogger.Text($"Could not export '{entry.Name}'", Constants.WHITE, true)); } } diff --git a/FModel/ViewModels/Commands/CopyCommand.cs b/FModel/ViewModels/Commands/CopyCommand.cs index a46ce85c..42add0cc 100644 --- a/FModel/ViewModels/Commands/CopyCommand.cs +++ b/FModel/ViewModels/Commands/CopyCommand.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text; using System.Windows; -using CUE4Parse.Utils; +using CUE4Parse.FileProvider.Objects; using FModel.Framework; namespace FModel.ViewModels.Commands; @@ -18,26 +18,26 @@ public override void Execute(ApplicationViewModel contextViewModel, object param if (parameter is not object[] parameters || parameters[0] is not string trigger) return; - var assetItems = ((IList) parameters[1]).Cast().ToArray(); - if (!assetItems.Any()) return; + var entries = ((IList) parameters[1]).Cast().ToArray(); + if (!entries.Any()) return; var sb = new StringBuilder(); switch (trigger) { case "File_Path": - foreach (var asset in assetItems) sb.AppendLine(asset.FullPath); + foreach (var entry in entries) sb.AppendLine(entry.Path); break; case "File_Name": - foreach (var asset in assetItems) sb.AppendLine(asset.FullPath.SubstringAfterLast('/')); + foreach (var entry in entries) sb.AppendLine(entry.Name); break; case "Directory_Path": - foreach (var asset in assetItems) sb.AppendLine(asset.FullPath.SubstringBeforeLast('/')); + foreach (var entry in entries) sb.AppendLine(entry.Directory); break; case "File_Path_No_Extension": - foreach (var asset in assetItems) sb.AppendLine(asset.FullPath.SubstringBeforeLast('.')); + foreach (var entry in entries) sb.AppendLine(entry.PathWithoutExtension); break; case "File_Name_No_Extension": - foreach (var asset in assetItems) sb.AppendLine(asset.FullPath.SubstringAfterLast('/').SubstringBeforeLast('.')); + foreach (var entry in entries) sb.AppendLine(entry.NameWithoutExtension); break; } diff --git a/FModel/ViewModels/Commands/LoadCommand.cs b/FModel/ViewModels/Commands/LoadCommand.cs index 304286ff..3e58b4e8 100644 --- a/FModel/ViewModels/Commands/LoadCommand.cs +++ b/FModel/ViewModels/Commands/LoadCommand.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using AdonisUI.Controls; +using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.Readers; using CUE4Parse.UE4.VirtualFileSystem; using CUE4Parse.Utils; @@ -37,13 +38,17 @@ public LoadCommand(LoadingModesViewModel contextViewModel) : base(contextViewMod public override async void Execute(LoadingModesViewModel contextViewModel, object parameter) { - if (_applicationView.CUE4Parse.GameDirectory.HasNoFile) return; if (_applicationView.CUE4Parse.Provider.Keys.Count == 0 && _applicationView.CUE4Parse.Provider.RequiredKeys.Count > 0) { FLogger.Append(ELog.Error, () => FLogger.Text("An encrypted archive has been found. In order to decrypt it, please specify a working AES encryption key", Constants.WHITE, true)); return; } + if (_applicationView.CUE4Parse.Provider.Files.Count == 0) + { + FLogger.Append(ELog.Error, () => FLogger.Text("No files were found in the archives or the specified directory", Constants.WHITE, true)); + return; + } #if DEBUG var loadingTime = Stopwatch.StartNew(); @@ -59,6 +64,7 @@ await Task.WhenAll( _threadWorkerView.Begin(cancellationToken => { // filter what to show + _applicationView.Status.UpdateStatusLabel("Packages", "Filtering"); switch (UserSettings.Default.LoadingMode) { case ELoadingMode.Multiple: @@ -100,42 +106,36 @@ private void FilterDirectoryFilesToDisplay(CancellationToken cancellationToken, if (directoryFiles == null) filter = null; else { - filter = new HashSet(); + filter = []; foreach (var directoryFile in directoryFiles) { - if (!directoryFile.IsEnabled) - continue; - + if (!directoryFile.IsEnabled) continue; filter.Add(directoryFile.Name); } } var hasFilter = filter != null && filter.Count != 0; - var entries = new List(); + var entries = new List(); foreach (var asset in _applicationView.CUE4Parse.Provider.Files.Values) { cancellationToken.ThrowIfCancellationRequested(); // cancel if needed - - if (asset is not VfsEntry entry || entry.Path.EndsWith(".uexp") || entry.Path.EndsWith(".ubulk") || entry.Path.EndsWith(".uptnl")) - continue; + if (asset.IsUePackagePayload) continue; if (hasFilter) { - if (filter.Contains(entry.Vfs.Name)) + if (asset is VfsEntry entry && filter.Contains(entry.Vfs.Name)) { - entries.Add(entry); - _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); + entries.Add(asset); } } else { - entries.Add(entry); - _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); + entries.Add(asset); } } - _applicationView.Status.UpdateStatusLabel("Folders & Packages"); + _applicationView.Status.UpdateStatusLabel($"{entries.Count:### ### ###} Packages"); _applicationView.CUE4Parse.AssetsFolder.BulkPopulate(entries); } @@ -157,11 +157,11 @@ private void FilterNewOrModifiedFilesToDisplay(CancellationToken cancellationTok var mode = UserSettings.Default.LoadingMode; var entries = ParseBackup(openFileDialog.FileName, mode, cancellationToken); - _applicationView.Status.UpdateStatusLabel($"{mode.ToString()[6..]} Folders & Packages"); + _applicationView.Status.UpdateStatusLabel($"{entries.Count:### ### ###} Packages"); _applicationView.CUE4Parse.AssetsFolder.BulkPopulate(entries); } - private List ParseBackup(string path, ELoadingMode mode, CancellationToken cancellationToken = default) + private List ParseBackup(string path, ELoadingMode mode, CancellationToken cancellationToken = default) { using var fileStream = new FileStream(path, FileMode.Open); using var memoryStream = new MemoryStream(); @@ -176,7 +176,7 @@ private List ParseBackup(string path, ELoadingMode mode, CancellationT memoryStream.Position = 0; using var archive = new FStreamArchive(fileStream.Name, memoryStream); - var entries = new List(); + var entries = new List(); switch (mode) { @@ -209,14 +209,12 @@ private List ParseBackup(string path, ELoadingMode mode, CancellationT } } - foreach (var (key, value) in _applicationView.CUE4Parse.Provider.Files) + foreach (var (key, asset) in _applicationView.CUE4Parse.Provider.Files) { cancellationToken.ThrowIfCancellationRequested(); - if (value is not VfsEntry entry || paths.Contains(key) || entry.Path.EndsWith(".uexp") || - entry.Path.EndsWith(".ubulk") || entry.Path.EndsWith(".uptnl")) continue; + if (asset.IsUePackagePayload || paths.Contains(key)) continue; - entries.Add(entry); - _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); + entries.Add(asset); } break; @@ -263,14 +261,12 @@ private List ParseBackup(string path, ELoadingMode mode, CancellationT return entries; } - private void AddEntry(string path, long uncompressedSize, bool isEncrypted, List entries) + private void AddEntry(string path, long uncompressedSize, bool isEncrypted, List entries) { - if (path.EndsWith(".uexp") || path.EndsWith(".ubulk") || path.EndsWith(".uptnl") || - !_applicationView.CUE4Parse.Provider.Files.TryGetValue(path, out var asset) || asset is not VfsEntry entry || - entry.Size == uncompressedSize && entry.IsEncrypted == isEncrypted) + if (!_applicationView.CUE4Parse.Provider.Files.TryGetValue(path, out var asset) || + asset.IsUePackagePayload || asset.Size == uncompressedSize && asset.IsEncrypted == isEncrypted) return; - entries.Add(entry); - _applicationView.Status.UpdateStatusLabel(entry.Vfs.Name); + entries.Add(asset); } } diff --git a/FModel/ViewModels/Commands/RightClickMenuCommand.cs b/FModel/ViewModels/Commands/RightClickMenuCommand.cs index 065790d6..0801e81b 100644 --- a/FModel/ViewModels/Commands/RightClickMenuCommand.cs +++ b/FModel/ViewModels/Commands/RightClickMenuCommand.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Linq; using System.Threading; +using CUE4Parse.FileProvider.Objects; using FModel.Framework; using FModel.Services; @@ -19,68 +20,68 @@ public override async void Execute(ApplicationViewModel contextViewModel, object if (parameter is not object[] parameters || parameters[0] is not string trigger) return; - var assetItems = ((IList) parameters[1]).Cast().ToArray(); - if (!assetItems.Any()) return; + var entries = ((IList) parameters[1]).Cast().ToArray(); + if (!entries.Any()) return; - var updateUi = assetItems.Length > 1 ? EBulkType.Auto : EBulkType.None; + var updateUi = entries.Length > 1 ? EBulkType.Auto : EBulkType.None; await _threadWorkerView.Begin(cancellationToken => { switch (trigger) { case "Assets_Extract_New_Tab": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.Extract(cancellationToken, asset, true); + contextViewModel.CUE4Parse.Extract(cancellationToken, entry, true); } break; case "Assets_Show_Metadata": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.ShowMetadata(asset); + contextViewModel.CUE4Parse.ShowMetadata(entry); } break; case "Assets_Export_Data": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.ExportData(asset); + contextViewModel.CUE4Parse.ExportData(entry); } break; case "Assets_Save_Properties": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Properties | updateUi); + contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Properties | updateUi); } break; case "Assets_Save_Textures": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Textures | updateUi); + contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Textures | updateUi); } break; case "Assets_Save_Models": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Meshes | updateUi); + contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Meshes | updateUi); } break; case "Assets_Save_Animations": - foreach (var asset in assetItems) + foreach (var entry in entries) { Thread.Yield(); cancellationToken.ThrowIfCancellationRequested(); - contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Animations | updateUi); + contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, EBulkType.Animations | updateUi); } break; } diff --git a/FModel/ViewModels/Commands/TabCommand.cs b/FModel/ViewModels/Commands/TabCommand.cs index 7cc50ad1..5abbc4e3 100644 --- a/FModel/ViewModels/Commands/TabCommand.cs +++ b/FModel/ViewModels/Commands/TabCommand.cs @@ -32,44 +32,44 @@ public override async void Execute(TabItem contextViewModel, object parameter) _applicationView.CUE4Parse.TabControl.RemoveOtherTabs(contextViewModel); break; case "Asset_Export_Data": - await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.Asset)); + await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.Entry)); break; case "Asset_Save_Properties": await _threadWorkerView.Begin(cancellationToken => { - _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Properties); + _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Properties); }); break; case "Asset_Save_Textures": await _threadWorkerView.Begin(cancellationToken => { - _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Textures); + _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Textures); }); break; case "Asset_Save_Models": await _threadWorkerView.Begin(cancellationToken => { - _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Meshes); + _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Meshes); }); break; case "Asset_Save_Animations": await _threadWorkerView.Begin(cancellationToken => { - _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Animations); + _applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Animations); }); break; case "Open_Properties": - if (contextViewModel.Asset.FileName == "New Tab" || contextViewModel.Document == null) return; - Helper.OpenWindow(contextViewModel.Asset.FileName + " (Properties)", () => + if (contextViewModel.Entry.Name == "New Tab" || contextViewModel.Document == null) return; + Helper.OpenWindow(contextViewModel.Entry.Name + " (Properties)", () => { new PropertiesPopout(contextViewModel) { - Title = contextViewModel.Asset.FileName + " (Properties)" + Title = contextViewModel.Entry.Name + " (Properties)" }.Show(); }); break; case "Copy_Asset_Path": - Clipboard.SetText(contextViewModel.Asset.FullPath); + Clipboard.SetText(contextViewModel.Entry.Path); break; } } diff --git a/FModel/ViewModels/SearchViewModel.cs b/FModel/ViewModels/SearchViewModel.cs index 426d0d6e..15585911 100644 --- a/FModel/ViewModels/SearchViewModel.cs +++ b/FModel/ViewModels/SearchViewModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows.Data; +using CUE4Parse.FileProvider.Objects; using FModel.Framework; namespace FModel.ViewModels; @@ -32,12 +33,12 @@ public bool HasMatchCaseEnabled } public int ResultsCount => SearchResults?.Count ?? 0; - public RangeObservableCollection SearchResults { get; } + public RangeObservableCollection SearchResults { get; } public ICollectionView SearchResultsView { get; } public SearchViewModel() { - SearchResults = new RangeObservableCollection(); + SearchResults = new RangeObservableCollection(); SearchResultsView = new ListCollectionView(SearchResults); } @@ -51,14 +52,14 @@ public void RefreshFilter() private bool ItemFilter(object item, IEnumerable filters) { - if (item is not AssetItem assetItem) + if (item is not GameFile entry) return true; if (!HasRegexEnabled) - return filters.All(x => assetItem.FullPath.Contains(x, HasMatchCaseEnabled ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)); + return filters.All(x => entry.Path.Contains(x, HasMatchCaseEnabled ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)); var o = RegexOptions.None; if (!HasMatchCaseEnabled) o |= RegexOptions.IgnoreCase; - return new Regex(FilterText, o).Match(assetItem.FullPath).Success; + return new Regex(FilterText, o).Match(entry.Path).Success; } } diff --git a/FModel/ViewModels/TabControlViewModel.cs b/FModel/ViewModels/TabControlViewModel.cs index e48da67b..1eda1e1c 100644 --- a/FModel/ViewModels/TabControlViewModel.cs +++ b/FModel/ViewModels/TabControlViewModel.cs @@ -8,7 +8,6 @@ using ICSharpCode.AvalonEdit.Highlighting; using Serilog; using SkiaSharp; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; @@ -16,6 +15,7 @@ using System.Windows.Media.Imaging; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse_Conversion.Textures; +using CUE4Parse.FileProvider.Objects; using CUE4Parse.Utils; namespace FModel.ViewModels; @@ -93,11 +93,11 @@ public class TabItem : ViewModel { public string ParentExportType { get; private set; } - private AssetItem _asset; - public AssetItem Asset + private GameFile _entry; + public GameFile Entry { - get => _asset; - set => SetProperty(ref _asset, value); + get => _entry; + set => SetProperty(ref _entry, value); } private bool _hasSearchOpen; @@ -209,16 +209,16 @@ public TabImage SelectedImage private GoToCommand _goToCommand; public GoToCommand GoToCommand => _goToCommand ??= new GoToCommand(null); - public TabItem(AssetItem asset, string parentExportType) + public TabItem(GameFile entry, string parentExportType) { - Asset = asset; + Entry = entry; ParentExportType = parentExportType; _images = new ObservableCollection(); } - public void SoftReset(AssetItem asset) + public void SoftReset(GameFile entry) { - Asset = asset; + Entry = entry; ParentExportType = string.Empty; ScrollTrigger = null; Application.Current.Dispatcher.Invoke(() => @@ -306,7 +306,7 @@ private void SaveImage(TabImage image, bool updateUi) var fileName = image.ExportName + ext; var path = Path.Combine(UserSettings.Default.TextureDirectory, - UserSettings.Default.KeepDirectoryStructure ? Asset.Directory : "", fileName!).Replace('\\', '/'); + UserSettings.Default.KeepDirectoryStructure ? Entry.Directory : "", fileName!).Replace('\\', '/'); Directory.CreateDirectory(path.SubstringBeforeLast('/')); @@ -327,9 +327,9 @@ private void SaveImage(TabImage image, string path) public void SaveProperty(bool updateUi) { - var fileName = Path.ChangeExtension(Asset.FileName, ".json"); + var fileName = Path.ChangeExtension(Entry.Name, ".json"); var directory = Path.Combine(UserSettings.Default.PropertiesDirectory, - UserSettings.Default.KeepDirectoryStructure ? Asset.Directory : "", fileName).Replace('\\', '/'); + UserSettings.Default.KeepDirectoryStructure ? Entry.Directory : "", fileName).Replace('\\', '/'); Directory.CreateDirectory(directory.SubstringBeforeLast('/')); @@ -386,21 +386,19 @@ public TabControlViewModel() } public void AddTab() => AddTab("New Tab"); - public void AddTab(string title) => AddTab(new AssetItem(title)); - public void AddTab(AssetItem asset, string parentExportType = null) + public void AddTab(string title) => AddTab(new FakeGameFile(title)); + public void AddTab(GameFile entry, string parentExportType = null) { - if (!CanAddTabs) return; - - var p = parentExportType ?? string.Empty; - if (SelectedTab?.Asset.FileName == "New Tab") + if (SelectedTab?.Entry.Name == "New Tab") { - SelectedTab.Asset = asset; + SelectedTab.Entry = entry; return; } + if (!CanAddTabs) return; Application.Current.Dispatcher.Invoke(() => { - _tabItems.Add(new TabItem(asset, p)); + _tabItems.Add(new TabItem(entry, parentExportType ?? string.Empty)); SelectedTab = _tabItems.Last(); }); } diff --git a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs index d46721fc..bc5fdab8 100644 --- a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs +++ b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs @@ -119,7 +119,7 @@ private void OnTextChanged(object sender, EventArgs e) if (sender is not TextEditor avalonEditor || DataContext is not TabItem tabItem || avalonEditor.Document == null || string.IsNullOrEmpty(avalonEditor.Document.Text)) return; - avalonEditor.Document.FileName = tabItem.Asset.FullPath.SubstringBeforeLast('.'); + avalonEditor.Document.FileName = tabItem.Entry.PathWithoutExtension; if (!_savedCarets.ContainsKey(avalonEditor.Document.FileName)) _ignoreCaret = true; diff --git a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs index c2331100..3bb5a275 100644 --- a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs +++ b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs @@ -24,7 +24,7 @@ public PropertiesPopout(TabItem contextViewModel) MyAvalonEditor.Document = new TextDocument { Text = contextViewModel.Document.Text, - FileName = contextViewModel.Asset.FullPath.SubstringBeforeLast('.') + FileName = contextViewModel.Entry.PathWithoutExtension }; MyAvalonEditor.FontSize = contextViewModel.FontSize; MyAvalonEditor.SyntaxHighlighting = contextViewModel.Highlighter; diff --git a/FModel/Views/Resources/Converters/FileExtensionEqualsConverter.cs b/FModel/Views/Resources/Converters/FileExtensionEqualsConverter.cs deleted file mode 100644 index 114e136e..00000000 --- a/FModel/Views/Resources/Converters/FileExtensionEqualsConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; - -namespace FModel.Views.Resources.Converters; - -public class FileExtensionEqualsConverter : IValueConverter -{ - public static readonly FileExtensionEqualsConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value.ToString().EndsWith(parameter.ToString()); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/FModel/Views/Resources/Converters/FullPathToFileConverter.cs b/FModel/Views/Resources/Converters/FullPathToFileConverter.cs deleted file mode 100644 index 347ec234..00000000 --- a/FModel/Views/Resources/Converters/FullPathToFileConverter.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using CUE4Parse.Utils; - -namespace FModel.Views.Resources.Converters; - -public class FullPathToFileConverter : IValueConverter -{ - public static readonly FullPathToFileConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value.ToString().SubstringAfterLast('/'); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index a1a2f8de..0a4af432 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -203,7 +203,7 @@ - @@ -596,19 +596,19 @@ - + - + - + - + - + @@ -651,7 +651,7 @@ - + @@ -856,7 +856,10 @@ - + + + + @@ -913,7 +916,7 @@ - + diff --git a/FModel/Views/SearchView.xaml b/FModel/Views/SearchView.xaml index 340b2584..3a454383 100644 --- a/FModel/Views/SearchView.xaml +++ b/FModel/Views/SearchView.xaml @@ -96,14 +96,14 @@ - + - + @@ -155,7 +155,14 @@ - + + + + diff --git a/FModel/Views/SearchView.xaml.cs b/FModel/Views/SearchView.xaml.cs index 2be09d65..2c4c866c 100644 --- a/FModel/Views/SearchView.xaml.cs +++ b/FModel/Views/SearchView.xaml.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using CUE4Parse.FileProvider.Objects; using FModel.Services; using FModel.ViewModels; @@ -30,12 +31,12 @@ private void OnDeleteSearchClick(object sender, RoutedEventArgs e) private async void OnAssetDoubleClick(object sender, RoutedEventArgs e) { - if (SearchListView.SelectedItem is not AssetItem assetItem) + if (SearchListView.SelectedItem is not GameFile entry) return; WindowState = WindowState.Minimized; MainWindow.YesWeCats.AssetsListName.ItemsSource = null; - var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(assetItem.Directory); + var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(entry.Directory); if (folder == null) return; MainWindow.YesWeCats.Activate(); @@ -46,18 +47,18 @@ private async void OnAssetDoubleClick(object sender, RoutedEventArgs e) do { await Task.Delay(100); - MainWindow.YesWeCats.AssetsListName.SelectedItem = assetItem; - MainWindow.YesWeCats.AssetsListName.ScrollIntoView(assetItem); + MainWindow.YesWeCats.AssetsListName.SelectedItem = entry; + MainWindow.YesWeCats.AssetsListName.ScrollIntoView(entry); } while (MainWindow.YesWeCats.AssetsListName.SelectedItem == null); } private async void OnAssetExtract(object sender, RoutedEventArgs e) { - if (SearchListView.SelectedItem is not AssetItem assetItem) + if (SearchListView.SelectedItem is not GameFile entry) return; WindowState = WindowState.Minimized; - await _threadWorkerView.Begin(cancellationToken => _applicationView.CUE4Parse.Extract(cancellationToken, assetItem, true)); + await _threadWorkerView.Begin(cancellationToken => _applicationView.CUE4Parse.Extract(cancellationToken, entry, true)); MainWindow.YesWeCats.Activate(); }