mirror of
https://github.com/4sval/FModel.git
synced 2026-05-05 20:36:46 -05:00
Update WwiseProvider for FDeferredByteData, counting failed exports
Co-authored-by: Masusder <59669685+Masusder@users.noreply.github.com>
This commit is contained in:
parent
fd4051b163
commit
8e66371fca
|
|
@ -1 +1 @@
|
|||
Subproject commit dc0f8183f6551f9b5bccc8aecee65807362ef297
|
||||
Subproject commit df263631dbb96469f8f0316d74f4904c51f439ed
|
||||
|
|
@ -454,13 +454,6 @@ namespace FModel.Settings
|
|||
set => SetProperty(ref _cameraMode, value);
|
||||
}
|
||||
|
||||
private int _wwiseMaxBnkPrefetch;
|
||||
public int WwiseMaxBnkPrefetch
|
||||
{
|
||||
get => _wwiseMaxBnkPrefetch;
|
||||
set => SetProperty(ref _wwiseMaxBnkPrefetch, value);
|
||||
}
|
||||
|
||||
private int _previewMaxTextureSize = 1024;
|
||||
public int PreviewMaxTextureSize
|
||||
{
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
public ConcurrentBag<string> UnknownExtensions = [];
|
||||
|
||||
public int ExportedCount;
|
||||
public int FailedExportCount;
|
||||
|
||||
public CUE4ParseViewModel()
|
||||
{
|
||||
|
|
@ -324,7 +325,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
|
||||
Provider.Initialize();
|
||||
_wwiseProviderLazy = new Lazy<WwiseProvider>(() => new WwiseProvider(Provider, UserSettings.Default.GameDirectory, UserSettings.Default.WwiseMaxBnkPrefetch));
|
||||
_wwiseProviderLazy = new Lazy<WwiseProvider>(() => new WwiseProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
_fmodProviderLazy = new Lazy<FModProvider>(() => new FModProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
_criWareProviderLazy = new Lazy<CriWareProvider>(() => new CriWareProvider(Provider, UserSettings.Default.GameDirectory));
|
||||
Log.Information($"{Provider.Versions.Game} ({Provider.Versions.Platform}) | Archives: x{Provider.UnloadedVfs.Count} | AES: x{Provider.RequiredKeys.Count} | Loose Files: x{Provider.Files.Count}");
|
||||
|
|
@ -601,7 +602,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
|
||||
public void ExtractFolder(CancellationToken cancellationToken, TreeItem folder, EBulkType bulk)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, bulk));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, bulk));
|
||||
|
||||
public void ExtractFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs));
|
||||
|
|
@ -807,13 +808,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "pck":
|
||||
{
|
||||
var archive = entry.CreateReader();
|
||||
var wwise = new WwiseReader(archive);
|
||||
var wwise = new WwiseReader(archive, new WwiseGameFileSource(entry));
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
var medias = WwiseProvider.ExtractBankSounds(wwise);
|
||||
foreach (var media in medias)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, media.OutputPath, media.Extension, media.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, media.OutputPath, media.Extension, media.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -1120,7 +1121,8 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case UExternalSource when (isNone || saveAudio) && pointer.Object.Value is UExternalSource externalSource:
|
||||
{
|
||||
var audioName = Path.GetFileNameWithoutExtension(externalSource.ExternalSourcePath);
|
||||
SaveAndPlaySound(cancellationToken, audioName, "wem", externalSource.Data?.WemFile ?? [], saveAudio, updateUi);
|
||||
var outputPath = Path.Combine(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/').SubstringBeforeLast('/'), audioName);
|
||||
SaveAndPlaySound(cancellationToken, outputPath, "wem", externalSource.Data?.WemFile?.GetData() ?? [], saveAudio, updateUi);
|
||||
return false;
|
||||
}
|
||||
case UAkAudioBank when (isNone || saveAudio) && pointer.Object.Value is UAkAudioBank soundBank:
|
||||
|
|
@ -1128,7 +1130,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var extractedSounds = WwiseProvider.ExtractBankSounds(soundBank);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1137,7 +1139,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var extractedSounds = WwiseProvider.ExtractAudioEventSounds(audioEvent);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1202,12 +1204,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case UAkMediaAsset when (isNone || saveAudio) && pointer.Object.Value is UAkMediaAsset akMediaAsset:
|
||||
{
|
||||
var audioName = akMediaAsset.MediaName ?? akMediaAsset.Name;
|
||||
if (akMediaAsset.CurrentMediaAssetData?.TryLoad<UAkMediaAssetData>(out var akMediaAssetData) is true)
|
||||
var outputPath = Path.Combine(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/').SubstringBeforeLast('/'), audioName);
|
||||
if (akMediaAsset.CurrentMediaAssetData?.ResolvedObject?.Object?.Value is UAkMediaAssetData akMediaAssetData)
|
||||
{
|
||||
var shouldDecompress = UserSettings.Default.CompressedAudioMode is ECompressedAudio.PlayDecompressed;
|
||||
akMediaAssetData.Decode(shouldDecompress, out var audioFormat, out var data);
|
||||
|
||||
SaveAndPlaySound(cancellationToken, audioName, audioFormat, data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, outputPath, audioFormat, data, saveAudio, updateUi);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1216,14 +1219,15 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var shouldDecompress = UserSettings.Default.CompressedAudioMode is ECompressedAudio.PlayDecompressed;
|
||||
foreach (var mediaIndex in akAudioEventData.MediaList)
|
||||
{
|
||||
if (mediaIndex.TryLoad<UAkMediaAsset>(out var akMediaAsset))
|
||||
if (mediaIndex.ResolvedObject?.Object?.Value is UAkMediaAsset akMediaAsset)
|
||||
{
|
||||
if (akMediaAsset.CurrentMediaAssetData?.TryLoad<UAkMediaAssetData>(out var akMediaAssetData) is true)
|
||||
if (akMediaAsset.CurrentMediaAssetData?.ResolvedObject?.Object?.Value is UAkMediaAssetData akMediaAssetData)
|
||||
{
|
||||
var audioName = akMediaAsset.MediaName ?? $"{akAudioEventData.Outer.Name} ({akMediaAsset.ID})";
|
||||
var outputPath = Path.Combine(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/').SubstringBeforeLast('/'), audioName);
|
||||
akMediaAssetData.Decode(shouldDecompress, out var audioFormat, out var data);
|
||||
|
||||
SaveAndPlaySound(cancellationToken, audioName, audioFormat, data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, outputPath, audioFormat, data, saveAudio, updateUi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1235,7 +1239,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var extractedSounds = WwiseProvider.ExtractDialogBorderlands3(dialogPerformanceData);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1245,12 +1249,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
if (Provider.Versions.Game is not EGame.GAME_Borderlands4)
|
||||
return false;
|
||||
|
||||
var ownerDirectory = WwiseProvider.GetOwnerDirectory(faceFXAnimSet);
|
||||
foreach (var faceFXAnimData in faceFXAnimSet.FaceFXAnimDataList)
|
||||
{
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventBorderlands4(faceFXAnimData.ID.Name, false);
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventBorderlands4(ownerDirectory, faceFXAnimData.ID.Name, false);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1259,12 +1264,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
// Borderlands 4
|
||||
case UGbxGraphAsset when (isNone || saveAudio) && pointer.Object.Value is UGbxGraphAsset gbxGraphAsset:
|
||||
{
|
||||
var ownerDirectory = WwiseProvider.GetOwnerDirectory(gbxGraphAsset);
|
||||
foreach (var (eventName, useSoundTag) in GbxAudioUtil.GetAndClearEvents())
|
||||
{
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventBorderlands4(eventName, useSoundTag);
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventBorderlands4(ownerDirectory, eventName, useSoundTag);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data, saveAudio, updateUi);
|
||||
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1404,28 +1410,33 @@ public class CUE4ParseViewModel : ViewModel
|
|||
TabControl.SelectedTab.SetDocumentText(cpp, false, false);
|
||||
}
|
||||
|
||||
private void SaveAndPlaySound(CancellationToken cancellationToken, string fullPath, string ext, byte[] data, bool isBulk, bool updateUi)
|
||||
private void SaveAndPlaySound(CancellationToken cancellationToken, string fullPath, string ext, byte[] data, bool saveAudio, bool updateUi)
|
||||
{
|
||||
if (fullPath.StartsWith('/')) fullPath = fullPath[1..];
|
||||
var savedAudioPath = Path.Combine(UserSettings.Default.AudioDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? fullPath : fullPath.SubstringAfterLast('/')).Replace('\\', '/') + $".{ext.ToLowerInvariant()}";
|
||||
|
||||
if (isBulk)
|
||||
if (saveAudio)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Directory.CreateDirectory(savedAudioPath.SubstringBeforeLast('/'));
|
||||
using var stream = new FileStream(savedAudioPath, FileMode.Create, FileAccess.Write);
|
||||
using (var writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(data);
|
||||
writer.Flush();
|
||||
}
|
||||
var directory = Path.GetDirectoryName(savedAudioPath);
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
bool conversionSuccess = true;
|
||||
if (UserSettings.Default.ConvertAudioOnBulkExport)
|
||||
{
|
||||
conversionSuccess = AudioPlayerViewModel.TryConvert(savedAudioPath, data, out string wavFilePath);
|
||||
if (conversionSuccess) savedAudioPath = wavFilePath;
|
||||
if (AudioPlayerViewModel.TryConvert(savedAudioPath, data, out string wavFilePath))
|
||||
savedAudioPath = wavFilePath;
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref FailedExportCount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using var stream = new FileStream(savedAudioPath, FileMode.Create, FileAccess.Write);
|
||||
stream.Write(data);
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref ExportedCount);
|
||||
|
|
@ -1475,6 +1486,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref FailedExportCount);
|
||||
Log.Error("{FileName} could not be saved", export.Name);
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not save '{export.Name}'", Constants.WHITE, true));
|
||||
}
|
||||
|
|
@ -1509,6 +1521,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref FailedExportCount);
|
||||
Log.Error("{FileName} could not be exported", entry.Name);
|
||||
if (updateUi)
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not export '{entry.Name}'", Constants.WHITE, true));
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
};
|
||||
|
||||
Interlocked.Exchange(ref contextViewModel.CUE4Parse.ExportedCount, 0);
|
||||
Interlocked.Exchange(ref contextViewModel.CUE4Parse.FailedExportCount, 0);
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
if (action is EAction.Show)
|
||||
|
|
@ -167,15 +168,24 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
FLogger.Link(directory, Path.Exists(path) ? path : basePath, true);
|
||||
});
|
||||
}
|
||||
else
|
||||
else if (contextViewModel.CUE4Parse.FailedExportCount == 0)
|
||||
{
|
||||
// Not an error because folder simply might not contain type of asset user is trying to save
|
||||
FLogger.Append(ELog.Warning, () =>
|
||||
{
|
||||
FLogger.Text($"Failed to export any {fileType} from {directory}", Constants.WHITE, true);
|
||||
FLogger.Text($"Failed to find any {fileType} in {directory}", Constants.WHITE, true);
|
||||
});
|
||||
}
|
||||
|
||||
if (contextViewModel.CUE4Parse.FailedExportCount > 0)
|
||||
{
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text($"Failed to export {contextViewModel.CUE4Parse.FailedExportCount} {fileType} from {directory}", Constants.WHITE, true);
|
||||
});
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref contextViewModel.CUE4Parse.ExportedCount, 0);
|
||||
Interlocked.Exchange(ref contextViewModel.CUE4Parse.FailedExportCount, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,8 +376,7 @@ public class TabItem : ViewModel
|
|||
public void SaveImage() => SaveImage(SelectedImage, true);
|
||||
private void SaveImage(TabImage image, bool updateUi)
|
||||
{
|
||||
if (image == null)
|
||||
return;
|
||||
if (image is null) return;
|
||||
|
||||
var path = Path.Combine(UserSettings.Default.TextureDirectory, UserSettings.Default.KeepDirectoryStructure ? Entry.Directory : "", image.ExportName).Replace('\\', '/');
|
||||
|
||||
|
|
@ -394,6 +393,7 @@ public class TabItem : ViewModel
|
|||
|
||||
private void SaveImage(TabImage image, string path)
|
||||
{
|
||||
if (image.ImageBuffer is null) return;
|
||||
using var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
fs.Write(image.ImageBuffer, 0, image.ImageBuffer.Length);
|
||||
}
|
||||
|
|
@ -427,6 +427,7 @@ public class TabItem : ViewModel
|
|||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref ApplicationService.ApplicationView.CUE4Parse.FailedExportCount);
|
||||
Log.Error("{FileName} could not be saved", fileName);
|
||||
if (updateUi)
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not save '{fileName}'", Constants.WHITE, true));
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
|
@ -249,19 +248,14 @@
|
|||
Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Text="Max Wwise Bank (.BNK) Prefetch" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<Slider Grid.Row="20" Grid.Column="2" Grid.ColumnSpan="5" TickPlacement="None" Minimum="0" Maximum="2048" Ticks="0,8,32,128,256,512,1024,2048"
|
||||
AutoToolTipPlacement="BottomRight" IsMoveToPointEnabled="True" IsSnapToTickEnabled="True" Margin="0 5 0 5"
|
||||
Value="{Binding WwiseMaxBnkPrefetch, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="21"
|
||||
<TextBlock Grid.Row="20"
|
||||
Grid.Column="0"
|
||||
Text="CRIWARE Decryption Key"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 10" />
|
||||
|
||||
<TextBox x:Name="CriwareKeyBox"
|
||||
Grid.Row="21"
|
||||
Grid.Row="20"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="5"
|
||||
Margin="0 5 0 10"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user