mirror of
https://github.com/4sval/FModel.git
synced 2026-04-25 07:21:54 -05:00
Merge pull request #564 from Masusder/dev
Some checks are pending
FModel QA Builder / build (push) Waiting to run
Some checks are pending
FModel QA Builder / build (push) Waiting to run
Support for audio events from Wwise soundbanks
This commit is contained in:
commit
4a9a44139d
|
|
@ -1 +1 @@
|
|||
Subproject commit 7bf781ffd8871c48fdca8be86576b313e023ce7c
|
||||
Subproject commit 3a333f2d95ec77ce162ea80ab05be0b279e43807
|
||||
|
|
@ -30,6 +30,21 @@ public class CustomDirectory : ViewModel
|
|||
new("Shop Backgrounds", "ShooterGame/Content/UI/OutOfGame/MainMenu/Store/Shared/Textures/"),
|
||||
new("Weapon Renders", "ShooterGame/Content/UI/Screens/OutOfGame/MainMenu/Collection/Assets/Large/")
|
||||
};
|
||||
case "Dead by Daylight":
|
||||
return new List<CustomDirectory>
|
||||
{
|
||||
new("Characters V1", "DeadByDaylight/Plugins/DBDCharacters/"),
|
||||
new("Characters V2", "DeadByDaylight/Plugins/Runtime/Bhvr/DBDCharacters/"),
|
||||
new("Characters (Deprecated)", "DeadbyDaylight/Content/Characters/"),
|
||||
new("Meshes", "DeadByDaylight/Content/Meshes/"),
|
||||
new("Textures", "DeadByDaylight/Content/Textures/"),
|
||||
new("Icons", "DeadByDaylight/Content/UI/UMGAssets/Icons/"),
|
||||
new("Blueprints", "DeadByDaylight/Content/Blueprints/"),
|
||||
new("Audio Events", "DeadByDaylight/Content/Audio/Events/"),
|
||||
new("Audio", "DeadByDaylight/Content/WwiseAudio/Cooked/"),
|
||||
new("Data Tables", "DeadByDaylight/Content/Data/"),
|
||||
new("Localization", "DeadByDaylight/Content/Localization/")
|
||||
};
|
||||
default:
|
||||
return new List<CustomDirectory>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -439,6 +439,13 @@ 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -78,6 +78,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
set => SetProperty(ref _modelIsOverwritingMaterial, value);
|
||||
}
|
||||
|
||||
private bool _modelIsWaitingAnimation;
|
||||
public bool ModelIsWaitingAnimation
|
||||
{
|
||||
get => _modelIsWaitingAnimation;
|
||||
set => SetProperty(ref _modelIsWaitingAnimation, value);
|
||||
}
|
||||
|
||||
public bool IsSnooperOpen => _snooper is { Exists: true, IsVisible: true };
|
||||
private Snooper _snooper;
|
||||
public Snooper SnooperViewer
|
||||
|
|
@ -117,6 +124,8 @@ public class CUE4ParseViewModel : ViewModel
|
|||
public SearchViewModel SearchVm { get; }
|
||||
public TabControlViewModel TabControl { get; }
|
||||
public ConfigIni IoStoreOnDemand { get; }
|
||||
private Lazy<WwiseProvider> _wwiseProviderLazy;
|
||||
public WwiseProvider WwiseProvider => _wwiseProviderLazy.Value;
|
||||
|
||||
public CUE4ParseViewModel()
|
||||
{
|
||||
|
|
@ -266,6 +275,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
|
||||
Provider.Initialize();
|
||||
_wwiseProviderLazy = new Lazy<WwiseProvider>(() => new WwiseProvider(Provider, UserSettings.Default.WwiseMaxBnkPrefetch));
|
||||
Log.Information($"{Provider.Versions.Game} ({Provider.Versions.Platform}) | Archives: x{Provider.UnloadedVfs.Count} | AES: x{Provider.RequiredKeys.Count} | Loose Files: x{Provider.Files.Count}");
|
||||
});
|
||||
}
|
||||
|
|
@ -670,9 +680,11 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var archive = entry.CreateReader();
|
||||
var wwise = new WwiseReader(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi);
|
||||
foreach (var (name, data) in wwise.WwiseEncodedMedias)
|
||||
|
||||
var medias = WwiseProvider.ExtractBankSounds(wwise);
|
||||
foreach (var media in medias)
|
||||
{
|
||||
SaveAndPlaySound(entry.Path.SubstringBeforeWithLast('/') + name, "WEM", data);
|
||||
SaveAndPlaySound(media.OutputPath, media.Extension, media.Data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -852,22 +864,12 @@ public class CUE4ParseViewModel : ViewModel
|
|||
TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi);
|
||||
return false;
|
||||
}
|
||||
case UAkAudioEvent when isNone && pointer.Object.Value is UAkAudioEvent { EventCookedData: { } wwiseData }:
|
||||
case UAkAudioEvent when isNone && pointer.Object.Value is UAkAudioEvent audioEvent:
|
||||
{
|
||||
foreach (var kvp in wwiseData.EventLanguageMap)
|
||||
var extractedSounds = WwiseProvider.ExtractAudioEventSounds(audioEvent);
|
||||
foreach (var sound in extractedSounds)
|
||||
{
|
||||
if (!kvp.Value.HasValue) continue;
|
||||
|
||||
foreach (var media in kvp.Value.Value.Media)
|
||||
{
|
||||
if (!Provider.TrySaveAsset(Path.Combine("Game/WwiseAudio/", media.MediaPathName.Text), out var data)) continue;
|
||||
|
||||
var namedPath = string.Concat(
|
||||
Provider.ProjectName, "/Content/WwiseAudio/",
|
||||
media.DebugName.Text.SubstringBeforeLast('.').Replace('\\', '/'),
|
||||
" (", kvp.Key.LanguageName.Text, ")");
|
||||
SaveAndPlaySound(namedPath, media.MediaPathName.Text.SubstringAfterLast('.'), data);
|
||||
}
|
||||
SaveAndPlaySound(sound.OutputPath, sound.Extension, sound.Data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -914,7 +916,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
SnooperViewer.Run();
|
||||
return true;
|
||||
}
|
||||
case UAnimSequenceBase when isNone && UserSettings.Default.PreviewAnimations || SnooperViewer.Renderer.Options.ModelIsWaitingAnimation:
|
||||
case UAnimSequenceBase when isNone && UserSettings.Default.PreviewAnimations || ModelIsWaitingAnimation:
|
||||
{
|
||||
// animate all animations using their specified skeleton or when we explicitly asked for a loaded model to be animated (ignoring whether we wanted to preview animations)
|
||||
SnooperViewer.Renderer.Animate(pointer.Object.Value);
|
||||
|
|
@ -961,7 +963,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
|
||||
private void SaveAndPlaySound(string fullPath, string ext, byte[] data)
|
||||
{
|
||||
if (fullPath.StartsWith("/")) fullPath = fullPath[1..];
|
||||
if (fullPath.StartsWith('/')) fullPath = fullPath[1..];
|
||||
var savedAudioPath = Path.Combine(UserSettings.Default.AudioDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? fullPath : fullPath.SubstringAfterLast('/')).Replace('\\', '/') + $".{ext.ToLowerInvariant()}";
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public class GameSelectorViewModel : ViewModel
|
|||
yield return GetUnrealEngineGame("9361c8c6d2f34b42b5f2f61093eedf48", "\\TslGame\\Content\\Paks", EGame.GAME_PlayerUnknownsBattlegrounds);
|
||||
yield return GetRiotGame("VALORANT", "ShooterGame\\Content\\Paks", EGame.GAME_Valorant);
|
||||
yield return DirectorySettings.Default("VALORANT [LIVE]", Constants._VAL_LIVE_TRIGGER, ue: EGame.GAME_Valorant);
|
||||
yield return GetSteamGame(381210, "\\DeadByDaylight\\Content\\Paks", EGame.GAME_UE4_27); // Dead By Daylight
|
||||
yield return GetSteamGame(381210, "\\DeadByDaylight\\Content\\Paks", EGame.GAME_DeadByDaylight, aesKey: "0x22b1639b548124925cf7b9cbaa09f9ac295fcf0324586d6b37ee1d42670b39b3"); // Dead By Daylight
|
||||
yield return GetSteamGame(578080, "\\TslGame\\Content\\Paks", EGame.GAME_PlayerUnknownsBattlegrounds); // PUBG
|
||||
yield return GetSteamGame(1172380, "\\SwGame\\Content\\Paks", EGame.GAME_StarWarsJediFallenOrder); // STAR WARS Jedi: Fallen Order™
|
||||
yield return GetSteamGame(677620, "\\PortalWars\\Content\\Paks", EGame.GAME_Splitgate); // Splitgate
|
||||
|
|
@ -151,13 +151,13 @@ public class GameSelectorViewModel : ViewModel
|
|||
return null;
|
||||
}
|
||||
|
||||
private DirectorySettings GetSteamGame(int id, string pakDirectory, EGame ueVersion)
|
||||
private DirectorySettings GetSteamGame(int id, string pakDirectory, EGame ueVersion, string aesKey = "")
|
||||
{
|
||||
var steamInfo = SteamDetection.GetSteamGameById(id);
|
||||
if (steamInfo is not null)
|
||||
{
|
||||
Log.Debug("Found {GameName} in steam manifests", steamInfo.Name);
|
||||
return DirectorySettings.Default(steamInfo.Name, $"{steamInfo.GameRoot}{pakDirectory}", ue: ueVersion);
|
||||
return DirectorySettings.Default(steamInfo.Name, $"{steamInfo.GameRoot}{pakDirectory}", ue: ueVersion, aes: aesKey);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:FModel"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
|
@ -227,6 +228,11 @@
|
|||
<TextBlock Grid.Row="17" Grid.Column="0" Text="Serialize Inlined Shader Maps" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="17" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ReadShaderMaps, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"/>
|
||||
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Text="Max Wwise Bank (.BNK) Prefetch" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<Slider Grid.Row="18" Grid.Column="2" Grid.ColumnSpan="5" TickPlacement="None" Minimum="0" Maximum="512" Ticks="0,2,4,8,16,32,64,128,256,512"
|
||||
AutoToolTipPlacement="BottomRight" IsMoveToPointEnabled="True" IsSnapToTickEnabled="True" Margin="0 5 0 5"
|
||||
Value="{Binding WwiseMaxBnkPrefetch, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="CreatorTemplate">
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ namespace FModel.Views.Snooper;
|
|||
public class Options
|
||||
{
|
||||
public FGuid SelectedModel { get; private set; }
|
||||
public bool ModelIsWaitingAnimation { get; private set; }
|
||||
public int SelectedSection { get; private set; }
|
||||
public int SelectedMorph { get; private set; }
|
||||
public int SelectedAnimation{ get; private set; }
|
||||
|
|
@ -238,7 +237,7 @@ public class Options
|
|||
|
||||
public void AnimateMesh(bool value)
|
||||
{
|
||||
ModelIsWaitingAnimation = value;
|
||||
Services.ApplicationService.ApplicationView.CUE4Parse.ModelIsWaitingAnimation = value;
|
||||
}
|
||||
|
||||
public void ResetModelsLightsAnimations()
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ public class Renderer : IDisposable
|
|||
|
||||
public void Animate(UObject anim)
|
||||
{
|
||||
if (!Options.ModelIsWaitingAnimation)
|
||||
if (!Services.ApplicationService.ApplicationView.CUE4Parse.ModelIsWaitingAnimation)
|
||||
{
|
||||
if (anim is UAnimSequenceBase animBase)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -624,6 +624,9 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGui.SeparatorText("Manual Inputs");
|
||||
model.Transforms[model.SelectedInstance].ImGuiTransform(s.Renderer.CameraOp.Speed / 100f);
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -48,5 +49,55 @@ public class Transform
|
|||
ModifyLocal(_saved.Value);
|
||||
}
|
||||
|
||||
public void ImGuiTransform(float speed)
|
||||
{
|
||||
const float width = 100f;
|
||||
|
||||
if (ImGui.TreeNode("Position"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Position.X, speed, 0f, 0f, "%.2f m");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Position.Y, speed, 0f, 0f, "%.2f m");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Position.Z, speed, 0f, 0f, "%.2f m");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
if (ImGui.TreeNode("Rotation"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("W", ref Rotation.W, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Rotation.X, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Rotation.Y, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Rotation.Z, .005f, 0f, 0f, "%.3f rad");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
if (ImGui.TreeNode("Scale"))
|
||||
{
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("X", ref Scale.X, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Y", ref Scale.Y, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
ImGui.DragFloat("Z", ref Scale.Z, speed, 0f, 0f, "%.3f");
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Matrix.Translation.ToString();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user