diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index bca1427d..68a6c775 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -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 { diff --git a/FModel/ViewModels/AudioPlayerViewModel.cs b/FModel/ViewModels/AudioPlayerViewModel.cs index 9821e915..c56fa96f 100644 --- a/FModel/ViewModels/AudioPlayerViewModel.cs +++ b/FModel/ViewModels/AudioPlayerViewModel.cs @@ -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(() => @@ -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(); }); } @@ -526,6 +559,11 @@ private void LoadSoundOut() _soundOut.Volume = UserSettings.Default.AudioPlayerVolume / 100; } + private void ClearSoundOut() + { + _soundOut = null; + } + private IEnumerable EnumerateDevices() { using var deviceEnumerator = new MMDeviceEnumerator(); diff --git a/FModel/ViewModels/Commands/RightClickMenuCommand.cs b/FModel/ViewModels/Commands/RightClickMenuCommand.cs index b490957c..28e50f7b 100644 --- a/FModel/ViewModels/Commands/RightClickMenuCommand.cs +++ b/FModel/ViewModels/Commands/RightClickMenuCommand.cs @@ -43,6 +43,7 @@ public override async void Execute(ApplicationViewModel contextViewModel, object if (param.Length == 0) return; var folders = param.OfType().ToArray(); + var searchMenu = param[0] is GameFile; var assets = param .Select(static item => item switch { @@ -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; @@ -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); + } } diff --git a/FModel/ViewModels/Commands/TabCommand.cs b/FModel/ViewModels/Commands/TabCommand.cs index a622d5e4..2867f87a 100644 --- a/FModel/ViewModels/Commands/TabCommand.cs +++ b/FModel/ViewModels/Commands/TabCommand.cs @@ -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; @@ -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; } } } diff --git a/FModel/ViewModels/GameSelectorViewModel.cs b/FModel/ViewModels/GameSelectorViewModel.cs index 369945b2..6447e2d7 100644 --- a/FModel/ViewModels/GameSelectorViewModel.cs +++ b/FModel/ViewModels/GameSelectorViewModel.cs @@ -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; diff --git a/FModel/ViewModels/TabControlViewModel.cs b/FModel/ViewModels/TabControlViewModel.cs index dbeb4423..7f18c1e7 100644 --- a/FModel/ViewModels/TabControlViewModel.cs +++ b/FModel/ViewModels/TabControlViewModel.cs @@ -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, () => { diff --git a/FModel/Views/AudioPlayer.xaml.cs b/FModel/Views/AudioPlayer.xaml.cs index 332b6101..f65660ce 100644 --- a/FModel/Views/AudioPlayer.xaml.cs +++ b/FModel/Views/AudioPlayer.xaml.cs @@ -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) diff --git a/FModel/Views/Resources/Controls/Aup/SourceEventArgs.cs b/FModel/Views/Resources/Controls/Aup/SourceEventArgs.cs index 102546ea..964638b7 100644 --- a/FModel/Views/Resources/Controls/Aup/SourceEventArgs.cs +++ b/FModel/Views/Resources/Controls/Aup/SourceEventArgs.cs @@ -4,7 +4,8 @@ namespace FModel.Views.Resources.Controls.Aup; public enum ESourceEventType { - Loading + Loading, + Clearing } public class SourceEventArgs : EventArgs @@ -15,4 +16,4 @@ public SourceEventArgs(ESourceEventType e) { Event = e; } -} \ No newline at end of file +} diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index c33eb148..ce77bf5c 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -910,6 +910,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -931,6 +951,35 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -1010,7 +1059,7 @@ - + @@ -1018,6 +1067,16 @@ + + + + + + + + + + diff --git a/FModel/Views/SearchView.xaml b/FModel/Views/SearchView.xaml index 9e3a1f93..defa4853 100644 --- a/FModel/Views/SearchView.xaml +++ b/FModel/Views/SearchView.xaml @@ -161,6 +161,21 @@ + + + + + + + + + + + + + + + @@ -529,6 +544,21 @@ + + + + + + + + + + + + + + + diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index b38b62d5..d08606ec 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -556,6 +556,7 @@ + @@ -602,6 +603,9 @@ + +