Criware decrypt key setting / HCA decoder

This commit is contained in:
Masusder
2025-11-07 16:42:41 +01:00
parent 879b5a2ce8
commit 2888c9261c
7 changed files with 152 additions and 32 deletions

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Versions;
@@ -24,7 +24,8 @@ public class DirectorySettings : ViewModel, ICloneable
Endpoints = old?.Endpoints ?? EndpointSettings.Default(gameName),
Directories = old?.Directories ?? CustomDirectory.Default(gameName),
AesKeys = old?.AesKeys ?? new AesResponse { MainKey = aes, DynamicKeys = null },
LastAesReload = old?.LastAesReload ?? DateTime.Today.AddDays(-1)
LastAesReload = old?.LastAesReload ?? DateTime.Today.AddDays(-1),
CriwareDecryptionKey = old?.CriwareDecryptionKey ?? 0
};
}
@@ -98,6 +99,13 @@ public class DirectorySettings : ViewModel, ICloneable
set => SetProperty(ref _lastAesReload, value);
}
private ulong _criwareDecryptionKey;
public ulong CriwareDecryptionKey
{
get => _criwareDecryptionKey;
set => SetProperty(ref _criwareDecryptionKey, value);
}
private bool Equals(DirectorySettings other)
{
return GameDirectory == other.GameDirectory && UeVersion == other.UeVersion;

View File

@@ -1,7 +1,3 @@
using CSCore;
using CSCore.DSP;
using CSCore.SoundOut;
using CSCore.Streams;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -12,7 +8,12 @@ using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Data;
using CSCore;
using CSCore.CoreAudioAPI;
using CSCore.DSP;
using CSCore.SoundOut;
using CSCore.Streams;
using CUE4Parse.UE4.CriWare.Decoders.HCA;
using CUE4Parse.Utils;
using FModel.Extensions;
using FModel.Framework;
@@ -569,7 +570,6 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
case "wem":
case "at9":
case "raw":
case "hca":
{
if (TryConvert(out var wavFilePath))
{
@@ -580,6 +580,37 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
return false;
}
case "hca":
{
try
{
byte[] wavData = HcaWaveStream.ConvertHcaToWav(SelectedAudioFile.Data, UserSettings.Default.CurrentDir.CriwareDecryptionKey);
string outputDir = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
Directory.CreateDirectory(outputDir);
string wavFilePath = Path.Combine(outputDir,
Path.ChangeExtension(SelectedAudioFile.FileName, ".wav"));
File.WriteAllBytes(wavFilePath, wavData);
var newAudio = new AudioFile(SelectedAudioFile.Id, new FileInfo(wavFilePath));
Replace(newAudio);
return true;
}
catch (CriwareDecryptionException ex)
{
FLogger.Append(ELog.Error, () => FLogger.Text($"Failed to convert HCA: '{ex.Message}'", Constants.WHITE, true));
Log.Error($"Failed to convert HCA: {ex.Message}");
return false;
}
catch (Exception ex)
{
Log.Error($"Failed to convert HCA: {ex.Message}");
return false;
}
}
case "rada":
case "binka":
{

View File

@@ -777,34 +777,33 @@ public class CUE4ParseViewModel : ViewModel
break;
}
case "awb":
{
var archive = entry.CreateReader();
var awbReader = new AwbReader(archive);
var extractedSounds = CriWareProvider.ExtractCriWareSounds(awbReader, archive.Name);
foreach (var sound in extractedSounds)
{
var archive = entry.CreateReader();
var awbReader = new AwbReader(archive);
var extractedSounds = CriWareProvider.ExtractCriWareSounds(awbReader, archive.Name);
foreach (var sound in extractedSounds)
{
SaveAndPlaySound(Path.Combine("/Criware/", sound.Name), sound.Extension, sound.Data, saveAudio);
}
break;
SaveAndPlaySound(Path.Combine("/Criware/", sound.Name), sound.Extension, sound.Data, saveAudio);
}
break;
}
case "acb":
{
var archive = entry.CreateReader();
var acbReader = new AcbReader(archive);
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(acbReader, Formatting.Indented), saveProperties, updateUi);
var extractedSounds = CriWareProvider.ExtractCriWareSounds(acbReader, archive.Name);
foreach (var sound in extractedSounds)
{
var archive = entry.CreateReader();
var acbReader = new AcbReader(archive);
SaveAndPlaySound(Path.Combine("/Criware/", sound.Name), sound.Extension, sound.Data, saveAudio);
}
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(acbReader, Formatting.Indented), saveProperties, updateUi);
var extractedSounds = CriWareProvider.ExtractCriWareSounds(acbReader, archive.Name);
foreach (var sound in extractedSounds)
{
SaveAndPlaySound(Path.Combine("/Criware/", sound.Name), sound.Extension, sound.Data, saveAudio);
}
break;
}
break;
}
case "xvag":
case "flac":
case "at9":

