diff --git a/BinarySerializer b/BinarySerializer index 5600316..40691ba 160000 --- a/BinarySerializer +++ b/BinarySerializer @@ -1 +1 @@ -Subproject commit 5600316c616aaa6a0028d5a2d041fcc100e4c79b +Subproject commit 40691ba75672e5e98b2f00b44a11d0baf02aa7ff diff --git a/ME3Tweaks.Wwiser.Tests/ChunkTests/BankHeaderTests.cs b/ME3Tweaks.Wwiser.Tests/ChunkTests/BankHeaderTests.cs index 8397d2b..b5d77ed 100644 --- a/ME3Tweaks.Wwiser.Tests/ChunkTests/BankHeaderTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ChunkTests/BankHeaderTests.cs @@ -3,7 +3,7 @@ namespace ME3Tweaks.Wwiser.Tests.ChunkTests; public class BankHeaderTests { [Test] - public void V134_Parses() + public void BKHD_V134_Parses() { var data = TestData.GetTestDataBytes(@"BankHeader",@"v134.bin"); var (_, result) = TestHelpers.Deserialize(data, 134); @@ -25,7 +25,7 @@ public void V134_Parses() } [Test] - public void V56_Parses() + public void BKHD_V56_Parses() { var data = TestData.GetTestDataBytes(@"BankHeader",@"v56.bin"); var (_, result) = TestHelpers.Deserialize(data, 56); @@ -48,12 +48,22 @@ public void V56_Parses() } [Test] - public void V134_Reserializes() + public void BKHD_V134_Reserializes() { var data = TestData.GetTestDataBytes(@"BankHeader",@"v134.bin"); var (_, result) = TestHelpers.Deserialize(data, 134); var reserialized = TestHelpers.Serialize(result, 134); - Assert.That(reserialized, Is.EqualTo(data)); + Assert.That(reserialized, Is.EquivalentTo(data)); + } + + [Test] + public void BKHD_V56_Reserializes() + { + var data = TestData.GetTestDataBytes(@"BankHeader",@"v56.bin"); + var (_, result) = TestHelpers.Deserialize(data, 56); + + var reserialized = TestHelpers.Serialize(result, 56); + Assert.That(reserialized, Is.EquivalentTo(data)); } } \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/ChunkTests/MediaIndexTests.cs b/ME3Tweaks.Wwiser.Tests/ChunkTests/MediaIndexTests.cs index 67bf96a..5244575 100644 --- a/ME3Tweaks.Wwiser.Tests/ChunkTests/MediaIndexTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ChunkTests/MediaIndexTests.cs @@ -3,7 +3,7 @@ public class MediaIndexTests { [Test] - public void V134_Parses() + public void DIDX_V134_Parses() { var data = TestData.GetTestDataBytes(@"MediaIndex",@"DIDXv134.bin"); var (_, result) = TestHelpers.Deserialize(data, 134); @@ -29,12 +29,12 @@ public void V134_Parses() } [Test] - public void V134_Reserializes() + public void DIDX_V134_Reserializes() { var data = TestData.GetTestDataBytes(@"MediaIndex",@"DIDXv134.bin"); var (_, result) = TestHelpers.Deserialize(data, 134); var reserialized = TestHelpers.Serialize(result, 134); - Assert.That(reserialized, Is.EqualTo(data)); + Assert.That(reserialized, Is.EquivalentTo(data)); } } \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/ChunkTests/StringMappingTests.cs b/ME3Tweaks.Wwiser.Tests/ChunkTests/StringMappingTests.cs index 567e5df..c54baf8 100644 --- a/ME3Tweaks.Wwiser.Tests/ChunkTests/StringMappingTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ChunkTests/StringMappingTests.cs @@ -3,7 +3,7 @@ public class StringMappingTests { [Test] - public void V56_Parses() + public void STID_V56_Parses() { var data = TestData.GetTestDataBytes(@"StringMapping",@"STIDv56.bin"); var (_, result) = TestHelpers.Deserialize(data, 56); @@ -29,12 +29,12 @@ public void V56_Parses() } [Test] - public void V56_Reserializes() + public void STID_V56_Reserializes() { var data = TestData.GetTestDataBytes(@"StringMapping",@"STIDv56.bin"); var (_, result) = TestHelpers.Deserialize(data, 56); var reserialized = TestHelpers.Serialize(result, 56); - Assert.That(reserialized, Is.EqualTo(data)); + Assert.That(reserialized, Is.EquivalentTo(data)); } } \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/ConvertTests/ActionConvertTests.cs b/ME3Tweaks.Wwiser.Tests/ConvertTests/ActionConvertTests.cs index ac7e360..976dae3 100644 --- a/ME3Tweaks.Wwiser.Tests/ConvertTests/ActionConvertTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ConvertTests/ActionConvertTests.cs @@ -5,7 +5,7 @@ namespace ME3Tweaks.Wwiser.Tests.ConvertTests; public class ActionTests { [Test] - public void Convert56to134_Works() + public void ConvertActionItem_56to134_Works() { var from = new BankSerializationContext(56); var to = new BankSerializationContext(134); @@ -18,7 +18,7 @@ public void Convert56to134_Works() } [Test] - public void Convert134to56_Works() + public void ConvertActionItem_134to56_Works() { var from = new BankSerializationContext(134); var to = new BankSerializationContext(56); diff --git a/ME3Tweaks.Wwiser.Tests/ConvertTests/ActorMixerConvertTests.cs b/ME3Tweaks.Wwiser.Tests/ConvertTests/ActorMixerConvertTests.cs index 958dd09..e979223 100644 --- a/ME3Tweaks.Wwiser.Tests/ConvertTests/ActorMixerConvertTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ConvertTests/ActorMixerConvertTests.cs @@ -6,7 +6,7 @@ namespace ME3Tweaks.Wwiser.Tests.ConvertTests; public class ActorMixerConvertTests { [Test] - public void Convert56to134_Works() + public void ConvertActorMixer_56to134_Works() { var from = new BankSerializationContext(56); var to = new BankSerializationContext(134); diff --git a/ME3Tweaks.Wwiser.Tests/ConvertTests/HircChunkConvertTests.cs b/ME3Tweaks.Wwiser.Tests/ConvertTests/HircChunkConvertTests.cs index 588b161..53c30fe 100644 --- a/ME3Tweaks.Wwiser.Tests/ConvertTests/HircChunkConvertTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ConvertTests/HircChunkConvertTests.cs @@ -7,7 +7,7 @@ namespace ME3Tweaks.Wwiser.Tests.ConvertTests; public class HircChunkConvertTests { [Test] - public void Convert56to134_Works() + public void ConvertHircChunk_56to134_ReturnsCorrectDataLength() { var from = new BankSerializationContext(56); var to = new BankSerializationContext(134); @@ -22,8 +22,8 @@ public void Convert56to134_Works() var data134 = TestData.GetTestDataBytes(@"Convert", @"HIRC", @"134.bin"); Assert.That(newData.Length, Is.EqualTo(data134.Length)); - var outfile = TestData.GetTestDataFilePath("Convert", "HIRC", "Out134"); + /*var outfile = TestData.GetTestDataFilePath("Convert", "HIRC", "Out134"); File.WriteAllText(outfile, string.Empty); // Wipe out file - TestHelpers.WriteStreamToFile(new MemoryStream(newData), outfile); + TestHelpers.WriteStreamToFile(new MemoryStream(newData), outfile);*/ } } \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/ConvertTests/ParameterNodeConvertTests.cs b/ME3Tweaks.Wwiser.Tests/ConvertTests/ParameterNodeConvertTests.cs index 10ed279..ae203a8 100644 --- a/ME3Tweaks.Wwiser.Tests/ConvertTests/ParameterNodeConvertTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ConvertTests/ParameterNodeConvertTests.cs @@ -6,7 +6,7 @@ namespace ME3Tweaks.Wwiser.Tests.ConvertTests; public class ParameterNodeConvertTests { [Test] - public void Convert56to134_Works() + public void ConvertParameterNode_56to134_Works() { var from = new BankSerializationContext(56); var to = new BankSerializationContext(134); @@ -23,7 +23,7 @@ public void Convert56to134_Works() } [Test] - public void Convert134to56_Works() + public void ConvertParameterNode_134to56_Works() { var from = new BankSerializationContext(134); var to = new BankSerializationContext(56); diff --git a/ME3Tweaks.Wwiser.Tests/FormatTests/BankHeaderPaddingTests.cs b/ME3Tweaks.Wwiser.Tests/FormatTests/BankHeaderPaddingTests.cs new file mode 100644 index 0000000..98519bf --- /dev/null +++ b/ME3Tweaks.Wwiser.Tests/FormatTests/BankHeaderPaddingTests.cs @@ -0,0 +1,39 @@ +namespace ME3Tweaks.Wwiser.Tests.FormatTests; + +public class BankHeaderPaddingTests +{ + [TestCase(8)] + [TestCase(24)] + [TestCase(0x158)] + public void DataProperlyAligned_PaddingIsZero(long dataOffset) + { + var padding = new BankHeaderPadding(); + padding.SetPadding(dataOffset); + + Assert.That(padding.Padding.Length, Is.EqualTo(0)); + } + + [TestCase(0, 8)] + [TestCase(4, 4)] + [TestCase(33, 7)] + public void DataNotAligned_PaddingAlignsProperly(long dataOffset, long expectedPadding) + { + var padding = new BankHeaderPadding(); + padding.SetPadding(dataOffset); + + Assert.That(padding.Padding.Length, Is.LessThanOrEqualTo(8)); + Assert.That(padding.Padding.Length, Is.EqualTo(expectedPadding)); + } + + [TestCase(15, 9)] + [TestCase(12, 12)] + [TestCase(0x15E, 10)] + public void DataNotAligned_PaddingProperlyOffsetBy8(long dataOffset, long expectedPadding) + { + var padding = new BankHeaderPadding(); + padding.SetPadding(dataOffset); + + Assert.That(padding.Padding.Length, Is.GreaterThan(8)); + Assert.That(padding.Padding.Length, Is.EqualTo(expectedPadding)); + } +} \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/FormatTests/UniTests.cs b/ME3Tweaks.Wwiser.Tests/FormatTests/UniTests.cs index d47d8aa..a2ded7a 100644 --- a/ME3Tweaks.Wwiser.Tests/FormatTests/UniTests.cs +++ b/ME3Tweaks.Wwiser.Tests/FormatTests/UniTests.cs @@ -8,7 +8,7 @@ public class UniTests [TestCase(new byte[] {0x0, 0x0, 0xC0, 0xC0 })] [TestCase(new byte[] {0x0, 0x0, 0x40, 0xC1 })] [TestCase(new byte[] {0xBF, 0x65, 0xD7, 0x17 })] - public void UniReserializes(byte[] data) + public void Uni_ReserializesSameBytes(byte[] data) { var (_, result) = TestHelpers.Deserialize(data, 113); var reserialized = TestHelpers.Serialize(result, 113); diff --git a/ME3Tweaks.Wwiser.Tests/HierarchyTests/HierarchyChunkTests.cs b/ME3Tweaks.Wwiser.Tests/HierarchyTests/HierarchyChunkTests.cs index 70aecd4..eb83192 100644 --- a/ME3Tweaks.Wwiser.Tests/HierarchyTests/HierarchyChunkTests.cs +++ b/ME3Tweaks.Wwiser.Tests/HierarchyTests/HierarchyChunkTests.cs @@ -5,8 +5,20 @@ namespace ME3Tweaks.Wwiser.Tests.HierarchyTests; public class HierarchyChunkTests { + [TestCase("HIRCv44.bin", 44)] + [TestCase("HIRCv56.bin", 56)] + [TestCase("HIRCv134.bin", 134)] + public void SimpleHircChunk_Reserializes(string fileName, int version) + { + var data = TestData.GetTestDataBytes(@"Hierarchy", @"SmallFullChunks", fileName); + var (serializer, result) = TestHelpers.Deserialize(data, version); + + var reserialized = TestHelpers.Serialize(result, version); + Assert.That(reserialized, Is.EquivalentTo(data)); + } + [Test] - public void SimpleChunk_v44_Parses() + public void SimpleHircChunk_v44_Parses() { var data = TestData.GetTestDataBytes(@"Hierarchy", @"SmallFullChunks", @"HIRCv44.bin"); var (serializer, result) = TestHelpers.Deserialize(data, 44); @@ -32,7 +44,7 @@ public void SimpleChunk_v44_Parses() } [Test] - public void SimpleChunk_v56_Parses() + public void SimpleHircChunk_v56_Parses() { var data = TestData.GetTestDataBytes(@"Hierarchy", @"SmallFullChunks", @"HIRCv56.bin"); var (serializer, result) = TestHelpers.Deserialize(data, 56); @@ -58,7 +70,7 @@ public void SimpleChunk_v56_Parses() } [Test] - public void SimpleChunk_v134_Parses() + public void SimpleHircChunk_v134_Parses() { var data = TestData.GetTestDataBytes(@"Hierarchy", @"SmallFullChunks", @"HIRCv134.bin"); var (serializer, result) = TestHelpers.Deserialize(data, 134); @@ -84,7 +96,7 @@ public void SimpleChunk_v134_Parses() } [Test] - public void BigChunkTest() + public void BigHircChunk_Reserializes() { var data = TestData.GetTestDataBytes(@"Hierarchy", @"LargeFullChunks", @"HIRC_V56.bin"); var (serializer, result) = TestHelpers.Deserialize(data, 56); diff --git a/ME3Tweaks.Wwiser.Tests/HierarchyTests/StateChunkTests.cs b/ME3Tweaks.Wwiser.Tests/HierarchyTests/StateChunkTests.cs index 4cf9172..4ec413d 100644 --- a/ME3Tweaks.Wwiser.Tests/HierarchyTests/StateChunkTests.cs +++ b/ME3Tweaks.Wwiser.Tests/HierarchyTests/StateChunkTests.cs @@ -7,7 +7,7 @@ public class StateChunkTests { [TestCase(new byte[] {00, 00}, 134)] [TestCase(new byte[] {00, 00, 00, 00}, 120)] - public void Empty_MultipleVersions_Parses(byte[] data, int version) + public void EmptyStateChunk_MultipleVersions_Parses(byte[] data, int version) { var (_, result) = TestHelpers.Deserialize(data, version); diff --git a/ME3Tweaks.Wwiser.Tests/HierarchyTests/SwitchContainerTests.cs b/ME3Tweaks.Wwiser.Tests/HierarchyTests/SwitchContainerTests.cs new file mode 100644 index 0000000..876818b --- /dev/null +++ b/ME3Tweaks.Wwiser.Tests/HierarchyTests/SwitchContainerTests.cs @@ -0,0 +1,16 @@ +using ME3Tweaks.Wwiser.Model.Hierarchy; + +namespace ME3Tweaks.Wwiser.Tests.HierarchyTests; + +public class SwitchContainerTests +{ + [TestCase("SwitchContainer_V56.bin", 56)] + public void SwitchContainer_Reserializes(string filename, int version) + { + var data = TestData.GetTestDataBytes(@"Hierarchy",@"SwitchContainer", filename); + var (_, result) = TestHelpers.Deserialize(data, version); + + var reserialized = TestHelpers.Serialize(result, version); + Assert.That(reserialized, Is.EquivalentTo(data)); + } +} \ No newline at end of file diff --git a/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/AdvSettingsTests.cs b/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/AdvSettingsTests.cs index e986902..5ba7eeb 100644 --- a/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/AdvSettingsTests.cs +++ b/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/AdvSettingsTests.cs @@ -6,7 +6,7 @@ public class AdvSettingsTests { [TestCase("Empty_V134.bin", 134)] [TestCase("Empty_V44.bin", 44)] - public void Empty_MultipleVersions_Reserializes(string file, int version) + public void EmptyAdvSettings_MultipleVersions_Reserializes(string file, int version) { var data = TestData.GetTestDataBytes(@"ParameterNode",@"AdvSettings", file); var (_, result) = TestHelpers.Deserialize(data, version); diff --git a/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/FullParameterNode.cs b/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/FullParameterNode.cs index 61b03fb..485d26d 100644 --- a/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/FullParameterNode.cs +++ b/ME3Tweaks.Wwiser.Tests/ParameterNodeTests/FullParameterNode.cs @@ -6,7 +6,7 @@ public class FullParameterNode { [TestCase("A_V134.bin", 134)] [TestCase("A_V56.bin", 56)] - public void Full_MultipleVersions_Reserializes(string file, int version) + public void FullParameterNode_MultipleVersions_Reserializes(string file, int version) { var data = TestData.GetTestDataBytes(@"ParameterNode", file); var (_, result) = TestHelpers.Deserialize(data, version); diff --git a/ME3Tweaks.Wwiser.Tests/TestData/Hierarchy/SwitchContainer/SwitchContainer_V56.bin b/ME3Tweaks.Wwiser.Tests/TestData/Hierarchy/SwitchContainer/SwitchContainer_V56.bin new file mode 100644 index 0000000..d5d5691 Binary files /dev/null and b/ME3Tweaks.Wwiser.Tests/TestData/Hierarchy/SwitchContainer/SwitchContainer_V56.bin differ diff --git a/ME3Tweaks.Wwiser.Tests/WwiseBankParserTests.cs b/ME3Tweaks.Wwiser.Tests/WwiseBankParserTests.cs index 7c0e456..38f513c 100644 --- a/ME3Tweaks.Wwiser.Tests/WwiseBankParserTests.cs +++ b/ME3Tweaks.Wwiser.Tests/WwiseBankParserTests.cs @@ -10,29 +10,42 @@ public void OnInstantiation_WithFullBank_ParsesVersionCorrectly(string bankFileN Assert.That(parser.Version, Is.EqualTo(correctVersion)); } + [Test] + public void FullBank_Reserializes_Synchronous() + { + var parser = new WwiseBankParser(TestData.GetTestDataFilePath("WholeBanks", "ME3_v56_1.bnk")); + parser.Deserialize(); + + var stream = new MemoryStream(); + parser.SerializeTo(stream); + //TestHelpers.WriteStreamToFile(stream, TestData.GetTestDataFilePath("WholeBanks", "Out1.bnk")); + var data = TestData.GetTestDataBytes("WholeBanks", "ME3_v56_1.bnk"); + Assert.That(stream.ToArray(), Is.EquivalentTo(data)); + } + [TestCase("ME3_v56_1.bnk")] [TestCase("ME3_v56_2.bnk")] [TestCase("ME3_v56_3.bnk")] - public async Task FullBank_V56_Reserializes(string filename) + public async Task FullBank_V56_Reserializes_Async(string filename) { var parser = new WwiseBankParser(TestData.GetTestDataFilePath("WholeBanks", filename)); - await parser.Deserialize(); + await parser.DeserializeAsync(); var stream = new MemoryStream(); - await parser.Serialize(stream); + await parser.SerializeToAsync(stream); //TestHelpers.WriteStreamToFile(stream, TestData.GetTestDataFilePath("WholeBanks", "Out1.bnk")); var data = TestData.GetTestDataBytes("WholeBanks", filename); Assert.That(stream.ToArray(), Is.EquivalentTo(data)); } [TestCase("LE3_v134_1.bnk")] // TODO: What is at the end of this file? - public async Task FullBank_V134_Reserializes(string filename) + public async Task FullBank_V134_Reserializes_Async(string filename) { var parser = new WwiseBankParser(TestData.GetTestDataFilePath("WholeBanks", filename)); - await parser.Deserialize(); + await parser.DeserializeAsync(); var stream = new MemoryStream(); - await parser.Serialize(stream); + await parser.SerializeToAsync(stream); //TestHelpers.WriteStreamToFile(stream, TestData.GetTestDataFilePath("WholeBanks", "Out1.bnk")); var data = TestData.GetTestDataBytes("WholeBanks", filename); var outData = stream.ToArray(); diff --git a/ME3Tweaks.Wwiser/BankConversion/AttenuationConverter.cs b/ME3Tweaks.Wwiser/BankConversion/AttenuationConverter.cs index 3b23a25..992b793 100644 --- a/ME3Tweaks.Wwiser/BankConversion/AttenuationConverter.cs +++ b/ME3Tweaks.Wwiser/BankConversion/AttenuationConverter.cs @@ -6,15 +6,19 @@ public class AttenuationConverter(BankSerializationContext from, BankSerializati { public void Convert(Attenuation item) { - item.Curves.Insert(2, item.Curves[1].Clone()); - item.CurveToUse.CurveMap[2] = 2; - for(var i = 3; i < item.CurveToUse.CurveMap.Length; i++) + if (item.Curves.Count >= 2) { - if (item.CurveToUse.CurveMap[i] > -1) item.CurveToUse.CurveMap[i]++; + item.Curves.Insert(2, item.Curves[1].Clone()); + item.CurveToUse.CurveMap[2] = 2; + for(var i = 3; i < item.CurveToUse.CurveMap.Length; i++) + { + if (item.CurveToUse.CurveMap[i] > -1) item.CurveToUse.CurveMap[i]++; + } } foreach (var c in item.Curves) { + // Could be mass effect le only RtpcConverter.ConvertRtpcFloatLt0(c); } } diff --git a/ME3Tweaks.Wwiser/Model/Action/Specific/SetGameParameter.cs b/ME3Tweaks.Wwiser/Model/Action/Specific/SetGameParameter.cs index 922d065..3c45c1a 100644 --- a/ME3Tweaks.Wwiser/Model/Action/Specific/SetGameParameter.cs +++ b/ME3Tweaks.Wwiser/Model/Action/Specific/SetGameParameter.cs @@ -4,7 +4,7 @@ namespace ME3Tweaks.Wwiser.Model.Action.Specific; -public class SetGameParameter +public class SetGameParameter : ISpecificParams { [FieldOrder(0)] [SerializeWhenVersion(89, ComparisonOperator.GreaterThan)] diff --git a/ME3Tweaks.Wwiser/Model/BankHeaderChunk.cs b/ME3Tweaks.Wwiser/Model/BankHeaderChunk.cs index 04f7106..b04c73a 100644 --- a/ME3Tweaks.Wwiser/Model/BankHeaderChunk.cs +++ b/ME3Tweaks.Wwiser/Model/BankHeaderChunk.cs @@ -97,9 +97,6 @@ public class BankHeaderPadding : IBinarySerializable public void Serialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext) { - /*var version = serializationContext.FindAncestor().Version; - var chunkSize = serializationContext.FindAncestor().ChunkSize; - stream.Write(new byte[GetPaddingSize(version, chunkSize)]);*/ stream.Write(Padding); } @@ -118,6 +115,22 @@ public void Deserialize(Stream stream, Endianness endianness, BinarySerializatio <= 141 => chunkSize - 0x14, _ => chunkSize - 0x14 - 0x04 - 0x10 }; + + /// + /// Sets the necessary padding for the DATA chunk. DATA must start at a multiple of 16 bytes + 8. IE 8, 24, 40, etc + /// + /// Initial offset of the DATA chunk + public void SetPadding(long dataChunkOffset) + { + var initAlignment = dataChunkOffset % 16; + Padding = initAlignment switch + { + < 8 => new byte[8 - initAlignment], + > 8 => new byte[8 + (16 - initAlignment)], + _ => Array.Empty() + }; + Array.Fill(Padding, (byte)0); + } } [Flags] diff --git a/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/GroupType.cs b/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/GroupType.cs new file mode 100644 index 0000000..77aed64 --- /dev/null +++ b/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/GroupType.cs @@ -0,0 +1,43 @@ +using BinarySerialization; + +namespace ME3Tweaks.Wwiser.Model.Hierarchy.Enums; + +public class GroupType : IBinarySerializable +{ + public GroupTypeInner Value { get; set; } + + public void Serialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext) + { + var version = serializationContext.FindAncestor().Version; + if (version <= 89) + { + stream.Write(BitConverter.GetBytes((uint)Value)); + } + else + { + stream.WriteByte((byte)Value); + } + } + + public void Deserialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext) + { + var version = serializationContext.FindAncestor().Version; + if (version <= 89) + { + Span span = stackalloc byte[4]; + var read = stream.Read(span); + if (read != 4) throw new Exception(); + Value = (GroupTypeInner)BitConverter.ToUInt32(span); + } + else + { + Value = (GroupTypeInner)stream.ReadByte(); + } + } + + public enum GroupTypeInner : uint + { + Switch, + State + } +} \ No newline at end of file diff --git a/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/OnSwitchMode.cs b/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/OnSwitchMode.cs new file mode 100644 index 0000000..4d939ab --- /dev/null +++ b/ME3Tweaks.Wwiser/Model/Hierarchy/Enums/OnSwitchMode.cs @@ -0,0 +1,7 @@ +namespace ME3Tweaks.Wwiser.Model.Hierarchy.Enums; + +public enum OnSwitchMode : uint +{ + PlayToEnd, + Stop +} \ No newline at end of file diff --git a/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemContainer.cs b/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemContainer.cs index 0d694ee..b058f26 100644 --- a/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemContainer.cs +++ b/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemContainer.cs @@ -13,6 +13,6 @@ public class HircItemContainer [FieldOrder(3)] [FieldLength(nameof(Size))] - [SubtypeFactory($"{nameof(Type)}.{nameof(Type.Value)}", typeof(HircTypeFactory))] + [SubtypeFactory($"{nameof(Type)}.{nameof(Type.Value)}", typeof(HircItemSubtypeFactory))] public required HircItem Item { get; set; } } \ No newline at end of file diff --git a/ME3Tweaks.Wwiser/Model/Hierarchy/HircTypeFactory.cs b/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemSubtypeFactory.cs similarity index 93% rename from ME3Tweaks.Wwiser/Model/Hierarchy/HircTypeFactory.cs rename to ME3Tweaks.Wwiser/Model/Hierarchy/HircItemSubtypeFactory.cs index 0536463..299a5d6 100644 --- a/ME3Tweaks.Wwiser/Model/Hierarchy/HircTypeFactory.cs +++ b/ME3Tweaks.Wwiser/Model/Hierarchy/HircItemSubtypeFactory.cs @@ -4,7 +4,7 @@ namespace ME3Tweaks.Wwiser.Model.Hierarchy; -public class HircTypeFactory : ISubtypeFactory +public class HircItemSubtypeFactory : ISubtypeFactory { private static readonly Dictionary TypeToEnum = new() { @@ -12,6 +12,7 @@ public class HircTypeFactory : ISubtypeFactory { typeof(Action), HircType.Action }, { typeof(Event), HircType.Event }, { typeof(RandSeqContainer), HircType.RandomSequenceContainer }, + { typeof(SwitchContainer), HircType.SwitchContainer }, { typeof(ActorMixer), HircType.ActorMixer }, { typeof(LayerContainer), HircType.LayerContainer }, { typeof(Attenuation), HircType.Attenuation }, @@ -46,7 +47,7 @@ public bool TryGetType(object key, [UnscopedRef] out Type type) HircType.Action => typeof(Action), HircType.Event => typeof(Event), HircType.RandomSequenceContainer => typeof(RandSeqContainer), - //HircType.SwitchContainer => + HircType.SwitchContainer => typeof(SwitchContainer), HircType.ActorMixer => typeof(ActorMixer), //HircType.Bus => HircType.LayerContainer => typeof(LayerContainer), diff --git a/ME3Tweaks.Wwiser/Model/Hierarchy/SwitchContainer.cs b/ME3Tweaks.Wwiser/Model/Hierarchy/SwitchContainer.cs new file mode 100644 index 0000000..056bf1e --- /dev/null +++ b/ME3Tweaks.Wwiser/Model/Hierarchy/SwitchContainer.cs @@ -0,0 +1,135 @@ +using BinarySerialization; +using ME3Tweaks.Wwiser.Model.Hierarchy.Enums; +using ME3Tweaks.Wwiser.Model.ParameterNode; + +namespace ME3Tweaks.Wwiser.Model.Hierarchy; + +public class SwitchContainer : HircItem, IHasNode +{ + [FieldOrder(0)] + public NodeBaseParameters NodeBaseParameters { get; set; } = new(); + + [FieldOrder(1)] + public GroupType GroupType { get; set; } = new(); + + [FieldOrder(2)] + public uint GroupId { get; set; } + + [FieldOrder(3)] + public uint DefaultSwitchId { get; set; } + + [FieldOrder(4)] + [SerializeAs(SerializedType.UInt1)] + public bool IsContinuousValidation { get; set; } + + [FieldOrder(5)] + public Children Children { get; set; } = new(); + + [FieldOrder(6)] + public uint SwitchGroupCount { get; set; } + + [FieldOrder(7)] + [FieldCount(nameof(SwitchGroupCount))] + public List SwitchGroups { get; set; } = new(); + + [FieldOrder(8)] + public uint SwitchParamsCount { get; set; } + + [FieldOrder(9)] + [FieldCount(nameof(SwitchParamsCount))] + public List SwitchParams { get; set; } = new(); +} + +public class SwitchParams : IAkIdentifiable, IBinarySerializable +{ + [Ignore] + public uint Id { get; set; } + + [Ignore] + public bool IsFirstOnly { get; set; } + + [Ignore] + public bool ContinuePlayback { get; set; } + + [Ignore] + public OnSwitchMode OnSwitchMode { get; set; } + + [Ignore] + public float FadeInTime { get; set; } + + [Ignore] + public float FadeOutTime { get; set; } + + public void Serialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext) + { + var version = serializationContext.FindAncestor().Version; + + stream.Write(BitConverter.GetBytes(Id)); + + if (version <= 89) + { + stream.WriteBoolByte(IsFirstOnly); + stream.WriteBoolByte(ContinuePlayback); + stream.Write(BitConverter.GetBytes((uint)OnSwitchMode)); + } + else + { + byte bitVector = 0; + if (IsFirstOnly) bitVector |= 1 << 0; + if (ContinuePlayback) bitVector |= 1 << 1; + stream.WriteByte(bitVector); + + stream.WriteByte((byte)OnSwitchMode); + } + + stream.Write(BitConverter.GetBytes(FadeInTime)); + stream.Write(BitConverter.GetBytes(FadeOutTime)); + } + + public void Deserialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext) + { + var version = serializationContext.FindAncestor().Version; + + Span span = stackalloc byte[4]; + var read = stream.Read(span); + if (read != 4) throw new Exception(); + Id = BitConverter.ToUInt32(span); + + if (version <= 89) + { + IsFirstOnly = stream.ReadBoolByte(); + ContinuePlayback = stream.ReadBoolByte(); + + read = stream.Read(span); + if (read != 4) throw new Exception(); + OnSwitchMode = (OnSwitchMode)BitConverter.ToUInt32(span); + } + else + { + var bitVector = stream.ReadByte(); + IsFirstOnly = (bitVector & (1 << 0)) == 1 << 0; + ContinuePlayback = (bitVector & (1 << 1)) == 1 << 1; + + OnSwitchMode = (OnSwitchMode)((byte)stream.ReadByte() & 0x7); + } + + + read = stream.Read(span); + if (read != 4) throw new Exception(); + FadeInTime = BitConverter.ToSingle(span); + + read = stream.Read(span); + if (read != 4) throw new Exception(); + FadeOutTime = BitConverter.ToSingle(span); + } +} + +public class SwitchGroup : AkIdentifiable +{ + [FieldOrder(0)] + public uint ItemCount { get; set; } + + [FieldOrder(1)] + [FieldCount(nameof(ItemCount))] + public List ItemIds { get; set; } = new(); +} \ No newline at end of file diff --git a/ME3Tweaks.Wwiser/WwiseBankParser.cs b/ME3Tweaks.Wwiser/WwiseBankParser.cs index 9612626..2dd4801 100644 --- a/ME3Tweaks.Wwiser/WwiseBankParser.cs +++ b/ME3Tweaks.Wwiser/WwiseBankParser.cs @@ -122,7 +122,7 @@ public void ConvertWithHeader(BankSerializationContext context) return (version, feedback); } - public async Task Deserialize() + public async Task DeserializeAsync() { if (_stream is null or { Length : 0 }) { @@ -134,15 +134,56 @@ public async Task Deserialize() .DeserializeAsync(_stream, CreateSerializationContext()); WwiseBank = new WwiseBank(root); } + + public void Deserialize() + { + if (_stream is null or { Length : 0 }) + { + throw new Exception("Inner stream is null or empty, cannot deserialize."); + } + + _stream.Position = 0; + var root = _serializer.Deserialize(_stream, CreateSerializationContext()); + WwiseBank = new WwiseBank(root); + } - public async Task Serialize(Stream stream) + public async Task SerializeToAsync(Stream stream) { if (WwiseBank is null) { throw new InvalidOperationException("Cannot serialize a null WwiseBank"); } + + SetBankHeaderPadding(); await _serializer.SerializeAsync(stream,WwiseBank.ToModel(), CreateSerializationContext()); } + + public void SerializeTo(Stream stream) + { + if (WwiseBank is null) + { + throw new InvalidOperationException("Cannot serialize a null WwiseBank"); + } + + SetBankHeaderPadding(); + _serializer.Serialize(stream,WwiseBank.ToModel(), CreateSerializationContext()); + } + + private void SetBankHeaderPadding() + { + if (WwiseBank?.DATA is not null) + { + var context = CreateSerializationContext(); + WwiseBank.BKHD.Padding = new BankHeaderPadding(); + + var bkhdSize= _serializer.SizeOf(new ChunkContainer(WwiseBank.BKHD), context); + var didxSize = (WwiseBank.DIDX != null) ? + _serializer.SizeOf(new ChunkContainer(WwiseBank.DIDX), context) : 0; + + var dataOffset = bkhdSize + didxSize; + WwiseBank.BKHD.Padding.SetPadding(dataOffset); + } + } private BankSerializationContext CreateSerializationContext() {