Skip to content
7 changes: 7 additions & 0 deletions FModel/Settings/UserSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,13 @@ public Hotkey AddAudio
set => SetProperty(ref _addAudio, value);
}

private Hotkey _removeAudio = new(Key.X);
public Hotkey RemoveAudio
{
get => _removeAudio;
set => SetProperty(ref _removeAudio, value);
}

private Hotkey _playPauseAudio = new(Key.K);
public Hotkey PlayPauseAudio
{
Expand Down
38 changes: 38 additions & 0 deletions FModel/ViewModels/AudioPlayerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,20 @@ public void Load()
});
}

public void Unload()
{
Application.Current.Dispatcher.Invoke(() =>
{
_waveSource = null;

PlayedFile = new AudioFile(-1, "No audio file");
Spectrum = null;

RaiseSourceEvent(ESourceEventType.Clearing);
ClearSoundOut();
});
}

public void AddToPlaylist(byte[] data, string filePath)
{
Application.Current.Dispatcher.Invoke(() =>
Expand Down Expand Up @@ -270,11 +284,30 @@ public void Remove()
if (_audioFiles.Count < 1) return;
Application.Current.Dispatcher.Invoke(() =>
{
var removedPlaying = false;
if (PlayedFile.Id == SelectedAudioFile.Id)
{
removedPlaying = true;
Stop();
}

_audioFiles.RemoveAt(SelectedAudioFile.Id);
for (var i = 0; i < _audioFiles.Count; i++)
{
_audioFiles[i].Id = i;
}

if (_audioFiles.Count < 1)
{
Unload();
return;
}

SelectedAudioFile = _audioFiles[SelectedAudioFile.Id];

if (!removedPlaying) return;
Load();
Play();
});
}

Expand Down Expand Up @@ -526,6 +559,11 @@ private void LoadSoundOut()
_soundOut.Volume = UserSettings.Default.AudioPlayerVolume / 100;
}

private void ClearSoundOut()
{
_soundOut = null;
}

private IEnumerable<MMDevice> EnumerateDevices()
{
using var deviceEnumerator = new MMDeviceEnumerator();
Expand Down
29 changes: 29 additions & 0 deletions FModel/ViewModels/Commands/RightClickMenuCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public override async void Execute(ApplicationViewModel contextViewModel, object
if (param.Length == 0) return;

var folders = param.OfType<TreeItem>().ToArray();
var searchMenu = param[0] is GameFile;
var assets = param
.Select(static item => item switch
{
Expand Down Expand Up @@ -138,6 +139,20 @@ await _threadWorkerView.Begin(cancellationToken =>
_ => (entry, bulk, update) => contextViewModel.CUE4Parse.Extract(cancellationToken, entry, false, bulk),
};

if (searchMenu)
{
var update = assets.Length > 1;
foreach (var entry in assets)
{
Thread.Yield();
cancellationToken.ThrowIfCancellationRequested();
fileAction(entry, bulktype, update);
}

if (assets.Length > 50) LogExport(contextViewModel, filetype);
return;
}

foreach (var group in assetsGroups)
{
var directory = group.Key;
Expand Down Expand Up @@ -190,4 +205,18 @@ private void LogExport(ApplicationViewModel contextViewModel, string directory,
Interlocked.Exchange(ref contextViewModel.CUE4Parse.ExportedCount, 0);
Interlocked.Exchange(ref contextViewModel.CUE4Parse.FailedExportCount, 0);
}

private void LogExport(ApplicationViewModel contextViewModel, string fileType)
{
if (contextViewModel.CUE4Parse.ExportedCount > 0)
{
FLogger.Append(ELog.Information, () =>
{
FLogger.Text($"Successfully exported {contextViewModel.CUE4Parse.ExportedCount} {fileType}, Failed to export {contextViewModel.CUE4Parse.FailedExportCount} {fileType} in other folders.", Constants.WHITE, true);
});
}

Interlocked.Exchange(ref contextViewModel.CUE4Parse.ExportedCount, 0);
Interlocked.Exchange(ref contextViewModel.CUE4Parse.FailedExportCount, 0);
}
}
20 changes: 19 additions & 1 deletion FModel/ViewModels/Commands/TabCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@ public override async void Execute(TabItem tabViewModel, object parameter)
case "Close_Other_Tabs":
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(tabViewModel);
break;
case "Assets_Show_Metadata":
_applicationView.CUE4Parse.ShowMetadata(tabViewModel.Entry);
break;
case "Find_References":
_applicationView.CUE4Parse.FindReferences(tabViewModel.Entry);
break;
case "Assets_Decompile":
_applicationView.CUE4Parse.Decompile(tabViewModel.Entry);
break;
case "Save_Data":
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(tabViewModel.Entry));
break;
Expand Down Expand Up @@ -77,9 +83,21 @@ await _threadWorkerView.Begin(cancellationToken =>
}.Show();
});
break;
case "Copy_Asset_Path":
case "File_Path":
Clipboard.SetText(tabViewModel.Entry.Path);
break;
case "File_Name":
Clipboard.SetText(tabViewModel.Entry.Name);
break;
case "Directory_Path":
Clipboard.SetText(tabViewModel.Entry.Directory);
break;
case "File_Path_No_Extension":
Clipboard.SetText(tabViewModel.Entry.PathWithoutExtension);
break;
case "File_Name_No_Extension":
Clipboard.SetText(tabViewModel.Entry.NameWithoutExtension);
break;
}
}
}
24 changes: 20 additions & 4 deletions FModel/ViewModels/GameSelectorViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,27 @@ private bool TryDetectUeVersion(string gameDirectory, out EGame ueVersion, [Mayb
}
}

