From 33e8d457ff14e011b6e28a6dfd9ede131207f7f4 Mon Sep 17 00:00:00 2001 From: Martin Benjamins Date: Mon, 15 Jul 2024 23:23:42 +0200 Subject: [PATCH 1/3] Basic implementation of LOD ADT --- Warcraft.NET/Files/ADT/Chunks/Legion/MBBB.cs | 79 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MBMB.cs | 78 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MBMH.cs | 80 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MBMI.cs | 79 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MBNV.cs | 80 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLDD.cs | 2 +- Warcraft.NET/Files/ADT/Chunks/Legion/MLDX.cs | 6 +- Warcraft.NET/Files/ADT/Chunks/Legion/MLFD.cs | 4 +- Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs | 81 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs | 100 +++++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs | 83 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLLL.cs | 79 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLLN.cs | 112 ++++++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs | 83 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLMD.cs | 6 +- Warcraft.NET/Files/ADT/Chunks/Legion/MLMX.cs | 6 +- Warcraft.NET/Files/ADT/Chunks/Legion/MLND.cs | 79 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLSI.cs | 79 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLVH.cs | 80 +++++++++ Warcraft.NET/Files/ADT/Chunks/Legion/MLVI.cs | 78 +++++++++ .../Files/ADT/Entries/Legion/MBBBEntry.cs | 68 ++++++++ .../Files/ADT/Entries/Legion/MBMHEntry.cs | 101 +++++++++++ .../Files/ADT/Entries/Legion/MBNVEntry.cs | 91 ++++++++++ .../Files/ADT/Entries/Legion/MLLLEntry.cs | 86 +++++++++ .../Files/ADT/Entries/Legion/MLNDEntry.cs | 93 ++++++++++ Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs | 26 +++ .../Files/ADT/TerrainLOD/Legion/TerrainLOD.cs | 164 ++++++++++++++++++ .../Files/ADT/TerrainLOD/TerrainLODBase.cs | 27 +++ 28 files changed, 1918 insertions(+), 12 deletions(-) create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MBBB.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MBMB.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MBMH.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MBMI.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MBNV.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLLL.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLLN.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLND.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLSI.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLVH.cs create mode 100644 Warcraft.NET/Files/ADT/Chunks/Legion/MLVI.cs create mode 100644 Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs create mode 100644 Warcraft.NET/Files/ADT/Entries/Legion/MBMHEntry.cs create mode 100644 Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs create mode 100644 Warcraft.NET/Files/ADT/Entries/Legion/MLLLEntry.cs create mode 100644 Warcraft.NET/Files/ADT/Entries/Legion/MLNDEntry.cs create mode 100644 Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs create mode 100644 Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs create mode 100644 Warcraft.NET/Files/ADT/TerrainLOD/TerrainLODBase.cs diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MBBB.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MBBB.cs new file mode 100644 index 0000000..2f261ba --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MBBB.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MBBB Chunk - Level of detail + /// + public class MBBB : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MBBB"; + + /// + /// Gets or sets s. + /// + public List MBBBEntries { get; set; } = []; + + /// + /// Initializes a new instance of the class. + /// + public MBBB() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBBB(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mbbbCount = br.BaseStream.Length / MBBBEntry.GetSize(); + for (var i = 0; i < mbbbCount; ++i) + { + MBBBEntries.Add(new MBBBEntry(br.ReadBytes(MBBBEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var mbbb in MBBBEntries) + { + bw.Write(mbbb.Serialize()); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MBMB.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMB.cs new file mode 100644 index 0000000..57e47c6 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMB.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MBMB Chunk - Level of detail + /// + public class MBMB : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MBMB"; + + /// + /// Unknown array with 20 byte elements. + /// + public List Entries = []; + + /// + /// Initializes a new instance of the class. + /// + public MBMB() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBMB(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mbmbCount = br.BaseStream.Length / 20; + for (var i = 0; i < mbmbCount; ++i) + { + Entries.Add(br.ReadBytes(20)); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var entry in Entries) + { + bw.Write(entry); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MBMH.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMH.cs new file mode 100644 index 0000000..566bf1f --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMH.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MBMH Chunk - Level of detail + /// + public class MBMH : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MBMH"; + + /// + /// Gets or sets s. + /// + public List MBMHEntries { get; set; } = []; + + /// + /// Initializes a new instance of the class. + /// + public MBMH() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBMH(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var objCount = br.BaseStream.Length / MBMHEntry.GetSize(); + + for (var i = 0; i < objCount; ++i) + { + MBMHEntries.Add(new MBMHEntry(br.ReadBytes(MBMHEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var mbmhEntry in MBMHEntries) + { + bw.Write(mbmhEntry.Serialize()); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MBMI.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMI.cs new file mode 100644 index 0000000..6137117 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MBMI.cs @@ -0,0 +1,79 @@ +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MBMI Chunk - Level of detail + /// + public class MBMI : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MBMI"; + + /// + /// Blend Mesh indices. + /// + public ushort[] BlendMeshIndices { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public MBMI() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBMI(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var count = (int)(ms.Length / 2); + BlendMeshIndices = new ushort[count]; + for (var i = 0; i < count; i++) + { + BlendMeshIndices[i] = br.ReadUInt16(); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var index in BlendMeshIndices) + { + bw.Write(index); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MBNV.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MBNV.cs new file mode 100644 index 0000000..6ad6a06 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MBNV.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MBMI Chunk - Level of detail + /// + public class MBNV : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MBNV"; + + /// + /// Blend Mesh Vertices. + /// + public List Entries { get; set; } = []; + + /// + /// Initializes a new instance of the class. + /// + public MBNV() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBNV(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mbnvCount = br.BaseStream.Length / MBNVEntry.GetSize(); + for (var i = 0; i < mbnvCount; ++i) + { + Entries.Add(new MBNVEntry(br.ReadBytes(MBNVEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var entry in Entries) + { + bw.Write(entry.Serialize()); + } + + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLDD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLDD.cs index eb32810..08319ed 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLDD.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLDD.cs @@ -23,7 +23,7 @@ public MLDD() : base() /// Initializes a new instance of the class. /// /// ExtendedData. - public MLDD(byte[] inData): base(inData) + public MLDD(byte[] inData) : base(inData) { } diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLDX.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLDX.cs index 2bc77a0..a98c11b 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLDX.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLDX.cs @@ -1,7 +1,7 @@ -using Warcraft.NET.Files.ADT.Entries.Legion; -using Warcraft.NET.Files.Interfaces; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; namespace Warcraft.NET.Files.ADT.Chunks.Legion { diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLFD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLFD.cs index 3b2a651..2162576 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLFD.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLFD.cs @@ -1,5 +1,5 @@ -using Warcraft.NET.Files.Interfaces; -using System.IO; +using System.IO; +using Warcraft.NET.Files.Interfaces; namespace Warcraft.NET.Files.ADT.Chunks.Legion { diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs new file mode 100644 index 0000000..e66bc27 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs @@ -0,0 +1,81 @@ +using System.IO; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Interfaces; +using Warcraft.NET.Files.Structures; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLHD Chunk - Level of detail header + /// + public class MLHD : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLHD"; + + /// + /// Unknown uint + /// + public uint Unknown0 { get; set; } + + /// + /// Unknown bounding box + /// + public BoundingBox UnkBoundingBox { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public MLHD() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLHD(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + Unknown0 = br.ReadUInt32(); + UnkBoundingBox = new BoundingBox(br.ReadVector3(AxisConfiguration.Native), br.ReadVector3(AxisConfiguration.Native)); + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return 28; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(Unknown0); + bw.WriteVector3(UnkBoundingBox.Minimum); + bw.WriteVector3(UnkBoundingBox.Maximum); + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs new file mode 100644 index 0000000..979b00f --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs @@ -0,0 +1,100 @@ +using System.IO; +using Warcraft.NET.Files.ADT.Flags; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLLD Chunk - Level of detail + /// + public class MLLD : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLLD"; + + /// + /// Flags. + /// + public MLLDFlags Flags { get; set; } + + /// + /// Size of the first (possibly compressed) depth chunk. + /// + public ushort DepthChunkSize { get; set; } + + /// + /// Approximate size of the second (possibly compressed) alpha chunk. Possibly off by 4-7 bytes. + /// + public ushort ApproxAlphaChunkSize { get; set; } + + /// + /// Data of the first (possibly compressed) depth chunk. + /// + public byte[] DepthChunkData { get; set; } + + /// + /// Data of the second (possibly compressed) alpha chunk. + /// Note: there might be 4-7 extra bytes at the end due to not full understand of this chunk. + /// + public byte[] AlphaChunkDataMaybe { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLLD() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLD(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + Flags = (MLLDFlags)br.ReadUInt32(); + DepthChunkSize = br.ReadUInt16(); + ApproxAlphaChunkSize = br.ReadUInt16(); + DepthChunkData = br.ReadBytes(DepthChunkSize); + AlphaChunkDataMaybe = br.ReadBytes((int)(ms.Length - ms.Position)); + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write((uint)Flags); + bw.Write(DepthChunkSize); + bw.Write(ApproxAlphaChunkSize); + bw.Write(DepthChunkData); + bw.Write(AlphaChunkDataMaybe); + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs new file mode 100644 index 0000000..ab5eb49 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs @@ -0,0 +1,83 @@ +using System.IO; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Interfaces; +using Warcraft.NET.Files.Structures; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLLI Chunk - Level of detail indices + /// + public class MLLI : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLLI"; + + /// + /// Unknown. + /// + public ShortVector3[] LiquidIndices { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public MLLI() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLI(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var vertexCount = inData.Length / 6; + LiquidIndices = new ShortVector3[vertexCount]; + for (var i = 0; i < vertexCount; ++i) + { + LiquidIndices[i] = br.ReadShortVector3(Structures.AxisConfiguration.Native); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var vertex in LiquidIndices) + { + bw.Write(vertex.X); + bw.Write(vertex.Y); + bw.Write(vertex.Z); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLL.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLL.cs new file mode 100644 index 0000000..20a8d52 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLL.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLLL Chunk - Level of detail levels + /// + public class MLLL : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLLL"; + + /// + /// Gets or sets s. + /// + public List MLLLEntries { get; set; } = []; + + /// + /// Initializes a new instance of the class. + /// + public MLLL() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLL(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mlllCount = br.BaseStream.Length / MLLLEntry.GetSize(); + for (var i = 0; i < mlllCount; ++i) + { + MLLLEntries.Add(new MLLLEntry(br.ReadBytes(MLLLEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var entry in MLLLEntries) + { + bw.Write(entry.Serialize()); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLN.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLN.cs new file mode 100644 index 0000000..aa82074 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLN.cs @@ -0,0 +1,112 @@ +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLLN Chunk - Level of detail liquid + /// + public class MLLN : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLLN"; + + /// + /// Unknown. + /// + public uint Unknown0 { get; set; } + + /// + /// MLLI Length. + /// + public uint MLLILength { get; set; } + + /// + /// Unknown. + /// + public uint Unknown2 { get; set; } + + /// + /// Unknown. + /// + public ushort Unknown3A { get; set; } + + /// + /// Unknown. + /// + public ushort Unknown3B { get; set; } + + /// + /// Unknown. + /// + public uint Unknown4 { get; set; } + + /// + /// Unknown. + /// + public uint Unknown5 { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLLN() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLN(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + Unknown0 = br.ReadUInt32(); + MLLILength = br.ReadUInt32(); + Unknown2 = br.ReadUInt32(); + Unknown3A = br.ReadUInt16(); + Unknown3B = br.ReadUInt16(); + Unknown4 = br.ReadUInt32(); + Unknown5 = br.ReadUInt32(); + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(Unknown0); + bw.Write(MLLILength); + bw.Write(Unknown2); + bw.Write(Unknown3A); + bw.Write(Unknown3B); + bw.Write(Unknown4); + bw.Write(Unknown5); + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs new file mode 100644 index 0000000..0f1b882 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs @@ -0,0 +1,83 @@ +using System.IO; +using System.Numerics; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLLV Chunk - Level of detail vertices + /// + public class MLLV : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLLV"; + + /// + /// Unknown. + /// + public Vector3[] LiquidVertices { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public MLLV() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLV(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var vertexCount = inData.Length / 12; + LiquidVertices = new Vector3[vertexCount]; + for (var i = 0; i < vertexCount; ++i) + { + LiquidVertices[i] = br.ReadVector3(Structures.AxisConfiguration.Native); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var vertex in LiquidVertices) + { + bw.Write(vertex.X); + bw.Write(vertex.Y); + bw.Write(vertex.Z); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLMD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLMD.cs index f5605a5..c753a0b 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLMD.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLMD.cs @@ -1,7 +1,7 @@ -using Warcraft.NET.Files.ADT.Entries.Legion; -using Warcraft.NET.Files.Interfaces; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; namespace Warcraft.NET.Files.ADT.Chunks.Legion { diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLMX.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLMX.cs index ab02638..ddbecc3 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLMX.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLMX.cs @@ -1,7 +1,7 @@ -using Warcraft.NET.Files.ADT.Entries.Legion; -using Warcraft.NET.Files.Interfaces; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; namespace Warcraft.NET.Files.ADT.Chunks.Legion { diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLND.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLND.cs new file mode 100644 index 0000000..f62a9dc --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLND.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Files.ADT.Entries.Legion; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLND Chunk - Level of detail + /// + public class MLND : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLND"; + + /// + /// Gets or sets s. + /// + public List MLNDEntries { get; set; } = []; + + /// + /// Initializes a new instance of the class. + /// + public MLND() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLND(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mlndCount = br.BaseStream.Length / MLNDEntry.GetSize(); + for (var i = 0; i < mlndCount; ++i) + { + MLNDEntries.Add(new MLNDEntry(br.ReadBytes(MLNDEntry.GetSize()))); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var entry in MLNDEntries) + { + bw.Write(entry.Serialize()); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLSI.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLSI.cs new file mode 100644 index 0000000..b3299e7 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLSI.cs @@ -0,0 +1,79 @@ +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLSI Chunk - Level of detail + /// + public class MLSI : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLSI"; + + /// + /// Skirt indices. + /// + public ushort[] SkirtIndices { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLSI() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLSI(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mlsiCount = br.BaseStream.Length / sizeof(uint); + SkirtIndices = new ushort[mlsiCount]; + for (var i = 0; i < mlsiCount; i++) + { + SkirtIndices[i] = br.ReadUInt16(); + } + + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var skirtIndex in SkirtIndices) + { + bw.Write(skirtIndex); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLVH.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLVH.cs new file mode 100644 index 0000000..3556de8 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLVH.cs @@ -0,0 +1,80 @@ +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLVH Chunk - Level of detail heightmap + /// + public class MLVH : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLVH"; + + /// + /// Height data. + /// + public float[] HeightData { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLVH() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLVH(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var heightCount = br.BaseStream.Length / sizeof(float); + + HeightData = new float[heightCount]; + + for (var i = 0; i < heightCount; i++) + { + HeightData[i] = br.ReadSingle(); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)Serialize().Length; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var height in HeightData) + { + bw.Write(height); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLVI.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLVI.cs new file mode 100644 index 0000000..ee230f0 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLVI.cs @@ -0,0 +1,78 @@ +using System.IO; +using Warcraft.NET.Files.Interfaces; + +namespace Warcraft.NET.Files.ADT.Chunks.Legion +{ + /// + /// MLVI Chunk - Level of detail + /// + public class MLVI : IIFFChunk, IBinarySerializable + { + /// + /// Holds the binary chunk signature. + /// + public const string Signature = "MLVI"; + + /// + /// Vertex indices. + /// + public ushort[] VertexIndices { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLVI() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLVI(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) + { + using (var ms = new MemoryStream(inData)) + using (var br = new BinaryReader(ms)) + { + var mlviCount = br.BaseStream.Length / sizeof(uint); + VertexIndices = new ushort[mlviCount]; + for (var i = 0; i < mlviCount; i++) + { + VertexIndices[i] = br.ReadUInt16(); + } + } + } + + /// + public string GetSignature() + { + return Signature; + } + + /// + public uint GetSize() + { + return (uint)VertexIndices.Length * 4; + } + + /// + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + foreach (var vertexIndex in VertexIndices) + { + bw.Write(vertexIndex); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs new file mode 100644 index 0000000..d8f65be --- /dev/null +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs @@ -0,0 +1,68 @@ +using System.IO; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Structures; + +namespace Warcraft.NET.Files.ADT.Entries.Legion +{ + /// + /// Blend mesh bounding box entry. + /// + public class MBBBEntry + { + /// + /// Unique ID of the map object. + /// + public uint MapObjectID { get; set; } + + /// + /// Bounding box. + /// + public BoundingBox BoundingBox { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MBBBEntry() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBBBEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + using (var br = new BinaryReader(ms)) + { + MapObjectID = br.ReadUInt32(); + BoundingBox = new BoundingBox(br.ReadVector3(AxisConfiguration.Native), br.ReadVector3(AxisConfiguration.Native)); + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 28; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(MapObjectID); + bw.WriteVector3(BoundingBox.Minimum); + bw.WriteVector3(BoundingBox.Maximum); + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MBMHEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MBMHEntry.cs new file mode 100644 index 0000000..d033092 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MBMHEntry.cs @@ -0,0 +1,101 @@ +using System.IO; + +namespace Warcraft.NET.Files.ADT.Entries.Legion +{ + /// + /// Blend mesh header entry. + /// + public class MBMHEntry + { + /// + /// Unique ID of the map object. + /// + public uint MapObjectID { get; set; } + + /// + /// Texture ID of linked WMO. + /// + public uint TextureID { get; set; } + + /// + /// Unknown value (wiki says always 0). + /// + public uint Unknown0 { get; set; } + + /// + /// Number of records in MBMI chunk for this mesh. + /// + public uint MBMICount { get; set; } + + /// + /// Number of records in MBNV chunk for this mesh. + /// + public uint MBNVCount { get; set; } + + /// + /// Offset to start record in MBMI chunk for this mesh. + /// + public uint MBMIStart { get; set; } + + /// + /// Offset to start record in MBNV chunk for this mesh. + /// + public uint MBNVStart { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MBMHEntry() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBMHEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + using (var br = new BinaryReader(ms)) + { + MapObjectID = br.ReadUInt32(); + TextureID = br.ReadUInt32(); + Unknown0 = br.ReadUInt32(); + MBMICount = br.ReadUInt32(); + MBNVCount = br.ReadUInt32(); + MBMIStart = br.ReadUInt32(); + MBNVStart = br.ReadUInt32(); + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 28; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(MapObjectID); + bw.Write(TextureID); + bw.Write(Unknown0); + bw.Write(MBMICount); + bw.Write(MBNVCount); + bw.Write(MBMIStart); + bw.Write(MBNVStart); + + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs new file mode 100644 index 0000000..05a6ac1 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs @@ -0,0 +1,91 @@ +using System.IO; +using System.Numerics; +using Warcraft.NET.Extensions; + +namespace Warcraft.NET.Files.ADT.Entries.Legion +{ + /// + /// Blend mesh vertices entry. + /// + public class MBNVEntry + { + /// + /// Vertex position. + /// + public Vector3 Position { get; set; } + + /// + /// Vertex normal. + /// + public Vector3 Normal { get; set; } + + /// + /// Texture/UV coordinate. + /// + public Vector2 TextureCoordinates { get; set; } + + /// + /// Color. + /// + public uint[] Color { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MBNVEntry() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MBNVEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + using (var br = new BinaryReader(ms)) + { + Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + Normal = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); + TextureCoordinates = new Vector2(br.ReadSingle(), br.ReadSingle()); + Color = new uint[3]; + for (var i = 0; i < 3; i++) + { + Color[i] = br.ReadUInt32(); + } + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 44; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.WriteVector3(Position); + bw.WriteVector3(Normal); + bw.Write(TextureCoordinates.X); + bw.Write(TextureCoordinates.Y); + + for (var i = 0; i < 3; i++) + { + bw.Write(Color[i]); + } + + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MLLLEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MLLLEntry.cs new file mode 100644 index 0000000..8749215 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MLLLEntry.cs @@ -0,0 +1,86 @@ +using System.IO; + +namespace Warcraft.NET.Files.ADT.Entries.Legion +{ + /// + /// LOD level entry. + /// + public class MLLLEntry + { + /// + /// LOD bands. + /// + public float LODBands { get; set; } + + /// + /// Height length. + /// + public uint HeightLength { get; set; } + + /// + /// Height index. + /// + public uint HeightIndex { get; set; } + + /// + /// MapAreaLow (WDL) length. + /// + public uint MapAreaLowLength { get; set; } + + /// + /// MapAreaLow (WDL) index. + /// + public uint MapAreaLowIndex { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLLLEntry() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLLLEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + using (var br = new BinaryReader(ms)) + { + LODBands = br.ReadSingle(); + HeightLength = br.ReadUInt32(); + HeightIndex = br.ReadUInt32(); + MapAreaLowLength = br.ReadUInt32(); + MapAreaLowIndex = br.ReadUInt32(); + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 20; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(LODBands); + bw.Write(HeightLength); + bw.Write(HeightIndex); + bw.Write(MapAreaLowLength); + bw.Write(MapAreaLowIndex); + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MLNDEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MLNDEntry.cs new file mode 100644 index 0000000..e46b2e5 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MLNDEntry.cs @@ -0,0 +1,93 @@ +using System.IO; + +namespace Warcraft.NET.Files.ADT.Entries.Legion +{ + /// + /// LOD quad tree entry. + /// + public class MLNDEntry + { + /// + /// MLVI used element offset + /// + public uint MLVIOffset { get; set; } + + /// + /// MLVI used element length + /// + public uint MLVILength { get; set; } + + /// + /// Unknown 0. + /// + public uint Unknown0 { get; set; } + + /// + /// Unknown 1. + /// + public uint Unknown1 { get; set; } + + /// + /// Indexes into MLND for child leaves. + /// + public ushort[] Indices { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public MLNDEntry() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// ExtendedData. + public MLNDEntry(byte[] data) + { + using (var ms = new MemoryStream(data)) + using (var br = new BinaryReader(ms)) + { + MLVIOffset = br.ReadUInt32(); + MLVILength = br.ReadUInt32(); + Unknown0 = br.ReadUInt32(); + Unknown1 = br.ReadUInt32(); + Indices = new ushort[4]; + for (var i = 0; i < 4; ++i) + { + Indices[i] = br.ReadUInt16(); + } + } + } + + /// + /// Gets the size of an entry. + /// + /// The size. + public static int GetSize() + { + return 24; + } + + /// + /// Gets the size of the data contained in this chunk. + /// + /// The size. + public byte[] Serialize(long offset = 0) + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(MLVIOffset); + bw.Write(MLVILength); + bw.Write(Unknown0); + bw.Write(Unknown1); + foreach (var index in Indices) + { + bw.Write(index); + } + return ms.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs b/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs new file mode 100644 index 0000000..3d63fa9 --- /dev/null +++ b/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs @@ -0,0 +1,26 @@ +using System; + +namespace Warcraft.NET.Files.ADT.Flags +{ + /// + /// Flags for the . + /// + [Flags] + public enum MLLDFlags : uint + { + /// + /// Has Tile Data + /// + Flag_HasTileData = 0x1, + + /// + /// Depth (first) chunk is compressed. + /// + Flag_DepthChunkCompressed = 0x2, + + /// + /// Alpha (second) chunk is compressed. + /// + Flag_AlphaChunkCompressed = 0x4, + } +} diff --git a/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs b/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs new file mode 100644 index 0000000..21cceac --- /dev/null +++ b/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs @@ -0,0 +1,164 @@ +using System.Collections.Generic; +using System.IO; +using Warcraft.NET.Attribute; +using Warcraft.NET.Extensions; +using Warcraft.NET.Files.ADT.Chunks; +using Warcraft.NET.Files.ADT.Chunks.Legion; +using Warcraft.NET.Types; + +namespace Warcraft.NET.Files.ADT.TerrainLOD.Legion +{ +#nullable enable + public class TerrainLOD : TerrainLODBase + { + /// + /// + /// + [ChunkOrder(2)] + public MLHD Header { get; set; } + + /// + /// + /// + [ChunkOrder(3)] + public MLVH Heightmap { get; set; } + + /// + /// + /// + [ChunkOrder(4)] + public MLLL Levels { get; set; } + + /// + /// + /// + [ChunkOrder(5)] + public MLND QuadTree { get; set; } + + /// + /// + /// + [ChunkOrder(6)] + public MLVI VertexIndices { get; set; } + + /// + /// + /// + [ChunkOrder(7)] + public MLSI SkirtIndices { get; set; } + + /// + /// Blend mesh headers. + /// + [ChunkOrder(8), ChunkOptional] + public MBMH BlendMeshHeaders { get; set; } + + /// + /// Blend mesh bounding boxes. + /// + [ChunkOrder(9), ChunkOptional] + public MBBB BlendMeshBoundingBoxes { get; set; } + + /// + /// Blend mesh indices. + /// + [ChunkOrder(10), ChunkOptional] + public MBMI BlendMeshIndices { get; set; } + + /// + /// Blend mesh vertices. + /// + [ChunkOrder(11), ChunkOptional] + public MBNV BlendMeshVertices { get; set; } + + /// + /// Blend mesh batches. + /// + [ChunkOrder(12), ChunkOptional] + public MBMB BlendMeshBatches { get; set; } + + /// + /// Liquid data. + /// TODO: Requires additional implementation for decompressing as well as properly reading the last chunk. + /// + [ChunkOrder(13), ChunkOptional] + public MLLD LiquidData { get; set; } + + /// + /// + /// + public SynchronizedList LiquidN { get; set; } = new SynchronizedList(new List(4096)); + + /// + /// + /// + public SynchronizedList LiquidIndices { get; set; } = new SynchronizedList(new List(4096)); + + /// + /// + /// + public SynchronizedList LiquidVertices { get; set; } = new SynchronizedList(new List(4096)); + + /// + /// Initializes a new instance of the class. + /// + public TerrainLOD() : base() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The binary data. + public TerrainLOD(byte[] inData) + { + using var ms = new MemoryStream(inData); + using var br = new BinaryReader(ms); + + Version = br.ReadIFFChunk(false, false); + Header = br.ReadIFFChunk(false, false); + Heightmap = br.ReadIFFChunk(false, false); + Levels = br.ReadIFFChunk(false, false); + QuadTree = br.ReadIFFChunk(false, false); + VertexIndices = br.ReadIFFChunk(false, false); + SkirtIndices = br.ReadIFFChunk(false, false); + + while (br.BaseStream.Position < br.BaseStream.Length) + { + var chunk = br.PeekChunkSignature(); + + switch (chunk) + { + case "MBMH": + BlendMeshHeaders = br.ReadIFFChunk(false, false); + break; + case "MBBB": + BlendMeshBoundingBoxes = br.ReadIFFChunk(false, false); + break; + case "MBMI": + BlendMeshIndices = br.ReadIFFChunk(false, false); + break; + case "MBNV": + BlendMeshVertices = br.ReadIFFChunk(false, false); + break; + case "MBMB": + BlendMeshBatches = br.ReadIFFChunk(false, false); + break; + case "MLLD": + LiquidData = br.ReadIFFChunk(false, false); + break; + case "MLLN": + LiquidN.Add(br.ReadIFFChunk(false, false)); + break; + case "MLLI": + LiquidIndices.Add(br.ReadIFFChunk(false, false)); + break; + case "MLLV": + LiquidVertices.Add(br.ReadIFFChunk(false, false)); + break; + } + } + } + } +#nullable disable +} diff --git a/Warcraft.NET/Files/ADT/TerrainLOD/TerrainLODBase.cs b/Warcraft.NET/Files/ADT/TerrainLOD/TerrainLODBase.cs new file mode 100644 index 0000000..cbc3d8c --- /dev/null +++ b/Warcraft.NET/Files/ADT/TerrainLOD/TerrainLODBase.cs @@ -0,0 +1,27 @@ +using Warcraft.NET.Attribute; +using Warcraft.NET.Files.ADT.Chunks; + +namespace Warcraft.NET.Files.ADT.TerrainLOD +{ + public abstract class TerrainLODBase : ChunkedFile + { + [ChunkOrder(1)] + public MVER Version { get; set; } + + + /// + /// Initializes a new instance of the class. + /// + public TerrainLODBase() : base() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The binary data. + public TerrainLODBase(byte[] inData) : base(inData) + { + } + } +} From 2528c5dac0a92994209a15b3be45b97b248b3673 Mon Sep 17 00:00:00 2001 From: Martin Benjamins Date: Mon, 15 Jul 2024 23:31:04 +0200 Subject: [PATCH 2/3] Remove unneeded new keywords --- Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs b/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs index 459512c..b5ff613 100644 --- a/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs +++ b/Warcraft.NET/Files/WDT/Entries/SL/MPL3Entry.cs @@ -110,7 +110,7 @@ public MPL3Entry(byte[] data) /// Gets the size of an entry. /// /// The size. - public new static int GetSize() + public static int GetSize() { return 56; } @@ -119,7 +119,7 @@ public MPL3Entry(byte[] data) /// Gets the size of the data contained in this chunk. /// /// The size. - public new byte[] Serialize(long offset = 0) + public byte[] Serialize(long offset = 0) { using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) From 51ca8db08f41a2b14d970fc78d2d57fef3e2682f Mon Sep 17 00:00:00 2001 From: Martin Benjamins Date: Tue, 16 Jul 2024 15:00:48 +0200 Subject: [PATCH 3/3] Fix some things based on feedback --- Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs | 5 ++-- Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs | 6 ++--- Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs | 6 ++--- Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs | 6 ++--- .../Files/ADT/Entries/Legion/MBBBEntry.cs | 5 ++-- .../Files/ADT/Entries/Legion/MBNVEntry.cs | 9 +++---- Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs | 6 ++--- .../Files/ADT/TerrainLOD/Legion/TerrainLOD.cs | 24 ++++++++++++------- 8 files changed, 34 insertions(+), 33 deletions(-) diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs index e66bc27..02b144d 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLHD.cs @@ -49,7 +49,7 @@ public void LoadBinaryData(byte[] inData) using (var br = new BinaryReader(ms)) { Unknown0 = br.ReadUInt32(); - UnkBoundingBox = new BoundingBox(br.ReadVector3(AxisConfiguration.Native), br.ReadVector3(AxisConfiguration.Native)); + UnkBoundingBox = br.ReadBoundingBox(); } } @@ -72,8 +72,7 @@ public byte[] Serialize(long offset = 0) using (var bw = new BinaryWriter(ms)) { bw.Write(Unknown0); - bw.WriteVector3(UnkBoundingBox.Minimum); - bw.WriteVector3(UnkBoundingBox.Maximum); + bw.WriteBoundingBox(UnkBoundingBox); return ms.ToArray(); } } diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs index 979b00f..20fb1a4 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLD.cs @@ -38,7 +38,7 @@ public class MLLD : IIFFChunk, IBinarySerializable /// Data of the second (possibly compressed) alpha chunk. /// Note: there might be 4-7 extra bytes at the end due to not full understand of this chunk. /// - public byte[] AlphaChunkDataMaybe { get; set; } + public byte[] AlphaChunkData { get; set; } /// /// Initializes a new instance of the class. @@ -66,7 +66,7 @@ public void LoadBinaryData(byte[] inData) DepthChunkSize = br.ReadUInt16(); ApproxAlphaChunkSize = br.ReadUInt16(); DepthChunkData = br.ReadBytes(DepthChunkSize); - AlphaChunkDataMaybe = br.ReadBytes((int)(ms.Length - ms.Position)); + AlphaChunkData = br.ReadBytes((int)(ms.Length - ms.Position)); } } @@ -92,7 +92,7 @@ public byte[] Serialize(long offset = 0) bw.Write(DepthChunkSize); bw.Write(ApproxAlphaChunkSize); bw.Write(DepthChunkData); - bw.Write(AlphaChunkDataMaybe); + bw.Write(AlphaChunkData); return ms.ToArray(); } } diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs index ab5eb49..7a48646 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLI.cs @@ -47,7 +47,7 @@ public void LoadBinaryData(byte[] inData) LiquidIndices = new ShortVector3[vertexCount]; for (var i = 0; i < vertexCount; ++i) { - LiquidIndices[i] = br.ReadShortVector3(Structures.AxisConfiguration.Native); + LiquidIndices[i] = br.ReadShortVector3(); } } } @@ -72,9 +72,7 @@ public byte[] Serialize(long offset = 0) { foreach (var vertex in LiquidIndices) { - bw.Write(vertex.X); - bw.Write(vertex.Y); - bw.Write(vertex.Z); + bw.WriteShortVector3(vertex); } return ms.ToArray(); } diff --git a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs index 0f1b882..66c8c08 100644 --- a/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs +++ b/Warcraft.NET/Files/ADT/Chunks/Legion/MLLV.cs @@ -47,7 +47,7 @@ public void LoadBinaryData(byte[] inData) LiquidVertices = new Vector3[vertexCount]; for (var i = 0; i < vertexCount; ++i) { - LiquidVertices[i] = br.ReadVector3(Structures.AxisConfiguration.Native); + LiquidVertices[i] = br.ReadVector3(); } } } @@ -72,9 +72,7 @@ public byte[] Serialize(long offset = 0) { foreach (var vertex in LiquidVertices) { - bw.Write(vertex.X); - bw.Write(vertex.Y); - bw.Write(vertex.Z); + bw.WriteVector3(vertex); } return ms.ToArray(); } diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs index d8f65be..a739cad 100644 --- a/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MBBBEntry.cs @@ -36,7 +36,7 @@ public MBBBEntry(byte[] data) using (var br = new BinaryReader(ms)) { MapObjectID = br.ReadUInt32(); - BoundingBox = new BoundingBox(br.ReadVector3(AxisConfiguration.Native), br.ReadVector3(AxisConfiguration.Native)); + BoundingBox = br.ReadBoundingBox(); } } @@ -59,8 +59,7 @@ public byte[] Serialize(long offset = 0) using (var bw = new BinaryWriter(ms)) { bw.Write(MapObjectID); - bw.WriteVector3(BoundingBox.Minimum); - bw.WriteVector3(BoundingBox.Maximum); + bw.WriteBoundingBox(BoundingBox); return ms.ToArray(); } } diff --git a/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs b/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs index 05a6ac1..371a0c7 100644 --- a/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs +++ b/Warcraft.NET/Files/ADT/Entries/Legion/MBNVEntry.cs @@ -1,6 +1,7 @@ using System.IO; using System.Numerics; using Warcraft.NET.Extensions; +using Warcraft.NET.Files.Structures; namespace Warcraft.NET.Files.ADT.Entries.Legion { @@ -27,7 +28,7 @@ public class MBNVEntry /// /// Color. /// - public uint[] Color { get; set; } + public RGBA[] Color { get; set; } /// /// Initializes a new instance of the class. @@ -48,10 +49,10 @@ public MBNVEntry(byte[] data) Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); Normal = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); TextureCoordinates = new Vector2(br.ReadSingle(), br.ReadSingle()); - Color = new uint[3]; + Color = new RGBA[3]; for (var i = 0; i < 3; i++) { - Color[i] = br.ReadUInt32(); + Color[i] = br.ReadRGBA(); } } } @@ -81,7 +82,7 @@ public byte[] Serialize(long offset = 0) for (var i = 0; i < 3; i++) { - bw.Write(Color[i]); + bw.WriteRGBA(Color[i]); } return ms.ToArray(); diff --git a/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs b/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs index 3d63fa9..4deeaec 100644 --- a/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs +++ b/Warcraft.NET/Files/ADT/Flags/MLLDFlags.cs @@ -11,16 +11,16 @@ public enum MLLDFlags : uint /// /// Has Tile Data /// - Flag_HasTileData = 0x1, + HasTileData = 0x1, /// /// Depth (first) chunk is compressed. /// - Flag_DepthChunkCompressed = 0x2, + DepthChunkCompressed = 0x2, /// /// Alpha (second) chunk is compressed. /// - Flag_AlphaChunkCompressed = 0x4, + AlphaChunkCompressed = 0x4, } } diff --git a/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs b/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs index 21cceac..a448059 100644 --- a/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs +++ b/Warcraft.NET/Files/ADT/TerrainLOD/Legion/TerrainLOD.cs @@ -12,37 +12,37 @@ namespace Warcraft.NET.Files.ADT.TerrainLOD.Legion public class TerrainLOD : TerrainLODBase { /// - /// + /// LOD header. /// [ChunkOrder(2)] public MLHD Header { get; set; } /// - /// + /// LOD heightmap. /// [ChunkOrder(3)] public MLVH Heightmap { get; set; } /// - /// + /// LOD levels. /// [ChunkOrder(4)] public MLLL Levels { get; set; } /// - /// + /// LOD quad-tree. /// [ChunkOrder(5)] public MLND QuadTree { get; set; } /// - /// + /// LOD Vertex Indices. /// [ChunkOrder(6)] public MLVI VertexIndices { get; set; } /// - /// + /// LOD Skirt Indices. /// [ChunkOrder(7)] public MLSI SkirtIndices { get; set; } @@ -85,17 +85,17 @@ public class TerrainLOD : TerrainLODBase public MLLD LiquidData { get; set; } /// - /// + /// Unknown name. Wiki says "MLLN introduces a new liquid". /// public SynchronizedList LiquidN { get; set; } = new SynchronizedList(new List(4096)); /// - /// + /// Liquid indices. /// public SynchronizedList LiquidIndices { get; set; } = new SynchronizedList(new List(4096)); /// - /// + /// Liquid veritices. /// public SynchronizedList LiquidVertices { get; set; } = new SynchronizedList(new List(4096)); @@ -111,6 +111,12 @@ public TerrainLOD() : base() /// /// The binary data. public TerrainLOD(byte[] inData) + { + LoadBinaryData(inData); + } + + /// + public void LoadBinaryData(byte[] inData) { using var ms = new MemoryStream(inData); using var br = new BinaryReader(ms);