View File

@@ -2,14 +2,14 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Objects.Core.Serialization;
using CUE4Parse.UE4.Versions;
using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Textures;
using CUE4Parse_Conversion.UEFormat.Enums;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using FModel.Framework;
using FModel.Services;
using FModel.Settings;
@@ -165,6 +165,13 @@ public class SettingsViewModel : ViewModel
set => SetProperty(ref _selectedTextureExportFormat, value);
}
private ulong _criwareDecryptionKey;
public ulong CriwareDecryptionKey
{
get => _criwareDecryptionKey;
set => SetProperty(ref _criwareDecryptionKey, value);
}
public bool SocketSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.ActorX;
public bool CompressionSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.UEFormat;
@@ -227,6 +234,7 @@ public class SettingsViewModel : ViewModel
_customVersionsSnapshot = UserSettings.Default.CurrentDir.Versioning.CustomVersions;
_optionsSnapshot = UserSettings.Default.CurrentDir.Versioning.Options;
_mapStructTypesSnapshot = UserSettings.Default.CurrentDir.Versioning.MapStructTypes;
_criwareDecryptionKey = UserSettings.Default.CurrentDir.CriwareDecryptionKey;
AesEndpoint = UserSettings.Default.CurrentDir.Endpoints[0];
MappingEndpoint = UserSettings.Default.CurrentDir.Endpoints[1];
@@ -262,6 +270,7 @@ public class SettingsViewModel : ViewModel
SelectedNaniteMeshExportFormat = _naniteMeshExportFormatSnapshot;
SelectedMaterialExportFormat = _materialExportFormatSnapshot;
SelectedTextureExportFormat = _textureExportFormatSnapshot;
CriwareDecryptionKey = _criwareDecryptionKey;
SelectedAesReload = UserSettings.Default.AesReload;
SelectedDiscordRpc = UserSettings.Default.DiscordRpc;
@@ -308,6 +317,7 @@ public class SettingsViewModel : ViewModel
UserSettings.Default.CurrentDir.Versioning.CustomVersions = SelectedCustomVersions;
UserSettings.Default.CurrentDir.Versioning.Options = SelectedOptions;
UserSettings.Default.CurrentDir.Versioning.MapStructTypes = SelectedMapStructTypes;
UserSettings.Default.CurrentDir.CriwareDecryptionKey = CriwareDecryptionKey;
UserSettings.Default.AssetLanguage = SelectedAssetLanguage;
UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio;

View File

@@ -46,6 +46,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -238,6 +239,26 @@
<Slider Grid.Row="19" 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="20"
Grid.Column="0"
Text="CRIWARE Decryption Key"
VerticalAlignment="Center"
Margin="0 0 0 10" />
<TextBox x:Name="CriwareKeyBox"
Grid.Row="20"
Grid.Column="2"
Grid.ColumnSpan="5"
Margin="0 5 0 10"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
MaxLength="20"
ToolTip="Enter decryption key in numeric or hexadecimal format (valid key is up to 20 digits or 8 bytes long)"
TextAlignment="Right"
TextChanged="CriwareKeyBox_TextChanged"
Loaded="CriwareKeyBox_Loaded"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="CreatorTemplate">

View File

@@ -1,4 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using FModel.Services;
@@ -190,4 +193,52 @@ public partial class SettingsView
_applicationView.SettingsView.MappingEndpoint, "Endpoint Configuration (Mapping)", EEndpointType.Mapping);
editor.ShowDialog();
}
private void CriwareKeyBox_Loaded(object sender, RoutedEventArgs e)
{
if (sender is not TextBox textBox)
return;
textBox.Text = _applicationView.SettingsView.CriwareDecryptionKey.ToString();
}
private void CriwareKeyBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (sender is not TextBox textBox)
return;
string input = textBox.Text?.Trim() ?? string.Empty;
if (string.IsNullOrEmpty(input))
return;
if (TryParseKey(input, out ulong parsed))
_applicationView.SettingsView.CriwareDecryptionKey = parsed;
}
private static bool TryParseKey(string text, out ulong value)
{
value = 0;
if (string.IsNullOrWhiteSpace(text))
return false;
bool isHex = false;
if (text.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
isHex = true;
text = text[2..];
}
else if (text.Any(char.IsLetter))
{
isHex = true;
}
int numberBase = text.All(Uri.IsHexDigit) ? 16 : 10;
return ulong.TryParse(
text,
isHex ? NumberStyles.HexNumber : NumberStyles.Integer,
CultureInfo.InvariantCulture,
out value
);
}
}