var crashReportClientExe = Path.Combine(projectDir, "..", "Engine", "Binaries", "Win64", "CrashReportClient.exe");
if (File.Exists(crashReportClientExe) && TryGetUeVersionFromExe(crashReportClientExe, out ueVersion))
var projectEngineBinariesDir = Path.Combine(projectDir, "..", "Engine", "Binaries", "Win64");

if (Directory.Exists(projectEngineBinariesDir))
{
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, crashReportClientExe);
return true;
var crashReportClientExe = Path.Combine(projectEngineBinariesDir, "CrashReportClient.exe");
if (File.Exists(crashReportClientExe) && TryGetUeVersionFromExe(crashReportClientExe, out ueVersion))
{
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, crashReportClientExe);
return true;
}
if (Directory.GetFiles(projectEngineBinariesDir, "*-Win64-Shipping.exe") is { Length: > 0 } shipping)
{
foreach (var exe in shipping)
{
if (TryGetUeVersionFromExe(exe, out ueVersion))
{
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, exe);
return true;
}
}
}
}

ueVersion = EGame.GAME_UE4_LATEST;
Expand Down
2 changes: 1 addition & 1 deletion FModel/ViewModels/TabControlViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ private void SaveCheck(string path, string fileName, bool updateUi)
{
Interlocked.Increment(ref ApplicationService.ApplicationView.CUE4Parse.ExportedCount);
Log.Information("{FileName} successfully saved", fileName);
if (updateUi)
if (updateUi && ApplicationService.ApplicationView.CUE4Parse.ExportedCount < 50)
{
FLogger.Append(ELog.Information, () =>
{
Expand Down
2 changes: 2 additions & 0 deletions FModel/Views/AudioPlayer.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ private void OnPreviewKeyDown(object sender, KeyEventArgs e)
_applicationView.AudioPlayer.Previous();
else if (UserSettings.Default.NextAudio.IsTriggered(e.Key))
_applicationView.AudioPlayer.Next();
else if (UserSettings.Default.RemoveAudio.IsTriggered(e.Key))
_applicationView.AudioPlayer.Remove();
}

private void OnAudioFileMouseDoubleClick(object sender, MouseButtonEventArgs e)
Expand Down
5 changes: 3 additions & 2 deletions FModel/Views/Resources/Controls/Aup/SourceEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ namespace FModel.Views.Resources.Controls.Aup;

public enum ESourceEventType
{
Loading
Loading,
Clearing
}

public class SourceEventArgs : EventArgs
Expand All @@ -15,4 +16,4 @@ public SourceEventArgs(ESourceEventType e)
{
Event = e;
}
}
}
61 changes: 60 additions & 1 deletion FModel/Views/Resources/Resources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,26 @@
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Show Metadata" Command="{Binding TabCommand}" CommandParameter="Assets_Show_Metadata">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemIsUePackageCondition />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
</MenuItem>
<MenuItem Header="Find References" Command="{Binding TabCommand}" CommandParameter="Find_References">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
Expand All @@ -931,6 +951,35 @@
</Binding>
</MenuItem.IsEnabled>
</MenuItem>
<MenuItem Header="Decompile Blueprint" Command="{Binding TabCommand}" CommandParameter="Assets_Decompile">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CppIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowDecompileOption, Source={x:Static settings:UserSettings.Default}}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
<MenuItem.IsEnabled>
<Binding Path="PlacementTarget.SelectedItems" RelativeSource="{RelativeSource AncestorType=ContextMenu}">
<Binding.Converter>
<converters:AnyItemMeetsConditionConverter>
<converters:AnyItemMeetsConditionConverter.Conditions>
<converters:ItemActionCondition Action="Code" />
</converters:AnyItemMeetsConditionConverter.Conditions>
</converters:AnyItemMeetsConditionConverter>
</Binding.Converter>
</Binding>
</MenuItem.IsEnabled>
</MenuItem>
<Separator />
<MenuItem Command="{Binding TabCommand}" CommandParameter="Save_Data">
<MenuItem.Header>
Expand Down Expand Up @@ -1010,14 +1059,24 @@
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Copy Package Path" Command="{Binding TabCommand}" CommandParameter="Copy_Asset_Path">
<MenuItem Header="Copy">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
<MenuItem Header="Package Path" Command="{Binding TabCommand}" CommandParameter="File_Path">
</MenuItem>
<MenuItem Header="Package Name" Command="{Binding TabCommand}" CommandParameter="File_Name">
</MenuItem>
<MenuItem Header="Directory Path" Command="{Binding TabCommand}" CommandParameter="Directory_Path">
</MenuItem>
<MenuItem Header="Package Path w/o Extension" Command="{Binding TabCommand}" CommandParameter="File_Path_No_Extension">
</MenuItem>
<MenuItem Header="Package Name w/o Extension" Command="{Binding TabCommand}" CommandParameter="File_Name_No_Extension">
</MenuItem>
</MenuItem>
</ContextMenu>
</Setter.Value>
Expand Down
30 changes: 30 additions & 0 deletions FModel/Views/SearchView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Show Metadata" Command="{Binding DataContext.mainApplication.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Show_Metadata" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Find References" Click="OnFindRefs">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
Expand Down Expand Up @@ -529,6 +544,21 @@
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Show Metadata" Command="{Binding DataContext.mainApplication.RightClickMenuCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
<Binding Source="Assets_Show_Metadata" />
<Binding Path="SelectedItems" />
</MultiBinding>
</MenuItem.CommandParameter>
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Find References" Click="OnFindRefs">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
Expand Down
4 changes: 4 additions & 0 deletions FModel/Views/SettingsView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand Down Expand Up @@ -602,6 +603,9 @@
<TextBlock Grid.Row="12" Grid.Column="0" Text="Next Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="12" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding NextAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
<TextBlock Grid.Row="13" Grid.Column="0" Text="Remove Selected Audio" VerticalAlignment="Center" Margin="0 0 0 5" />
<controls:HotkeyTextBox Grid.Row="13" Grid.Column="2" Style="{StaticResource TextBoxDefaultStyle}" Margin="0 0 0 5"
HotKey="{Binding RemoveAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</ResourceDictionary>
Expand Down