From 6b0b5dc8586da7a3c53dd02db110b4affb7c3c1b Mon Sep 17 00:00:00 2001 From: Pear <61670316+Pear-231@users.noreply.github.com> Date: Sat, 29 Mar 2025 20:12:36 +0000 Subject: [PATCH 01/54] Change Notes: - Fixed a bug where actions were only processing single sound targets rather than containers where necessary. - Fixed a bug where OverrideBusID was set unnecessarily. --- .../CompilerDataProcessor.cs | 9 ++++-- .../Hirc/V136/SoundHircGenerator_V136.cs | 31 ++++++++++--------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Editors/Audio/AudioProjectCompiler/CompilerDataProcessor.cs b/Editors/Audio/AudioProjectCompiler/CompilerDataProcessor.cs index 2c3611038..f0856216e 100644 --- a/Editors/Audio/AudioProjectCompiler/CompilerDataProcessor.cs +++ b/Editors/Audio/AudioProjectCompiler/CompilerDataProcessor.cs @@ -187,22 +187,27 @@ public void CreateStopActionEvents(AudioProject audioProject) } } - // TODO: Need some way to handle play and stop actions so that they reference the same sound if they used the same sound and the rest of the event name is the same public void SetActionData(AudioProject audioProject) { foreach (var soundBank in audioProject.SoundBanks) { foreach (var actionEvent in soundBank.ActionEvents) { - var action = new Action { ID = AudioProjectCompilerHelpers.GenerateUnusedHircID(UsedHircIdsByLanguageIDLookup, actionEvent.Sound.Language) }; + var action = new Action(); if (actionEvent.Name.StartsWith("Stop_")) action.ActionType = AkActionType.Stop_E_O; if (actionEvent.Sound != null) + { + action.ID = AudioProjectCompilerHelpers.GenerateUnusedHircID(UsedHircIdsByLanguageIDLookup, actionEvent.Sound.Language); action.IDExt = actionEvent.Sound.ID; + } else + { + action.ID = AudioProjectCompilerHelpers.GenerateUnusedHircID(UsedHircIdsByLanguageIDLookup, actionEvent.RandomSequenceContainer.Language); action.IDExt = actionEvent.RandomSequenceContainer.ID; + } actionEvent.Actions = [action]; diff --git a/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/SoundHircGenerator_V136.cs b/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/SoundHircGenerator_V136.cs index a8cd231f5..9ca999b64 100644 --- a/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/SoundHircGenerator_V136.cs +++ b/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/SoundHircGenerator_V136.cs @@ -47,6 +47,9 @@ private static AkBankSourceData_V136 CreateAkBankSourceData(Sound audioProjectSo private static NodeBaseParams_V136 CreateNodeBaseParams(Sound audioProjectSound) { + // A workaround for figuring out whether the Action Event / Dialogue Event involved is targetting a single sound or a container. + var soundIsTarget = audioProjectSound.AudioSettings != null; + var nodeBaseParams = new NodeBaseParams_V136(); nodeBaseParams.NodeInitialFxParams = new NodeInitialFxParams_V136() { @@ -54,43 +57,43 @@ private static NodeBaseParams_V136 CreateNodeBaseParams(Sound audioProjectSound) NumFx = 0, }; nodeBaseParams.OverrideAttachmentParams = 0; - nodeBaseParams.OverrideBusID = audioProjectSound.OverrideBusID; + nodeBaseParams.OverrideBusID = soundIsTarget ? audioProjectSound.OverrideBusID : 0; nodeBaseParams.DirectParentID = audioProjectSound.DirectParentID; nodeBaseParams.BitVector = 0; nodeBaseParams.NodeInitialParams = new NodeInitialParams_V136(); - if (audioProjectSound.AudioSettings.LoopingType == LoopingType.FiniteLooping) + if (soundIsTarget && audioProjectSound.AudioSettings.LoopingType == LoopingType.FiniteLooping) { nodeBaseParams.NodeInitialParams.AkPropBundle0 = new AkPropBundle_V136() { PropsList = new List + { + new AkPropBundle_V136.PropBundleInstance_V136 { - new AkPropBundle_V136.PropBundleInstance_V136 - { - ID = AkPropId_V136.Loop, - Value = audioProjectSound.AudioSettings.NumberOfLoops - } + ID = AkPropId_V136.Loop, + Value = audioProjectSound.AudioSettings.NumberOfLoops } + } }; } - else if (audioProjectSound.AudioSettings.LoopingType == LoopingType.InfiniteLooping) + else if (soundIsTarget && audioProjectSound.AudioSettings.LoopingType == LoopingType.InfiniteLooping) { nodeBaseParams.NodeInitialParams.AkPropBundle0 = new AkPropBundle_V136() { PropsList = new List + { + new AkPropBundle_V136.PropBundleInstance_V136 { - new AkPropBundle_V136.PropBundleInstance_V136 - { - ID = AkPropId_V136.Loop, - Value = 0 - } + ID = AkPropId_V136.Loop, + Value = 0 } + } }; } else nodeBaseParams.NodeInitialParams.AkPropBundle0 = new AkPropBundle_V136() { PropsList = new List() }; - nodeBaseParams.NodeInitialParams.AkPropBundle1 = new AkPropBundleMinMax_V136() { PropsList = new List() }; + nodeBaseParams.NodeInitialParams.AkPropBundle1 = new AkPropBundleMinMax_V136() { PropsList = new List() }; nodeBaseParams.PositioningParams = new PositioningParams_V136() { BitsPositioning = 0x00 From a6f3ccc7cd43a1133eff9f8934e3dbf69bfc8ebe Mon Sep 17 00:00:00 2001 From: Pear <61670316+Pear-231@users.noreply.github.com> Date: Sat, 29 Mar 2025 21:26:52 +0000 Subject: [PATCH 02/54] Change Notes: - Added interfaces for dialogue event arguments and decision tree properties. --- .../V136/DialogueEventHircGenerator_V136.cs | 11 ++++--- Editors/Audio/Utility/DecisionPathHelper.cs | 16 +++++----- Editors/Audio/Utility/WwiseTreeParserBase.cs | 1 - .../Audio/Utility/WwiseTreeParserChildren.cs | 17 +++++------ .../Audio/Utility/WwiseTreeParserParent.cs | 2 +- Shared/GameFiles/Wwise/Hirc/HircInterfaces.cs | 30 ++++++++++++++----- .../Wwise/Hirc/V112/CAkDialogueEvent_V112.cs | 10 +++---- .../Wwise/Hirc/V112/CAkRanSeqCntr_V112.cs | 2 +- .../Wwise/Hirc/V112/CAkSwitchCntr_V112.cs | 8 ++--- .../Hirc/V112/Shared/AkDecisionTree_V112.cs | 3 +- .../Wwise/Hirc/V112/Shared/AkGameSync_V112.cs | 7 +++-- .../Wwise/Hirc/V136/CAkDialogueEvent_V136.cs | 8 ++--- .../Wwise/Hirc/V136/CAkRanSeqCntr_V136.cs | 2 +- .../Wwise/Hirc/V136/CAkSwitchCntr_V136.cs | 8 ++--- .../Hirc/V136/Shared/AkDecisionTree_V136.cs | 3 +- .../Wwise/Hirc/V136/Shared/AkGameSync_V136.cs | 3 +- 16 files changed, 73 insertions(+), 58 deletions(-) diff --git a/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/DialogueEventHircGenerator_V136.cs b/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/DialogueEventHircGenerator_V136.cs index b77067f66..937c18659 100644 --- a/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/DialogueEventHircGenerator_V136.cs +++ b/Editors/Audio/AudioProjectCompiler/WwiseGeneratorService/WwiseGenerators/Hirc/V136/DialogueEventHircGenerator_V136.cs @@ -26,17 +26,20 @@ private static CAkDialogueEvent_V136 CreateDialogueEvent(DialogueEvent audioProj dialogueEventHirc.Probability = 100; dialogueEventHirc.Arguments = CreateArguments(audioProjectDialogueEvent, dialogueEventHirc); dialogueEventHirc.TreeDepth = (uint)dialogueEventHirc.Arguments.Count; - dialogueEventHirc.AkDecisionTree = CreateDecisionTree(audioProjectDialogueEvent); - dialogueEventHirc.TreeDataSize = (uint)dialogueEventHirc.AkDecisionTree.Nodes.Count * new AkDecisionTree_V136.Node_V136().GetSize(); + + var decisionTree = CreateDecisionTree(audioProjectDialogueEvent); + dialogueEventHirc.AkDecisionTree = decisionTree; + dialogueEventHirc.TreeDataSize = (uint)decisionTree.Nodes.Count * new AkDecisionTree_V136.Node_V136().GetSize(); + dialogueEventHirc.Mode = (byte)AkMode.BestMatch; dialogueEventHirc.AkPropBundle0 = new AkPropBundle_V136() { PropsList = new List() }; dialogueEventHirc.AkPropBundle1 = new AkPropBundleMinMax_V136() { PropsList = new List() }; return dialogueEventHirc; } - private static List CreateArguments(DialogueEvent audioProjectDialogueEvent, CAkDialogueEvent_V136 dialogueEventHirc) + private static List CreateArguments(DialogueEvent audioProjectDialogueEvent, CAkDialogueEvent_V136 dialogueEventHirc) { - var arguments = new List(); + var arguments = new List(); foreach (var statePathNode in audioProjectDialogueEvent.StatePaths[0].Nodes) { var argument = new AkGameSync_V136 diff --git a/Editors/Audio/Utility/DecisionPathHelper.cs b/Editors/Audio/Utility/DecisionPathHelper.cs index aca5f086f..9ac794344 100644 --- a/Editors/Audio/Utility/DecisionPathHelper.cs +++ b/Editors/Audio/Utility/DecisionPathHelper.cs @@ -25,7 +25,7 @@ public class DecisionPathCollection public class DecisionPath { public List Items { get; set; } = new List(); - public uint ChildNodeId { get; set; } + public uint ChildNodeID { get; set; } public string GetAsString(string separator = ".") => string.Join(separator, Items.Select(x => x.DisplayName)); } @@ -44,8 +44,8 @@ public DecisionPathHelper(IAudioRepository audioRepository) public DecisionPathCollection GetDecisionPaths(ICAkDialogueEvent dialogueEvent) => dialogueEvent switch { - CAkDialogueEvent_V136 event136 => GetDecisionPaths(event136.AkDecisionTree, event136.Arguments), - CAkDialogueEvent_V112 event112 => GetDecisionPaths(event112.AkDecisionTree, event112.Arguments), + CAkDialogueEvent_V136 event136 => GetDecisionPaths((AkDecisionTree_V136)event136.AkDecisionTree, event136.Arguments.Cast().ToList()), + CAkDialogueEvent_V112 event112 => GetDecisionPaths((AkDecisionTree_V112)event112.AkDecisionTree, event112.Arguments.Cast().ToList()), _ => throw new NotImplementedException(), }; @@ -57,7 +57,7 @@ DecisionPathCollection GetDecisionPaths(AkDecisionTree_V136 decisionTree, List(); foreach (var path in paths) { - var currentPath = new DecisionPath() { ChildNodeId = path.Item2 }; + var currentPath = new DecisionPath() { ChildNodeID = path.Item2 }; foreach (var item in path.Item1.Skip(1)) { var name = _audioRepository.GetNameFromID(item.Key); @@ -91,7 +91,7 @@ private DecisionPathCollection GetDecisionPaths(AkDecisionTree_V112 decisionTree var decisionPath = new List(); foreach (var path in paths) { - var currentPath = new DecisionPath() { ChildNodeId = path.Item2 }; + var currentPath = new DecisionPath() { ChildNodeID = path.Item2 }; foreach (var item in path.Item1.Skip(1)) { var name = _audioRepository.GetNameFromID(item.Key); @@ -106,13 +106,13 @@ private DecisionPathCollection GetDecisionPaths(AkDecisionTree_V112 decisionTree var arguments = argumentsList .Select(x => { - var name = _audioRepository.GetNameFromID(x.GroupId); - return new { Name = name, x.GroupId }; + var name = _audioRepository.GetNameFromID(x.GroupID); + return new { Name = name, x.GroupID }; }).ToList(); var decisionPathCollection = new DecisionPathCollection() { - Header = new DecisionPath() { Items = arguments.Select(x => new DecisionPathItem() { DisplayName = x.Name, Value = x.GroupId }).ToList() }, + Header = new DecisionPath() { Items = arguments.Select(x => new DecisionPathItem() { DisplayName = x.Name, Value = x.GroupID }).ToList() }, Paths = decisionPath }; diff --git a/Editors/Audio/Utility/WwiseTreeParserBase.cs b/Editors/Audio/Utility/WwiseTreeParserBase.cs index d42bd2786..f41f3a448 100644 --- a/Editors/Audio/Utility/WwiseTreeParserBase.cs +++ b/Editors/Audio/Utility/WwiseTreeParserBase.cs @@ -74,7 +74,6 @@ private void ProcessHircObject(HircItem item, HircTreeItem parent) } } - protected void ProcessNext(uint hircId, HircTreeItem parent) { if (hircId == 0) diff --git a/Editors/Audio/Utility/WwiseTreeParserChildren.cs b/Editors/Audio/Utility/WwiseTreeParserChildren.cs index c5e4dd7aa..df6b4f95c 100644 --- a/Editors/Audio/Utility/WwiseTreeParserChildren.cs +++ b/Editors/Audio/Utility/WwiseTreeParserChildren.cs @@ -26,7 +26,6 @@ public WwiseTreeParserChildren(IAudioRepository repository, bool showId, bool sh _hircProcessChildMap.Add(AkBkHircType.Music_Random_Sequence, ProcessRandMusicContainer); } - private void ProcessDialogueEvent(HircItem item, HircTreeItem parent) { var hirc = GetAsType(item); @@ -34,21 +33,21 @@ private void ProcessDialogueEvent(HircItem item, HircTreeItem parent) var helper = new DecisionPathHelper(_repository); var paths = helper.GetDecisionPaths(hirc); - var dialogueEventNode = new HircTreeItem() { DisplayName = $"Dialog_Event {_repository.GetNameFromID(item.ID)} - [{paths.Header.GetAsString()}]", Item = item }; + var dialogueEventNode = new HircTreeItem() { DisplayName = $"Dialogue Event {_repository.GetNameFromID(item.ID)} - [{paths.Header.GetAsString()}]", Item = item }; parent.Children.Add(dialogueEventNode); foreach (var path in paths.Paths) { var pathNode = new HircTreeItem() { DisplayName = path.GetAsString(), Item = item, IsExpanded = false }; dialogueEventNode.Children.Add(pathNode); - ProcessNext(path.ChildNodeId, pathNode); + ProcessNext(path.ChildNodeID, pathNode); } } void ProcessEvent(HircItem item, HircTreeItem parent) { var actionHirc = GetAsType(item); - var actionTreeNode = new HircTreeItem() { DisplayName = $"Event {_repository.GetNameFromID(item.ID)}", Item = item }; + var actionTreeNode = new HircTreeItem() { DisplayName = $"Action Event {_repository.GetNameFromID(item.ID)}", Item = item }; parent.Children.Add(actionTreeNode); var actions = actionHirc.GetActionIds(); @@ -88,7 +87,7 @@ void ProcessAction(HircItem item, HircTreeItem parent) .ToList(); foreach (var normalSwitch in normalSwitches) - if (normalSwitch.GroupId == stateGroupId) + if (normalSwitch.GroupID == stateGroupId) ProcessNext(normalSwitch.ID, actionTreeNode); } else ProcessNext(childId, actionTreeNode); @@ -118,14 +117,14 @@ public void ProcessActorMixer(HircItem item, HircTreeItem parent) void ProcessSwitchControl(HircItem item, HircTreeItem parent) { var switchControl = GetAsType(item); - var switchType = _repository.GetNameFromID(switchControl.GroupId); + var switchType = _repository.GetNameFromID(switchControl.GroupID); var defaultValue = _repository.GetNameFromID(switchControl.DefaultSwitch); var switchControlNode = new HircTreeItem() { DisplayName = $"Switch {switchType} DefaultValue: {defaultValue}", Item = item }; parent.Children.Add(switchControlNode); foreach (var switchCase in switchControl.SwitchList) { - var switchValue = _repository.GetNameFromID(switchCase.SwitchId); + var switchValue = _repository.GetNameFromID(switchCase.SwitchID); var switchValueNode = new HircTreeItem() { DisplayName = $"SwitchValue: {switchValue}", Item = item, IsMetaNode = true }; switchControlNode.Children.Add(switchValueNode); @@ -145,7 +144,7 @@ private void ProcessLayerContainer(HircItem item, HircTreeItem parent) private void ProcessSequenceContainer(HircItem item, HircTreeItem parent) { - var layerContainer = GetAsType(item); + var layerContainer = GetAsType(item); var layerNode = new HircTreeItem() { DisplayName = $"Rand Container", Item = item }; parent.Children.Add(layerNode); @@ -187,7 +186,7 @@ private void ProcessMusicSwitch(HircItem item, HircTreeItem parent) { var pathNode = new HircTreeItem() { DisplayName = path.GetAsString(), Item = hirc, IsExpanded = false }; dialogueEventNode.Children.Add(pathNode); - ProcessNext(path.ChildNodeId, pathNode); + ProcessNext(path.ChildNodeID, pathNode); } } diff --git a/Editors/Audio/Utility/WwiseTreeParserParent.cs b/Editors/Audio/Utility/WwiseTreeParserParent.cs index aa43d4783..51bde5aba 100644 --- a/Editors/Audio/Utility/WwiseTreeParserParent.cs +++ b/Editors/Audio/Utility/WwiseTreeParserParent.cs @@ -37,7 +37,7 @@ private void FindParentSwitchControl(HircItem item, HircTreeItem parent) private void FindParentRandContainer(HircItem item, HircTreeItem parent) { - var sqtContainer = GetAsType(item); + var sqtContainer = GetAsType(item); var node = new HircTreeItem() { DisplayName = $"Rand Container {GetDisplayId(item.ID, item.OwnerFilePath, false)} {GetParentInfo(sqtContainer.GetDirectParentID())}", Item = item }; parent.Children.Add(node); ProcessNext(sqtContainer.GetDirectParentID(), node); diff --git a/Shared/GameFiles/Wwise/Hirc/HircInterfaces.cs b/Shared/GameFiles/Wwise/Hirc/HircInterfaces.cs index 7a4904a11..386f50d3d 100644 --- a/Shared/GameFiles/Wwise/Hirc/HircInterfaces.cs +++ b/Shared/GameFiles/Wwise/Hirc/HircInterfaces.cs @@ -1,4 +1,5 @@ -using Shared.GameFormats.Wwise.Enums; +using Shared.Core.ByteParsing; +using Shared.GameFormats.Wwise.Enums; namespace Shared.GameFormats.Wwise.Hirc { @@ -23,8 +24,21 @@ public interface ICAkAction public interface ICAkDialogueEvent { - List Arguments { get; } - object AkDecisionTree { get; } + public List Arguments { get; } + IAkDecisionTree AkDecisionTree { get; } + + public interface IAkGameSync + { + public uint GroupID { get; set; } + public AkGroupType GroupType { get; set; } + public uint GetSize(); + } + + public interface IAkDecisionTree + { + void ReadData(ByteChunk chunk, uint treeDataSize, uint treeDepth); + byte[] WriteData(); + } } public interface ICAkActorMixer @@ -35,14 +49,14 @@ public interface ICAkActorMixer public interface ICAkSwitchCntr { - uint GroupId { get; } - uint DefaultSwitch { get; } + public uint GroupID { get; } + public uint DefaultSwitch { get; } public List SwitchList { get; } public interface ICAkSwitchPackage { - uint SwitchId { get; } - List NodeIdList { get; } + public uint SwitchID { get; } + public List NodeIdList { get; } } public uint GetDirectParentID(); @@ -59,7 +73,7 @@ public interface ICAkLayerCntr public uint GetDirectParentID(); } - public interface ICAkRanSeqCnt + public interface ICAkRanSeqCntr { public uint GetDirectParentID(); public List GetChildren(); diff --git a/Shared/GameFiles/Wwise/Hirc/V112/CAkDialogueEvent_V112.cs b/Shared/GameFiles/Wwise/Hirc/V112/CAkDialogueEvent_V112.cs index 138aecd09..c984518e0 100644 --- a/Shared/GameFiles/Wwise/Hirc/V112/CAkDialogueEvent_V112.cs +++ b/Shared/GameFiles/Wwise/Hirc/V112/CAkDialogueEvent_V112.cs @@ -1,6 +1,7 @@ using Shared.Core.ByteParsing; using Shared.GameFormats.Wwise.Enums; using Shared.GameFormats.Wwise.Hirc.V112.Shared; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V112 { @@ -8,10 +9,10 @@ public class CAkDialogueEvent_V112 : HircItem, ICAkDialogueEvent { public byte Probability { get; set; } public uint TreeDepth { get; set; } - public List Arguments { get; set; } = []; + public List Arguments { get; set; } = []; public uint TreeDataSize { get; set; } public byte Mode { get; set; } - public AkDecisionTree_V112 AkDecisionTree { get; set; } = new AkDecisionTree_V112(); + public IAkDecisionTree AkDecisionTree { get; set; } = new AkDecisionTree_V112(); protected override void ReadData(ByteChunk chunk) { @@ -23,7 +24,7 @@ protected override void ReadData(ByteChunk chunk) // First read all the group ids for (var i = 0; i < TreeDepth; i++) - Arguments[i].GroupId = chunk.ReadUInt32(); + Arguments[i].GroupID = chunk.ReadUInt32(); // Then read all the group types for (var i = 0; i < TreeDepth; i++) @@ -36,8 +37,5 @@ protected override void ReadData(ByteChunk chunk) public override void UpdateSectionSize() => throw new NotImplementedException(); public override byte[] WriteData() => throw new NotImplementedException(); - - List ICAkDialogueEvent.Arguments => Arguments.Cast().ToList(); - object ICAkDialogueEvent.AkDecisionTree => AkDecisionTree; } } diff --git a/Shared/GameFiles/Wwise/Hirc/V112/CAkRanSeqCntr_V112.cs b/Shared/GameFiles/Wwise/Hirc/V112/CAkRanSeqCntr_V112.cs index a7716b3a8..d9d042722 100644 --- a/Shared/GameFiles/Wwise/Hirc/V112/CAkRanSeqCntr_V112.cs +++ b/Shared/GameFiles/Wwise/Hirc/V112/CAkRanSeqCntr_V112.cs @@ -3,7 +3,7 @@ namespace Shared.GameFormats.Wwise.Hirc.V112 { - public class CAkRanSeqCntr_V112 : HircItem, ICAkRanSeqCnt + public class CAkRanSeqCntr_V112 : HircItem, ICAkRanSeqCntr { public NodeBaseParams_V112 NodeBaseParams { get; set; } = new NodeBaseParams_V112(); public ushort LoopCount { get; set; } diff --git a/Shared/GameFiles/Wwise/Hirc/V112/CAkSwitchCntr_V112.cs b/Shared/GameFiles/Wwise/Hirc/V112/CAkSwitchCntr_V112.cs index 25a1ea5b0..87f41ef7f 100644 --- a/Shared/GameFiles/Wwise/Hirc/V112/CAkSwitchCntr_V112.cs +++ b/Shared/GameFiles/Wwise/Hirc/V112/CAkSwitchCntr_V112.cs @@ -9,7 +9,7 @@ public class CAkSwitchCntr_V112 : HircItem, ICAkSwitchCntr { public NodeBaseParams_V112 NodeBaseParams { get; set; } = new NodeBaseParams_V112(); public AkGroupType GroupType { get; set; } - public uint GroupId { get; set; } + public uint GroupID { get; set; } public uint DefaultSwitch { get; set; } public byte IsContinuousValidation { get; set; } public Children_V112 Children { get; set; } = new Children_V112(); @@ -20,7 +20,7 @@ protected override void ReadData(ByteChunk chunk) { NodeBaseParams.ReadData(chunk); GroupType = (AkGroupType)chunk.ReadByte(); - GroupId = chunk.ReadUInt32(); + GroupID = chunk.ReadUInt32(); DefaultSwitch = chunk.ReadUInt32(); IsContinuousValidation = chunk.ReadByte(); Children.ReadData(chunk); @@ -40,13 +40,13 @@ protected override void ReadData(ByteChunk chunk) public class CAkSwitchPackage_V112 : ICAkSwitchPackage { - public uint SwitchId { get; set; } + public uint SwitchID { get; set; } public List NodeIdList { get; set; } = []; public static ICAkSwitchPackage ReadData(ByteChunk chunk) { var instance = new CAkSwitchPackage_V112(); - instance.SwitchId = chunk.ReadUInt32(); + instance.SwitchID = chunk.ReadUInt32(); var numChildren = chunk.ReadUInt32(); for (var i = 0; i < numChildren; i++) instance.NodeIdList.Add(chunk.ReadUInt32()); diff --git a/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkDecisionTree_V112.cs b/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkDecisionTree_V112.cs index 03945ae20..72d567165 100644 --- a/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkDecisionTree_V112.cs +++ b/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkDecisionTree_V112.cs @@ -1,8 +1,9 @@ using Shared.Core.ByteParsing; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V112.Shared { - public class AkDecisionTree_V112 + public class AkDecisionTree_V112 : IAkDecisionTree { public Node_V112 DecisionTree { get; set; } = new Node_V112(); // Root node of the decision tree in hierarchical form public List Nodes { get; set; } = []; // Flattened list of all nodes in the decision tree in sequential order for read / write diff --git a/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkGameSync_V112.cs b/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkGameSync_V112.cs index 61f29ec71..e76e2d3bc 100644 --- a/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkGameSync_V112.cs +++ b/Shared/GameFiles/Wwise/Hirc/V112/Shared/AkGameSync_V112.cs @@ -1,16 +1,17 @@ using Shared.Core.ByteParsing; using Shared.GameFormats.Wwise.Enums; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V112.Shared { - public class AkGameSync_V112 + public class AkGameSync_V112 : IAkGameSync { - public uint GroupId { get; set; } + public uint GroupID { get; set; } public AkGroupType GroupType { get; set; } public uint GetSize() { - var groupIdSize = ByteHelper.GetPropertyTypeSize(GroupId); + var groupIdSize = ByteHelper.GetPropertyTypeSize(GroupID); var groupTypeSize = ByteHelper.GetPropertyTypeSize(GroupType); return groupIdSize + groupTypeSize; } diff --git a/Shared/GameFiles/Wwise/Hirc/V136/CAkDialogueEvent_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/CAkDialogueEvent_V136.cs index f8b390a42..1119796bf 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/CAkDialogueEvent_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/CAkDialogueEvent_V136.cs @@ -1,6 +1,7 @@ using Shared.Core.ByteParsing; using Shared.GameFormats.Wwise.Enums; using Shared.GameFormats.Wwise.Hirc.V136.Shared; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V136 { @@ -8,10 +9,10 @@ public partial class CAkDialogueEvent_V136 : HircItem, ICAkDialogueEvent { public byte Probability { get; set; } public uint TreeDepth { get; set; } - public List Arguments { get; set; } = []; + public List Arguments { get; set; } = []; public uint TreeDataSize { get; set; } public byte Mode { get; set; } - public AkDecisionTree_V136 AkDecisionTree { get; set; } = new AkDecisionTree_V136(); + public IAkDecisionTree AkDecisionTree { get; set; } = new AkDecisionTree_V136(); public AkPropBundle_V136 AkPropBundle0 { get; set; } = new AkPropBundle_V136(); public AkPropBundleMinMax_V136 AkPropBundle1 { get; set; } = new AkPropBundleMinMax_V136(); @@ -81,8 +82,5 @@ public override void UpdateSectionSize() var modeSize = ByteHelper.GetPropertyTypeSize(Mode); SectionSize = idSize + probabilitySize + treeDepthSize + arugumentsSize + treeDataSizeSize + modeSize + TreeDataSize + AkPropBundle0.GetSize() + AkPropBundle1.GetSize(); } - - List ICAkDialogueEvent.Arguments => Arguments.Cast().ToList(); - object ICAkDialogueEvent.AkDecisionTree => AkDecisionTree; } } diff --git a/Shared/GameFiles/Wwise/Hirc/V136/CAkRanSeqCntr_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/CAkRanSeqCntr_V136.cs index b81a0c856..aabe9b097 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/CAkRanSeqCntr_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/CAkRanSeqCntr_V136.cs @@ -3,7 +3,7 @@ namespace Shared.GameFormats.Wwise.Hirc.V136 { - public class CAkRanSeqCntr_V136 : HircItem, ICAkRanSeqCnt + public class CAkRanSeqCntr_V136 : HircItem, ICAkRanSeqCntr { public NodeBaseParams_V136 NodeBaseParams { get; set; } = new NodeBaseParams_V136(); public ushort LoopCount { get; set; } diff --git a/Shared/GameFiles/Wwise/Hirc/V136/CAkSwitchCntr_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/CAkSwitchCntr_V136.cs index e49e4e00a..175eec7f6 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/CAkSwitchCntr_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/CAkSwitchCntr_V136.cs @@ -9,7 +9,7 @@ public class CAkSwitchCntr_V136 : HircItem, ICAkSwitchCntr { public NodeBaseParams_V136 NodeBaseParams { get; set; } = new NodeBaseParams_V136(); public AkGroupType EGroupType { get; set; } - public uint GroupId { get; set; } + public uint GroupID { get; set; } public uint DefaultSwitch { get; set; } public byte BIsContinuousValidation { get; set; } public Children_V136 Children { get; set; } = new Children_V136(); @@ -23,7 +23,7 @@ protected override void ReadData(ByteChunk chunk) { NodeBaseParams.ReadData(chunk); EGroupType = (AkGroupType)chunk.ReadByte(); - GroupId = chunk.ReadUInt32(); + GroupID = chunk.ReadUInt32(); DefaultSwitch = chunk.ReadUInt32(); BIsContinuousValidation = chunk.ReadByte(); Children.ReadData(chunk); @@ -50,12 +50,12 @@ protected override void ReadData(ByteChunk chunk) public class CAkSwitchPackage_V136 : ICAkSwitchPackage { - public uint SwitchId { get; set; } + public uint SwitchID { get; set; } public List NodeIdList { get; set; } = []; public void ReadData(ByteChunk chunk) { - SwitchId = chunk.ReadUInt32(); + SwitchID = chunk.ReadUInt32(); var numChildren = chunk.ReadUInt32(); for (var i = 0; i < numChildren; i++) NodeIdList.Add(chunk.ReadUInt32()); diff --git a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs index bd80c4e14..bdce44afa 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs @@ -1,8 +1,9 @@ using Shared.Core.ByteParsing; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V136.Shared { - public class AkDecisionTree_V136 + public class AkDecisionTree_V136 : IAkDecisionTree { public Node_V136 DecisionTree { get; set; } = new Node_V136(); // Root node of the decision tree in hierarchical form public List Nodes { get; set; } = []; // Flattened list of all nodes in the decision tree in sequential order for read / write diff --git a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkGameSync_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkGameSync_V136.cs index c8d75619d..402ce4f12 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkGameSync_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkGameSync_V136.cs @@ -1,9 +1,10 @@ using Shared.Core.ByteParsing; using Shared.GameFormats.Wwise.Enums; +using static Shared.GameFormats.Wwise.Hirc.ICAkDialogueEvent; namespace Shared.GameFormats.Wwise.Hirc.V136.Shared { - public class AkGameSync_V136 + public class AkGameSync_V136 : IAkGameSync { public uint GroupID { get; set; } public AkGroupType GroupType { get; set; } From cc6b1896bf0851c7a54471437b566e4c1315ad3d Mon Sep 17 00:00:00 2001 From: Pear <61670316+Pear-231@users.noreply.github.com> Date: Fri, 2 May 2025 15:35:43 +0100 Subject: [PATCH 03/54] Change Notes: - Fixed a bug where BrowseDialogResultFolder was only returning the selected folder rather than the path to the folder. - Fixed bug where V136 'Data_BNK' sounds did not play in the Audio Explorer. - Fixed a bug where states weren't being saved properly into the AudioRepository. - Fixed niche dialogue event reading error thanks to bnnm behind Wwiser. - Fixed a bug where the Pack File Explorer Import Directory button was causing a crash. --- Shared/GameFiles/Dat/DatFileParser.cs | 26 +++++------ Shared/GameFiles/Dat/SoundDatFile.cs | 28 ++++++------ .../Hirc/V136/Shared/AkDecisionTree_V136.cs | 45 ++++++------------- .../SharedCore/Services/IStandardDialogs.cs | 1 - Shared/SharedCore/ToolCreation/EditorEnums.cs | 1 - .../Commands/ImportDirectoryCommand.cs | 31 ++++++++----- .../PackFile/PackFileBrowserWindow.xaml.cs | 13 +++++- 7 files changed, 73 insertions(+), 72 deletions(-) diff --git a/Shared/GameFiles/Dat/DatFileParser.cs b/Shared/GameFiles/Dat/DatFileParser.cs index 828c3076f..0a3982c3c 100644 --- a/Shared/GameFiles/Dat/DatFileParser.cs +++ b/Shared/GameFiles/Dat/DatFileParser.cs @@ -14,12 +14,12 @@ public static SoundDatFile Parse(PackFile file, bool isAtilla) var sectionZeroCount = chunk.ReadUInt32(); for (var i = 0; i < sectionZeroCount; i++) - output.EventWithStateGroup.Add(new SoundDatFile.DatEventWithStateGroup() { EventName = ReadStr32(chunk), Value = chunk.ReadSingle() }); + output.EventWithStateGroup.Add(new SoundDatFile.DatEventWithStateGroup() { Event = ReadStr32(chunk), Value = chunk.ReadSingle() }); var sectionOneCount = chunk.ReadInt32(); for (var i = 0; i < sectionOneCount; i++) { - var stateGroup = new SoundDatFile.DatStateGroupsWithStates() { StateGroupName = ReadStr32(chunk) }; + var stateGroup = new SoundDatFile.DatStateGroupsWithStates() { StateGroup = ReadStr32(chunk) }; var state = chunk.ReadUInt32(); for (var j = 0; j < state; j++) stateGroup.States.Add(ReadStr32(chunk)); @@ -30,7 +30,7 @@ public static SoundDatFile Parse(PackFile file, bool isAtilla) var sectionTwoCount = chunk.ReadInt32(); for (var i = 0; i < sectionTwoCount; i++) { - var stateGroup = new SoundDatFile.DatStateGroupsWithStates() { StateGroupName = ReadStr32(chunk) }; + var stateGroup = new SoundDatFile.DatStateGroupsWithStates() { StateGroup = ReadStr32(chunk) }; var state = chunk.ReadUInt32(); for (var j = 0; j < state; j++) stateGroup.States.Add(ReadStr32(chunk)); @@ -41,7 +41,7 @@ public static SoundDatFile Parse(PackFile file, bool isAtilla) var sectionThreeCount = chunk.ReadInt32(); for (var i = 0; i < sectionThreeCount; i++) { - var dialogueEvent = new SoundDatFile.DatDialogueEventsWithStateGroups() { EventName = ReadStr32(chunk) }; + var dialogueEvent = new SoundDatFile.DatDialogueEventsWithStateGroups() { Event = ReadStr32(chunk) }; var stateGroup = chunk.ReadUInt32(); for (var j = 0; j < stateGroup; j++) @@ -54,13 +54,13 @@ public static SoundDatFile Parse(PackFile file, bool isAtilla) { var sectionFourCount = chunk.ReadInt32(); for (var i = 0; i < sectionFourCount; i++) - output.SettingValues.Add(new SoundDatFile.DatSettingValues() { EventName = ReadStr32(chunk) }); + output.SettingValues.Add(new SoundDatFile.DatSettingValues() { Event = ReadStr32(chunk) }); } else { var sectionFourCount = chunk.ReadInt32(); for (var i = 0; i < sectionFourCount; i++) - output.SettingValues.Add(new SoundDatFile.DatSettingValues() { EventName = ReadStr32(chunk), MinValue = chunk.ReadSingle(), MaxValue = chunk.ReadSingle() }); + output.SettingValues.Add(new SoundDatFile.DatSettingValues() { Event = ReadStr32(chunk), MinValue = chunk.ReadSingle(), MaxValue = chunk.ReadSingle() }); var sectionFiveCount = chunk.ReadInt32(); for (var i = 0; i < sectionFiveCount; i++) @@ -77,34 +77,34 @@ public static byte[] WriteData(SoundDatFile file) memStream.Write(ByteParsers.UInt32.EncodeValue((uint)file.EventWithStateGroup.Count(), out _)); foreach (var value in file.EventWithStateGroup) { - memStream.Write(WriteStr32(value.EventName)); + memStream.Write(WriteStr32(value.Event)); memStream.Write(ByteParsers.Single.EncodeValue(value.Value, out _)); } memStream.Write(ByteParsers.UInt32.EncodeValue((uint)file.StateGroupsWithStates0.Count(), out _)); foreach (var enumType in file.StateGroupsWithStates0) { - memStream.Write(WriteStr32(enumType.StateGroupName)); + memStream.Write(WriteStr32(enumType.StateGroup)); memStream.Write(ByteParsers.UInt32.EncodeValue((uint)enumType.States.Count(), out _)); foreach (var enumValue in enumType.States) - memStream.Write(WriteStr32(enumType.StateGroupName)); + memStream.Write(WriteStr32(enumType.StateGroup)); } memStream.Write(ByteParsers.UInt32.EncodeValue((uint)file.StateGroupsWithStates1.Count(), out _)); foreach (var enumType in file.StateGroupsWithStates1) { - memStream.Write(WriteStr32(enumType.StateGroupName)); + memStream.Write(WriteStr32(enumType.StateGroup)); memStream.Write(ByteParsers.UInt32.EncodeValue((uint)enumType.States.Count(), out _)); foreach (var enumValue in enumType.States) - memStream.Write(WriteStr32(enumType.StateGroupName)); + memStream.Write(WriteStr32(enumType.StateGroup)); } memStream.Write(ByteParsers.UInt32.EncodeValue((uint)file.DialogueEventsWithStateGroups.Count(), out _)); foreach (var voiceEvent in file.DialogueEventsWithStateGroups) { - memStream.Write(WriteStr32(voiceEvent.EventName)); + memStream.Write(WriteStr32(voiceEvent.Event)); memStream.Write(ByteParsers.UInt32.EncodeValue((uint)voiceEvent.StateGroups.Count(), out _)); foreach (var value in voiceEvent.StateGroups) @@ -115,7 +115,7 @@ public static byte[] WriteData(SoundDatFile file) memStream.Write(ByteParsers.UInt32.EncodeValue((uint)file.SettingValues.Count(), out _)); foreach (var value in file.SettingValues) { - memStream.Write(WriteStr32(value.EventName)); + memStream.Write(WriteStr32(value.Event)); memStream.Write(ByteParsers.Single.EncodeValue(value.MinValue, out _)); memStream.Write(ByteParsers.Single.EncodeValue(value.MaxValue, out _)); } diff --git a/Shared/GameFiles/Dat/SoundDatFile.cs b/Shared/GameFiles/Dat/SoundDatFile.cs index a58bb7a9d..3e9159847 100644 --- a/Shared/GameFiles/Dat/SoundDatFile.cs +++ b/Shared/GameFiles/Dat/SoundDatFile.cs @@ -8,21 +8,21 @@ public class SoundDatFile [DebuggerDisplay("EventWithValue {EventName} {Value}")] public class DatEventWithStateGroup { - public string EventName { get; set; } + public string Event { get; set; } public float Value { get; set; } } [DebuggerDisplay("EventWithValues {EventName} [{Values.Count}]")] public class DatDialogueEventsWithStateGroups { - public string EventName { get; set; } + public string Event { get; set; } public List StateGroups { get; set; } = new List(); } [DebuggerDisplay("SettingValue {EventName} [{MinValue}-{MaxValue}]")] public class DatSettingValues { - public string EventName { get; set; } + public string Event { get; set; } public float MinValue { get; set; } public float MaxValue { get; set; } } @@ -31,7 +31,7 @@ public class DatSettingValues [DebuggerDisplay("EventTypeEnums {EnumName} [{EnumValues.Count}]")] public class DatStateGroupsWithStates { - public string StateGroupName { get; set; } + public string StateGroup { get; set; } public List States { get; set; } = []; } @@ -48,23 +48,23 @@ public void DumpToFile(string filePath) builder.AppendLine($"Section 1 -{EventWithStateGroup.Count}"); foreach (var item in EventWithStateGroup) - builder.AppendLine($"{item.EventName}, {item.Value}"); + builder.AppendLine($"{item.Event}, {item.Value}"); builder.AppendLine($"Section 2 -{StateGroupsWithStates0.Count}"); foreach (var item in StateGroupsWithStates0) - builder.AppendLine($"{item.StateGroupName}, [{string.Join(",", item.States)}]"); + builder.AppendLine($"{item.StateGroup}, [{string.Join(",", item.States)}]"); builder.AppendLine($"Section 3 -{StateGroupsWithStates1.Count}"); foreach (var item in StateGroupsWithStates1) - builder.AppendLine($"{item.StateGroupName}, [{string.Join(",", item.States)}]"); + builder.AppendLine($"{item.StateGroup}, [{string.Join(",", item.States)}]"); builder.AppendLine($"Section 4 -{DialogueEventsWithStateGroups.Count}"); foreach (var item in DialogueEventsWithStateGroups) - builder.AppendLine($"{item.EventName}, [{string.Join(",", item.StateGroups)}]"); + builder.AppendLine($"{item.Event}, [{string.Join(",", item.StateGroups)}]"); builder.AppendLine($"Section 5 -{SettingValues.Count}"); foreach (var item in SettingValues) - builder.AppendLine($"{item.EventName}, {item.MinValue}, {item.MaxValue}"); + builder.AppendLine($"{item.Event}, {item.MinValue}, {item.MaxValue}"); builder.AppendLine($"Section 6 -{Unknown.Count}"); foreach (var item in Unknown) @@ -88,16 +88,16 @@ public void Merge(SoundDatFile other) public string[] CreateFileNameList() { var output = new List(); - output.AddRange(EventWithStateGroup.Select(x => x.EventName)); + output.AddRange(EventWithStateGroup.Select(x => x.Event)); - output.AddRange(StateGroupsWithStates0.Select(x => x.StateGroupName)); + output.AddRange(StateGroupsWithStates0.Select(x => x.StateGroup)); output.AddRange(StateGroupsWithStates0.SelectMany(x => x.States)); - output.AddRange(StateGroupsWithStates1.Select(x => x.StateGroupName)); + output.AddRange(StateGroupsWithStates1.Select(x => x.StateGroup)); output.AddRange(StateGroupsWithStates1.SelectMany(x => x.States)); - output.AddRange(DialogueEventsWithStateGroups.Select(x => x.EventName)); - output.AddRange(SettingValues.Select(x => x.EventName)); + output.AddRange(DialogueEventsWithStateGroups.Select(x => x.Event)); + output.AddRange(SettingValues.Select(x => x.Event)); output.AddRange(Unknown.Select(x => x)); return output.ToArray(); diff --git a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs index bdce44afa..d6c542fba 100644 --- a/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs +++ b/Shared/GameFiles/Wwise/Hirc/V136/Shared/AkDecisionTree_V136.cs @@ -8,12 +8,12 @@ public class AkDecisionTree_V136 : IAkDecisionTree public Node_V136 DecisionTree { get; set; } = new Node_V136(); // Root node of the decision tree in hierarchical form public List Nodes { get; set; } = []; // Flattened list of all nodes in the decision tree in sequential order for read / write - public void ReadData(ByteChunk chunk, uint uTreeDataSize, uint maxTreeDepth) + public void ReadData(ByteChunk chunk, uint treeDataSize, uint maxTreeDepth) { - Nodes = new List(); + Nodes = []; uint currentDepth = 0; + var countMax = treeDataSize / new Node_V136().GetSize(); - var countMax = uTreeDataSize / new Node_V136().GetSize(); for (var i = 0; i < countMax; i++) { Nodes.Add(Node_V136.ReadData(chunk, countMax, currentDepth, maxTreeDepth)); @@ -21,24 +21,27 @@ public void ReadData(ByteChunk chunk, uint uTreeDataSize, uint maxTreeDepth) } ushort childrenCount = 1; - DecisionTree = BuildDecisionTree(Nodes, 0, maxTreeDepth, 0, ref childrenCount, (ushort)countMax); + var startIndex = 0; + uint startDepth = 0; + DecisionTree = ReadDecisionTree(Nodes, startIndex, maxTreeDepth, startDepth, ref childrenCount, (ushort)countMax); } - private static Node_V136 BuildDecisionTree(List nodes, int index, uint maxDepth, uint currentDepth, ref ushort count, ushort countMax) + private static Node_V136 ReadDecisionTree(List nodes, int index, uint maxDepth, uint currentDepth, ref ushort count, ushort countMax) { if (index >= nodes.Count) return null; var node = nodes[index]; - var isAudioNode = node.ChildrenIdx > countMax || node.ChildrenCount > countMax; + var isOver = node.ChildrenIdx + node.ChildrenCount > countMax; + var isAudioNode = node.ChildrenIdx > countMax || node.ChildrenCount > countMax || isOver; var isMax = currentDepth == maxDepth; - if (!(isAudioNode || isMax)) //|| treeNode.ChildrenCount == 0)) + if (!(isAudioNode || isMax)) { var treeNodeChildren = new List(); for (var i = 0; i < node.ChildrenCount; i++) { - var childNode = BuildDecisionTree(nodes, node.ChildrenIdx + i, maxDepth, currentDepth + 1, ref count, countMax); + var childNode = ReadDecisionTree(nodes, node.ChildrenIdx + i, maxDepth, currentDepth + 1, ref count, countMax); if (childNode != null) treeNodeChildren.Add(childNode); } @@ -57,9 +60,7 @@ public byte[] WriteData() memStream.Write(ByteParsers.UInt32.EncodeValue(node.Key ?? 0, out _), 0, 4); if (node.AudioNodeID != 0) - { memStream.Write(ByteParsers.UInt32.EncodeValue(node.AudioNodeID, out _), 0, 4); - } else { memStream.Write(ByteParsers.UShort.EncodeValue(node.ChildrenIdx, out _), 0, 2); @@ -72,25 +73,6 @@ public byte[] WriteData() return memStream.ToArray(); } - // Recursively traverses the decision tree, flattening it into a list so nodes can be read sequentially - // Should initially be supplied with the root node which is the first node in the DecisionTree property - public static List TraverseAndFlatten(Node_V136 rootNode) - { - var nodes = new List(); - InternalTraverseAndFlatten(nodes, rootNode); - return nodes; - } - - public static void InternalTraverseAndFlatten(List nodes, Node_V136 node) - { - if (node == null) - return; - - nodes.Add(node); - foreach (var child_node in node.Nodes) - InternalTraverseAndFlatten(nodes, child_node); - } - public class Node_V136 { public uint? Key { get; set; } @@ -110,7 +92,8 @@ public static Node_V136 ReadData(ByteChunk chunk, uint countMax, uint currentDep node.ChildrenIdx = (ushort)((idChildrenPeek >> 0) & 0xFFFF); node.ChildrenCount = (ushort)((idChildrenPeek >> 16) & 0xFFFF); - var isAudioNode = node.ChildrenIdx > countMax || node.ChildrenCount > countMax; + var isOver = node.ChildrenIdx + node.ChildrenCount > countMax; + var isAudioNode = node.ChildrenIdx > countMax || node.ChildrenCount > countMax || isOver; var isMax = currentDepth == maxDepth; if (isAudioNode || isMax) node.AudioNodeID = chunk.ReadUInt32(); @@ -127,7 +110,7 @@ public static Node_V136 ReadData(ByteChunk chunk, uint countMax, uint currentDep public uint GetSize() { - // Either ChildrenIdx and ChildrenCoun are used or AudioNodeID is used but in either case the same amount of bytes are used so doesn't matter which one is used to calculate the size here + // Either ChildrenIdx and ChildrenCount are used or AudioNodeID is used but in either case the same amount of bytes are used so doesn't matter which one is used to calculate the size here var idSize = ByteHelper.GetPropertyTypeSize(Key); var childrenIdxSize = ByteHelper.GetPropertyTypeSize(ChildrenIdx); var childrenCountSize = ByteHelper.GetPropertyTypeSize(ChildrenCount); diff --git a/Shared/SharedCore/Services/IStandardDialogs.cs b/Shared/SharedCore/Services/IStandardDialogs.cs index 3bd26cb0c..6537fd6c7 100644 --- a/Shared/SharedCore/Services/IStandardDialogs.cs +++ b/Shared/SharedCore/Services/IStandardDialogs.cs @@ -28,5 +28,4 @@ public enum ShowMessageBoxResult OK, Cancel, } - } diff --git a/Shared/SharedCore/ToolCreation/EditorEnums.cs b/Shared/SharedCore/ToolCreation/EditorEnums.cs index 3fcc31245..5aecc9eaa 100644 --- a/Shared/SharedCore/ToolCreation/EditorEnums.cs +++ b/Shared/SharedCore/ToolCreation/EditorEnums.cs @@ -19,7 +19,6 @@ public enum EditorEnums CampaginAnimation_Editor, AnimationPack_Editor, AudioExplorer_Editor, - AudioCompiler_Editor, Audio_Editor, Twui_Editor, None, diff --git a/Shared/SharedUI/BaseDialogs/PackFileTree/ContextMenu/Commands/ImportDirectoryCommand.cs b/Shared/SharedUI/BaseDialogs/PackFileTree/ContextMenu/Commands/ImportDirectoryCommand.cs index f35b247de..d105c6f1a 100644 --- a/Shared/SharedUI/BaseDialogs/PackFileTree/ContextMenu/Commands/ImportDirectoryCommand.cs +++ b/Shared/SharedUI/BaseDialogs/PackFileTree/ContextMenu/Commands/ImportDirectoryCommand.cs @@ -23,29 +23,38 @@ public void Execute(TreeNode _selectedNode) var dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { - var parentPath = _selectedNode.GetFullPath(); - var originalFilePaths = Directory.GetFiles(parentPath, "*", SearchOption.AllDirectories); - var filePaths = originalFilePaths.Select(x => x.Replace(dialog.SelectedPath + "\\", "")).ToList(); - if (!string.IsNullOrWhiteSpace(parentPath)) - parentPath += "\\"; + var folderPath = dialog.SelectedPath; + var folderName = new DirectoryInfo(folderPath).Name; + var originalFilePaths = Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories); + var filePaths = originalFilePaths.Select(x => x.Replace($"{folderPath}\\", "")).ToList(); + + var packNodeParentPath = _selectedNode.GetFullPath(); + if (!string.IsNullOrWhiteSpace(packNodeParentPath)) + packNodeParentPath += "\\"; var filesAdded = new List(); for (var i = 0; i < filePaths.Count; i++) { var currentPath = filePaths[i]; - var filename = Path.GetFileName(currentPath); + var fileName = Path.GetFileName(currentPath); + + var packDirectoryPath = $"{packNodeParentPath.ToLower()}{folderName}"; + + var directoryPath = string.Empty; + if (currentPath != fileName) + { + directoryPath = currentPath.Replace($"\\{fileName}", string.Empty).ToLower(); + packDirectoryPath = $"{packDirectoryPath}\\{directoryPath}"; + } var source = MemorySource.FromFile(originalFilePaths[i]); - var file = new PackFile(filename, source); - filesAdded.Add(new NewPackFileEntry(parentPath.ToLower(), file)); + var file = new PackFile(fileName, source); + filesAdded.Add(new NewPackFileEntry(packDirectoryPath, file)); } packFileService.AddFilesToPack(_selectedNode.FileOwner, filesAdded); } } } - - - } diff --git a/Shared/SharedUI/BaseDialogs/StandardDialog/PackFile/PackFileBrowserWindow.xaml.cs b/Shared/SharedUI/BaseDialogs/StandardDialog/PackFile/PackFileBrowserWindow.xaml.cs index 659673a19..c2b5d74a5 100644 --- a/Shared/SharedUI/BaseDialogs/StandardDialog/PackFile/PackFileBrowserWindow.xaml.cs +++ b/Shared/SharedUI/BaseDialogs/StandardDialog/PackFile/PackFileBrowserWindow.xaml.cs @@ -54,12 +54,23 @@ private void Button_Click(object sender, RoutedEventArgs e) SelectedFile = ViewModel.SelectedItem?.Item; if (ViewModel.SelectedItem?.NodeType == NodeType.Directory) - SelectedFolder = ViewModel.SelectedItem?.Name; + SelectedFolder = GetFolderPath(ViewModel.SelectedItem, ViewModel.SelectedItem?.Name); DialogResult = true; Close(); } + private static string GetFolderPath(TreeNode node, string folderPath) + { + if (node.Parent?.NodeType == NodeType.Root) + return folderPath; + else + { + folderPath = $"{node.Parent.Name}\\{folderPath}"; + return GetFolderPath(node.Parent, folderPath); + } + } + public void Dispose() { PreviewKeyDown -= HandleEsc; From b0d5239fb2672d46c164e198beed1322f59e01fc Mon Sep 17 00:00:00 2001 From: Pear <61670316+Pear-231@users.noreply.github.com> Date: Fri, 2 May 2025 15:35:54 +0100 Subject: [PATCH 04/54] Change Notes: - Refactored DataGrids to use a DataTable instead of a Dictionary - way better! - Added support for dragging Audio Files as a way of setting them. - Added functionality to set the name of the event based on an audio file if only a single audio file is set. - Added refreshing to the audio files when files / folders in a pack are added or removed. - Fixed a bug where state paths that were out of date due to CA state group changes were unable to be edited. - Fixed bug where show edited items only was showing dialogue events that weren't edited if others in its SoundBank were. - Renaming WwiseHash.cs to get around git's file renaming capitalisation issue. --- .../Audio/AudioEditor/AudioEditorService.cs | 185 +++----------- .../Audio/AudioEditor/AudioEditorViewModel.cs | 27 +- .../AudioFilesExplorerView.xaml | 4 +- .../AudioFilesExplorerViewModel.cs | 54 ++-- .../AudioFilesExplorer/MultiSelectTreeView.cs | 80 ++++-- .../ActionEventDataService.cs | 19 +- .../AudioProjectData/AudioProject.cs | 236 +++++++++++++++++- .../AudioProjectData/AudioProjectHelpers.cs | 157 +++++++++--- .../DialogueEventDataService.cs | 17 +- .../AudioProjectData/StateGroupDataService.cs | 17 +- .../AudioProjectEditorView.xaml | 4 +- .../AudioProjectEditorViewModel.cs | 93 ++++--- .../DataGrid/ActionEventDataGridService.cs | 39 +-- .../DataGrid/DialogueEventDataGridService.cs | 19 +- .../DataGrid/StateGroupDataGridService.cs | 20 +- .../AudioProjectExplorerViewModel.cs | 9 +- .../AudioProjectExplorer/TreeBuilder.cs | 20 +- .../AudioProjectExplorer/TreeNode.cs | 6 +- .../AudioProjectViewerView.xaml | 2 +- .../AudioProjectViewerView.xaml.cs | 8 +- .../AudioProjectViewerViewModel.cs | 116 ++++----- .../DataGrid/ActionEventDataGridService.cs | 29 ++- .../DataGrid/DialogueEventDataGridService.cs | 24 +- .../DataGrid/StateGroupDataGridService.cs | 23 +- .../AudioSettings/AudioSettingsView.xaml | 13 +- .../AudioSettings/AudioSettingsView.xaml.cs | 50 +++- .../AudioSettings/AudioSettingsViewModel.cs | 17 +- .../DataGrids/DataGridConfiguration.cs | 11 +- .../AudioEditor/DataGrids/DataGridHelpers.cs | 46 ++-- .../AudioEditor/Events/AudioFilesSetEvent.cs | 7 + .../AudioEditor/Events/ItemAddedEvent.cs | 2 +- .../AudioEditor/Events/SetEnablementEvent.cs | 6 + .../Audio/AudioEditor/IAudioEditorService.cs | 15 +- Editors/Audio/AudioEditor/IntegrityChecker.cs | 58 ++--- .../NewAudioProjectViewModel.cs | 28 +-- .../NewAudioProjectWindow.xaml | 4 - .../NewAudioProjectWindow.xaml.cs | 19 +- .../AudioExplorer/AudioExplorerViewModel.cs | 16 +- .../AudioProjectCompilerHelpers.cs | 4 +- .../CompilerDataProcessor.cs | 14 +- .../Bkhd/BkhdChunkGenerator.cs | 2 +- Editors/Audio/DependencyInjectionContainer.cs | 7 +- Editors/Audio/Storage/AudioRepository.cs | 23 +- Editors/Audio/Storage/BnkLoader.cs | 16 +- Editors/Audio/Storage/DatLoader.cs | 47 +++- Editors/Audio/Storage/RepositoryProvider.cs | 16 +- .../OpenNewAudioProjectWindowCommand.cs | 26 ++ Editors/Audio/Utility/SoundPlayer.cs | 8 +- Editors/Audio/Utility/VgStreamWrapper.cs | 14 +- Editors/Audio/Utility/WWiseHash.cs | 24 -- Editors/Audio/Utility/WwiseHashRename.cs | 23 ++ .../Reports/Audio/DialogueEventInfoPrinter.cs | 30 +-- 52 files changed, 1063 insertions(+), 691 deletions(-) create mode 100644 Editors/Audio/AudioEditor/Events/AudioFilesSetEvent.cs create mode 100644 Editors/Audio/AudioEditor/Events/SetEnablementEvent.cs create mode 100644 Editors/Audio/UICommands/OpenNewAudioProjectWindowCommand.cs delete mode 100644 Editors/Audio/Utility/WWiseHash.cs create mode 100644 Editors/Audio/Utility/WwiseHashRename.cs diff --git a/Editors/Audio/AudioEditor/AudioEditorService.cs b/Editors/Audio/AudioEditor/AudioEditorService.cs index 7a0f5c19c..af26585ce 100644 --- a/Editors/Audio/AudioEditor/AudioEditorService.cs +++ b/Editors/Audio/AudioEditor/AudioEditorService.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using System.Text; @@ -14,14 +13,11 @@ using Editors.Audio.AudioEditor.AudioSettings; using Editors.Audio.AudioEditor.DataGrids; using Editors.Audio.AudioProjectCompiler; -using Editors.Audio.GameSettings.Warhammer3; using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; using Shared.Core.Services; -using static Editors.Audio.GameSettings.Warhammer3.DialogueEvents; -using static Editors.Audio.GameSettings.Warhammer3.StateGroups; using TreeNode = Editors.Audio.AudioEditor.AudioProjectExplorer.TreeNode; namespace Editors.Audio.AudioEditor @@ -60,34 +56,29 @@ public AudioEditorService( } public AudioProject AudioProject { get; set; } - public string AudioProjectFileName { get; set; } - public string AudioProjectDirectory { get; set; } public AudioEditorViewModel AudioEditorViewModel { get; set; } public AudioProjectExplorerViewModel AudioProjectExplorerViewModel { get; set; } public AudioFilesExplorerViewModel AudioFilesExplorerViewModel { get; set; } public AudioProjectEditorViewModel AudioProjectEditorViewModel { get; set; } public AudioProjectViewerViewModel AudioProjectViewerViewModel { get; set; } public AudioSettingsViewModel AudioSettingsViewModel { get; set; } - public Dictionary> ModdedStatesByStateGroupLookup { get; set; } = []; - public Dictionary> DialogueEventsWithStateGroupsWithIntegrityError { get; set; } = []; - public Dictionary DialogueEventSoundBankFiltering { get; set; } = []; // TODO: Check if unused? Also check for other unused functions. + public Dictionary> ModdedStatesByStateGroupLookup { get; set; } = []; // TODO Replace this as it can just be extracted from the audio project directly when needed. - public void SaveAudioProject() + public void SaveAudioProject(AudioProject audioProject, string audioProjectFileName, string audioProjectDirectoryPath) { - var audioProject = GetAudioProjectWithoutUnusedObjects(); - var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, WriteIndented = true }; var audioProjectJson = JsonSerializer.Serialize(audioProject, options); - var audioProjectFileName = $"{AudioProjectFileName}.aproj"; - var audioProjectFilePath = $"{AudioProjectDirectory}\\{audioProjectFileName}"; + + audioProjectFileName = $"{audioProjectFileName}.aproj"; + var audioProjectFilePath = $"{audioProjectDirectoryPath}\\{audioProjectFileName}"; var packFile = PackFile.CreateFromASCII(audioProjectFileName, audioProjectJson); _fileSaveService.Save(audioProjectFilePath, packFile.DataSource.ReadData(), true); - _logger.Here().Information($"Saved Audio Project file: {AudioProjectDirectory}\\{AudioProjectFileName}.aproj"); + _logger.Here().Information($"Saved Audio Project file: {audioProjectFilePath}"); } public void LoadAudioProject(AudioEditorViewModel audioEditorViewModel) @@ -109,13 +100,13 @@ public void LoadAudioProject(AudioEditorViewModel audioEditorViewModel) ResetAudioProject(); // Set the AudioProject - var savedProject = JsonSerializer.Deserialize(audioProjectJson); - AudioProjectFileName = fileName.Replace(fileType, string.Empty); - AudioProjectDirectory = filePath.Replace($"\\{fileName}", string.Empty); + var loadedAudioProject = JsonSerializer.Deserialize(audioProjectJson); + loadedAudioProject.FileName = fileName.Replace(fileType, string.Empty); + loadedAudioProject.DirectoryPath = filePath.Replace($"\\{fileName}", string.Empty); - // Initialise a full Audio Project and merge the saved Audio Project with it - InitialiseAudioProject(AudioProjectFileName, AudioProjectDirectory, savedProject.Language); - MergeSavedAudioProjectIntoAudioProjectWithUnusedItems(savedProject); + // Initialise a 'full' Audio Project to include unused stuff + InitialiseAudioProject(loadedAudioProject.FileName, loadedAudioProject.DirectoryPath, loadedAudioProject.Language); + MergeSavedAudioProjectIntoAudioProjectWithUnusedItems(loadedAudioProject); // Initialise data after AudioProject is set so it uses the correct instance audioEditorViewModel.InitialiseAudioEditorData(); @@ -133,30 +124,25 @@ public void InitialiseAudioProject(string fileName, string directory, string lan { AudioEditorViewModel.AudioProjectExplorerViewModel.AudioProjectExplorerLabel = $"Audio Project Explorer - {DataGridHelpers.AddExtraUnderscoresToString(fileName)}"; - AudioProjectFileName = fileName; - AudioProjectDirectory = directory; + AudioProject = AudioProject.CreateAudioProject(); + AudioProject.FileName = fileName; + AudioProject.DirectoryPath = directory; AudioProject.Language = language; - InitialiseSoundBanks(); - - InitialiseModdedStatesGroups(); - - SortSoundBanksAlphabetically(); - AudioEditorViewModel.AudioProjectExplorerViewModel.CreateAudioProjectTree(); } public void CompileAudioProject() { - var audioProject = GetAudioProjectWithoutUnusedObjects(); + var audioProject = AudioProject.GetAudioProject(AudioProject); - SaveAudioProject(); + SaveAudioProject(audioProject, audioProject.FileName, audioProject.DirectoryPath); if (audioProject.SoundBanks == null) return; - var audioProjectFileName = AudioProjectFileName.Replace(" ", "_"); - _compilerDataProcessor.SetSoundBankData(audioProject, audioProjectFileName); + var audioProjectFileName = audioProject.FileName.Replace(" ", "_"); + _compilerDataProcessor.SetSoundBankData(audioProject); // We set the data from the bottom up, so Sounds, then Actions, then Events to ensure that IDs are generated before they're referenced. // For example IDs set in Sounds / Sound Containers are used in Actions, and IDs set in Actions are used in Events. @@ -188,75 +174,10 @@ public void CompileAudioProject() SaveCompiledAudioProjectToPack(audioProject); } - private void InitialiseSoundBanks() - { - var soundBanks = Enum.GetValues() - .Select(soundBankSubtype => new SoundBank - { - Name = SoundBanks.GetSoundBankSubTypeString(soundBankSubtype), - SoundBankType = SoundBanks.GetSoundBankSubType(soundBankSubtype) - }) - .ToList(); - - AudioProject.SoundBanks = []; - - foreach (var soundBankSubtype in Enum.GetValues()) - { - var soundBank = new SoundBank - { - Name = SoundBanks.GetSoundBankSubTypeString(soundBankSubtype), - SoundBankType = SoundBanks.GetSoundBankSubType(soundBankSubtype) - }; - - if (soundBank.SoundBankType == SoundBanks.Wh3SoundBankType.ActionEventSoundBank) - soundBank.ActionEvents = []; - else - { - soundBank.DialogueEvents = []; - - var filteredDialogueEvents = DialogueEventData - .Where(dialogueEvent => dialogueEvent.SoundBank == SoundBanks.GetSoundBankSubtype(soundBank.Name)); - - foreach (var dialogueData in filteredDialogueEvents) - { - var dialogueEvent = new DialogueEvent - { - Name = dialogueData.Name, - StatePaths = [] - }; - soundBank.DialogueEvents.Add(dialogueEvent); - } - } - - AudioProject.SoundBanks.Add(soundBank); - } - } - - private void InitialiseModdedStatesGroups() - { - AudioProject.StateGroups = []; - - foreach (var moddedStateGroup in ModdedStateGroups) - { - var stateGroup = new StateGroup { Name = moddedStateGroup, States = [] }; - AudioProject.StateGroups.Add(stateGroup); - } - } - - public void SortSoundBanksAlphabetically() - { - var sortedSoundBanks = AudioProject.SoundBanks.OrderBy(soundBank => soundBank.Name).ToList(); - - AudioProject.SoundBanks.Clear(); - - foreach (var soundBank in sortedSoundBanks) - AudioProject.SoundBanks.Add(soundBank); - } - public void BuildModdedStatesByStateGroupLookup(List moddedStateGroups, Dictionary> moddedStatesByStateGroupLookup) { if (moddedStatesByStateGroupLookup == null) - moddedStatesByStateGroupLookup = new Dictionary>(); + moddedStatesByStateGroupLookup = []; else moddedStatesByStateGroupLookup.Clear(); @@ -275,55 +196,7 @@ public void BuildModdedStatesByStateGroupLookup(List moddedStateGrou } } - private AudioProject GetAudioProjectWithoutUnusedObjects() - { - var usedSoundBanksList = AudioProject.SoundBanks - .Where(soundBank => soundBank != null) - .Select(soundBank => - { - var dialogueEvents = (soundBank.DialogueEvents ?? Enumerable.Empty()) - .Where(dialogueEvent => dialogueEvent.StatePaths != null && dialogueEvent.StatePaths.Count != 0) - .ToList(); - - var actionEvents = (soundBank.ActionEvents ?? Enumerable.Empty()) - .Where(actionEvent => actionEvent.Sound != null || actionEvent.RandomSequenceContainer != null) - .ToList(); - - return new SoundBank - { - Name = soundBank.Name, - SoundBankType = soundBank.SoundBankType, - DialogueEvents = dialogueEvents.Count != 0 - ? new List(dialogueEvents) - : null, - ActionEvents = actionEvents.Count != 0 - ? new List(actionEvents) - : null - }; - }) - .Where(soundBank => soundBank.DialogueEvents != null && soundBank.DialogueEvents.Any() || soundBank.ActionEvents != null && soundBank.ActionEvents.Any()) - .ToList(); - - var soundBanksResult = usedSoundBanksList.Count != 0 - ? new List(usedSoundBanksList) - : null; - - var usedStateGroupsList = (AudioProject.StateGroups ?? new List()) - .Where(stateGroup => stateGroup.States != null && stateGroup.States.Count != 0) - .ToList(); - - var stateGroupsResult = usedStateGroupsList.Count != 0 - ? new List(usedStateGroupsList) - : null; - - return new AudioProject - { - Language = AudioProject.Language, - SoundBanks = soundBanksResult, - StateGroups = stateGroupsResult - }; - } - + // The Audio Project Explorer displays the entire Audio Project including unused items, but we only save the used items to the Audio Project file private void MergeSavedAudioProjectIntoAudioProjectWithUnusedItems(AudioProject savedProject) { if (savedProject == null) @@ -397,8 +270,8 @@ private void SaveCompiledAudioProjectToPack(AudioProject audioProject) WriteIndented = true }; var audioProjectJson = JsonSerializer.Serialize(audioProject, options); - var audioProjectFileName = $"{AudioProjectFileName}_compiled.json"; - var audioProjectFilePath = $"{AudioProjectDirectory}\\{audioProjectFileName}"; + var audioProjectFileName = $"{audioProject.FileName}_compiled.json"; + var audioProjectFilePath = $"{audioProject.DirectoryPath}\\{audioProjectFileName}"; var packFile = PackFile.CreateFromASCII(audioProjectFileName, audioProjectJson); _fileSaveService.Save(audioProjectFilePath, packFile.DataSource.ReadData(), true); } @@ -413,19 +286,19 @@ public TreeNode GetSelectedExplorerNode() return AudioProjectExplorerViewModel._selectedAudioProjectTreeNode; } - public ObservableCollection> GetEditorDataGrid() + public DataTable GetEditorDataGrid() { return AudioProjectEditorViewModel.AudioProjectEditorDataGrid; } - public ObservableCollection> GetViewerDataGrid() + public DataTable GetViewerDataGrid() { return AudioProjectViewerViewModel.AudioProjectViewerDataGrid; } - public ObservableCollection> GetSelectedViewerRows() + public List GetSelectedViewerRows() { - return AudioProjectViewerViewModel.SelectedDataGridRows; + return AudioProjectViewerViewModel._selectedDataGridRows; } } } diff --git a/Editors/Audio/AudioEditor/AudioEditorViewModel.cs b/Editors/Audio/AudioEditor/AudioEditorViewModel.cs index 903048d06..2f871b92a 100644 --- a/Editors/Audio/AudioEditor/AudioEditorViewModel.cs +++ b/Editors/Audio/AudioEditor/AudioEditorViewModel.cs @@ -1,11 +1,13 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Editors.Audio.AudioEditor.AudioFilesExplorer; +using Editors.Audio.AudioEditor.AudioProjectData; using Editors.Audio.AudioEditor.AudioProjectEditor; using Editors.Audio.AudioEditor.AudioProjectExplorer; using Editors.Audio.AudioEditor.AudioProjectViewer; using Editors.Audio.AudioEditor.AudioSettings; -using Editors.Audio.AudioEditor.NewAudioProject; +using Editors.Audio.UICommands; +using Shared.Core.Events; using Shared.Core.PackFiles; using Shared.Core.Services; using Shared.Core.ToolCreation; @@ -13,6 +15,7 @@ namespace Editors.Audio.AudioEditor { + // TODO: Resolve TOOLTIP PLACEHOLDER instances public partial class AudioEditorViewModel : ObservableObject, IEditorInterface { public AudioProjectExplorerViewModel AudioProjectExplorerViewModel { get; } @@ -21,6 +24,7 @@ public partial class AudioEditorViewModel : ObservableObject, IEditorInterface public AudioProjectViewerViewModel AudioProjectViewerViewModel { get; } public AudioSettingsViewModel AudioSettingsViewModel { get; } + private readonly IUiCommandFactory _uiCommandFactory; private readonly IPackFileService _packFileService; private readonly IStandardDialogs _standardDialogs; private readonly IAudioEditorService _audioEditorService; @@ -29,6 +33,7 @@ public partial class AudioEditorViewModel : ObservableObject, IEditorInterface public string DisplayName { get; set; } = "Audio Editor"; public AudioEditorViewModel( + IUiCommandFactory uiCommandFactory, AudioProjectExplorerViewModel audioProjectExplorerViewModel, AudioFilesExplorerViewModel audioFilesExplorerViewModel, AudioProjectEditorViewModel audioProjectEditorViewModel, @@ -39,6 +44,7 @@ public AudioEditorViewModel( IAudioEditorService audioEditorService, IntegrityChecker integrityChecker) { + _uiCommandFactory = uiCommandFactory; _packFileService = packFileService; _standardDialogs = standardDialogs; _audioEditorService = audioEditorService; @@ -59,12 +65,13 @@ public AudioEditorViewModel( [RelayCommand] public void NewAudioProject() { - NewAudioProjectWindow.Show(_packFileService, _audioEditorService, _standardDialogs); + _uiCommandFactory.Create().Execute(); } [RelayCommand] public void SaveAudioProject() { - _audioEditorService.SaveAudioProject(); + var audioProject = AudioProject.GetAudioProject(_audioEditorService.AudioProject); + _audioEditorService.SaveAudioProject(audioProject, audioProject.FileName, audioProject.DirectoryPath); } [RelayCommand] public void LoadAudioProject() @@ -79,12 +86,13 @@ [RelayCommand] public void CompileAudioProject() public void InitialiseAudioEditorData() { - AudioProjectEditorViewModel.AudioProjectEditorDataGrid = []; - AudioProjectViewerViewModel.AudioProjectViewerDataGrid = []; - AudioProjectViewerViewModel.SelectedDataGridRows = []; - AudioProjectViewerViewModel.CopiedDataGridRows = []; + AudioProjectEditorViewModel.AudioProjectEditorDataGrid = new(); + AudioProjectViewerViewModel.AudioProjectViewerDataGrid = new(); + AudioProjectViewerViewModel._selectedDataGridRows = []; + AudioProjectViewerViewModel._copiedRows = []; AudioProjectExplorerViewModel.DialogueEventPresets = []; } + private void InitialiseAudioEditorService() { _audioEditorService.AudioEditorViewModel = this; @@ -94,12 +102,13 @@ private void InitialiseAudioEditorService() _audioEditorService.AudioProjectViewerViewModel = AudioProjectViewerViewModel; _audioEditorService.AudioSettingsViewModel = AudioSettingsViewModel; } + public void ResetAudioEditorData() { AudioProjectEditorViewModel.AudioProjectEditorDataGrid = null; AudioProjectViewerViewModel.AudioProjectViewerDataGrid = null; - AudioProjectViewerViewModel.SelectedDataGridRows = null; - AudioProjectViewerViewModel.CopiedDataGridRows = null; + AudioProjectViewerViewModel._selectedDataGridRows = null; + AudioProjectViewerViewModel._copiedRows = null; AudioProjectExplorerViewModel._selectedAudioProjectTreeNode = null; AudioProjectExplorerViewModel.AudioProjectTree.Clear(); } diff --git a/Editors/Audio/AudioEditor/AudioFilesExplorer/AudioFilesExplorerView.xaml b/Editors/Audio/AudioEditor/AudioFilesExplorer/AudioFilesExplorerView.xaml index 9192eb94f..4f4226784 100644 --- a/Editors/Audio/AudioEditor/AudioFilesExplorer/AudioFilesExplorerView.xaml +++ b/Editors/Audio/AudioEditor/AudioFilesExplorer/AudioFilesExplorerView.xaml @@ -68,10 +68,10 @@