C4P pull + other random stuff

This commit is contained in:
Asval 2025-08-04 21:27:07 +02:00
parent af4435e444
commit b71c25606a
6 changed files with 67 additions and 85 deletions

@ -1 +1 @@
Subproject commit 48c7cbbfe032ba1a2745d81c96d578718348a775
Subproject commit 81c08002501539309b23946688ed1e613f3d43e7

View File

@ -31,7 +31,6 @@ using CUE4Parse.UE4.Localization;
using CUE4Parse.UE4.Objects.Core.Serialization;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Oodle.Objects;
using CUE4Parse.UE4.Pak;
using CUE4Parse.UE4.Readers;
using CUE4Parse.UE4.Shaders;
using CUE4Parse.UE4.Versions;
@ -63,12 +62,7 @@ using SkiaSharp;
using UE4Config.Parsing;
using Application = System.Windows.Application;
using FGuid = CUE4Parse.UE4.Objects.Core.Misc.FGuid;
using CUE4Parse.UE4.Assets.Objects;
using CUE4Parse.UE4.Kismet;
using CUE4Parse.UE4.Objects.Core.Math;
using CUE4Parse.UE4.Objects.GameplayTags;
using System.Text;
using AssetRipper.TextureDecoder.Rgb;
using CUE4Parse.UE4.Objects.UObject.Editor;
namespace FModel.ViewModels;
@ -77,12 +71,10 @@ public class CUE4ParseViewModel : ViewModel
{
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
private readonly Regex _fnLiveRegex = new(@"^FortniteGame[/\\]Content[/\\]Paks[/\\]",
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private bool _modelIsOverwritingMaterial;
public bool ModelIsOverwritingMaterial
{
get => _modelIsOverwritingMaterial;
@ -98,7 +90,6 @@ public class CUE4ParseViewModel : ViewModel
public bool IsSnooperOpen => _snooper is { Exists: true, IsVisible: true };
private Snooper _snooper;
public Snooper SnooperViewer
{
get
@ -501,7 +492,6 @@ public class CUE4ParseViewModel : ViewModel
}
private int _virtualPathCount { get; set; }
public Task LoadVirtualPaths()
{
if (_virtualPathCount > 0) return Task.CompletedTask;
@ -1022,21 +1012,19 @@ public class CUE4ParseViewModel : ViewModel
TabControl.SelectedTab.TitleExtra = "Decompiled";
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("cpp");
var pkg = Provider.LoadPackage(entry);
string editorPath = Path.Combine(Path.GetDirectoryName(entry.Path)!, $"{Path.GetFileNameWithoutExtension(entry.Path)}.o.uasset");
UObject meta = null;
UClassCookedMetaData cookedMetaData = null;
try
{
Provider.TryGetGameFile(editorPath, out var metaGame);
var editorPkg = Provider.LoadPackage(metaGame);
meta = editorPkg.GetExport("CookedClassMetaData", StringComparison.InvariantCultureIgnoreCase);
var editorPkg = Provider.LoadPackage(entry.Path.Replace(".uasset", ".o.uasset"));
cookedMetaData = editorPkg.GetExport<UClassCookedMetaData>("CookedClassMetaData");
}
catch
{
// ignored
}
catch (Exception e) {}
var cppList = new List<string>();
var pkg = Provider.LoadPackage(entry);
for (var i = 0; i < pkg.ExportMapLength; i++)
{
var pointer = new FPackageIndex(pkg, i + 1).ResolvedObject;
@ -1047,13 +1035,10 @@ public class CUE4ParseViewModel : ViewModel
if (dummy is not UClass || pointer.Object.Value is not UClass blueprint)
continue;
cppList.Add(blueprint.DecompileBlueprintToPseudo(meta));
cppList.Add(blueprint.DecompileBlueprintToPseudo(cookedMetaData));
}
var cpp = cppList.Count > 1
? string.Join("\n\n", cppList)
: cppList.FirstOrDefault() ?? string.Empty;
var cpp = cppList.Count > 1 ? string.Join("\n\n", cppList) : cppList.FirstOrDefault() ?? string.Empty;
if (entry.Path.Contains("_Verse.uasset"))
{
cpp = Regex.Replace(cpp, "__verse_0x[a-fA-F0-9]{8}_", ""); // UnmangleCasedName

View File

@ -4,29 +4,11 @@ using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Data;
using System.Windows.Input;
using CUE4Parse.FileProvider.Objects;
using FModel.Framework;
namespace FModel.ViewModels;
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func<bool>? _canExecute;
public event EventHandler? CanExecuteChanged;
public RelayCommand(Action execute, Func<bool>? canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true;
public void Execute(object? parameter) => _execute();
}
public class SearchViewModel : ViewModel
{
public enum ESortSizeMode
@ -64,22 +46,6 @@ public class SearchViewModel : ViewModel
set => SetProperty(ref _currentSortSizeMode, value);
}
public void CycleSortSizeMode()
{
CurrentSortSizeMode = CurrentSortSizeMode switch
{
ESortSizeMode.None => ESortSizeMode.Ascending,
ESortSizeMode.Ascending => ESortSizeMode.Descending,
ESortSizeMode.Descending => ESortSizeMode.None,
_ => ESortSizeMode.None
};
RefreshFilter();
}
private RelayCommand? _sortSizeModeCommand;
public ICommand SortSizeModeCommand => _sortSizeModeCommand ??= new RelayCommand(CycleSortSizeMode);
public int ResultsCount => SearchResults?.Count ?? 0;
public RangeObservableCollection<GameFile> SearchResults { get; }
public ICollectionView SearchResultsView { get; }
@ -87,23 +53,38 @@ public class SearchViewModel : ViewModel
public SearchViewModel()
{
SearchResults = new RangeObservableCollection<GameFile>();
SearchResultsView = new ListCollectionView(SearchResults);
SearchResultsView = new ListCollectionView(SearchResults)
{
Filter = e => ItemFilter(e, FilterText?.Trim().Split(' ') ?? []),
};
}
public void RefreshFilter()
{
if (!string.IsNullOrEmpty(FilterText))
SearchResultsView.Filter = e => ItemFilter(e, FilterText.Trim().Split(' '));
else
SearchResultsView.Refresh();
SearchResultsView.Refresh();
}
SearchResultsView.SortDescriptions.Clear();
public void CycleSortSizeMode()
{
CurrentSortSizeMode = CurrentSortSizeMode switch
{
ESortSizeMode.None => ESortSizeMode.Descending,
ESortSizeMode.Descending => ESortSizeMode.Ascending,
_ => ESortSizeMode.None
};
if (CurrentSortSizeMode != ESortSizeMode.None)
SearchResultsView.SortDescriptions.Add(new SortDescription(nameof(GameFile.Size),
CurrentSortSizeMode == ESortSizeMode.Ascending
using (SearchResultsView.DeferRefresh())
{
SearchResultsView.SortDescriptions.Clear();
if (CurrentSortSizeMode != ESortSizeMode.None)
{
var sort = CurrentSortSizeMode == ESortSizeMode.Ascending
? ListSortDirection.Ascending
: ListSortDirection.Descending));
: ListSortDirection.Descending;
SearchResultsView.SortDescriptions.Add(new SortDescription(nameof(GameFile.Size), sort));
}
}
}
private bool ItemFilter(object item, IEnumerable<string> filters)
@ -118,4 +99,4 @@ public class SearchViewModel : ViewModel
if (!HasMatchCaseEnabled) o |= RegexOptions.IgnoreCase;
return new Regex(FilterText, o).Match(entry.Path).Success;
}
}
}

View File

@ -292,8 +292,14 @@ public class SettingsViewModel : ViewModel
whatShouldIDo.Add(SettingsOut.ReloadMappings);
if (_ueGameSnapshot != SelectedUeGame || _customVersionsSnapshot != SelectedCustomVersions ||
_optionsSnapshot != SelectedOptions || // combobox
_uePlatformSnapshot != SelectedUePlatform || _optionsSnapshot != SelectedOptions || // combobox
_mapStructTypesSnapshot != SelectedMapStructTypes ||
_outputSnapshot != UserSettings.Default.OutputDirectory || // textbox
_rawDataSnapshot != UserSettings.Default.RawDataDirectory || // textbox
_propertiesSnapshot != UserSettings.Default.PropertiesDirectory || // textbox
_textureSnapshot != UserSettings.Default.TextureDirectory || // textbox
_audioSnapshot != UserSettings.Default.AudioDirectory || // textbox
_modelSnapshot != UserSettings.Default.ModelDirectory || // textbox
_gameSnapshot != UserSettings.Default.GameDirectory) // textbox
restart = true;

View File

@ -58,14 +58,6 @@
</TextBox.Style>
</TextBox>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button ToolTip="Sort File Sizes" Padding="5" Command="{Binding CUE4Parse.SearchVm.SortSizeModeCommand}" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SortIcon}" />
</Canvas>
</Viewbox>
</Button>
<ToggleButton ToolTip="Match Case" Padding="5" IsChecked="{Binding CUE4Parse.SearchVm.HasMatchCaseEnabled}" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarToggleButton}}">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
@ -80,6 +72,13 @@
</Canvas>
</Viewbox>
</ToggleButton>
<Button ToolTip="Sort File Sizes" Padding="5" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" Click="OnSortClick">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SortIcon}" />
</Canvas>
</Viewbox>
</Button>
<Button ToolTip="Clear Search Filter" Padding="5" Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" Click="OnDeleteSearchClick">
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
@ -88,8 +87,14 @@
</Viewbox>
</Button>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding CUE4Parse.SearchVm.ResultsCount, FallbackValue=0, StringFormat={}{0:### ### ###} Loaded Packages}"
VerticalAlignment="Center" HorizontalAlignment="Right" FontStyle="Italic"/>
<TextBlock Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="10 0 0 0" FontStyle="Italic">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:### ### ###} Loaded Packages ({1})">
<Binding Path="CUE4Parse.SearchVm.ResultsCount" FallbackValue="0" />
<Binding Path="CUE4Parse.SearchVm.CurrentSortSizeMode" FallbackValue="None" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
<ListView Grid.Row="1" x:Name="SearchListView" VirtualizingPanel.IsVirtualizing="True" ItemsSource="{Binding CUE4Parse.SearchVm.SearchResultsView, IsAsync=True}">

View File

@ -29,6 +29,11 @@ public partial class SearchView
_applicationView.CUE4Parse.SearchVm.RefreshFilter();
}
private void OnSortClick(object sender, RoutedEventArgs e)
{
_applicationView.CUE4Parse.SearchVm.CycleSortSizeMode();
}
private async void OnAssetDoubleClick(object sender, RoutedEventArgs e)
{
if (SearchListView.SelectedItem is not GameFile entry)
@ -38,14 +43,14 @@ public partial class SearchView
MainWindow.YesWeCats.AssetsListName.ItemsSource = null;
var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(entry.Directory);
if (folder == null) return;
MainWindow.YesWeCats.Activate();
do { await Task.Delay(100); } while (MainWindow.YesWeCats.AssetsListName.Items.Count < folder.AssetsList.Assets.Count);
while (!folder.IsSelected || MainWindow.YesWeCats.AssetsFolderName.SelectedItem != folder)
await Task.Delay(50); // stops assets tab from opening too early
MainWindow.YesWeCats.LeftTabControl.SelectedIndex = 2; // assets tab
do
{