diff --git a/Maple2.File.IO/Nif/PhysXMesh.cs b/Maple2.File.IO/Nif/PhysXMesh.cs index a5fd196..e0f2940 100644 --- a/Maple2.File.IO/Nif/PhysXMesh.cs +++ b/Maple2.File.IO/Nif/PhysXMesh.cs @@ -5,11 +5,11 @@ namespace Maple2.File.IO.Nif; public struct PhysXMeshFace { - public byte Vert0; - public byte Vert1; - public byte Vert2; + public uint Vert0; + public uint Vert1; + public uint Vert2; - public PhysXMeshFace(byte vert0 = 0, byte vert1 = 0, byte vert2 = 0) { + public PhysXMeshFace(uint vert0 = 0, uint vert1 = 0, uint vert2 = 0) { Vert0 = vert0; Vert1 = vert1; Vert2 = vert2; @@ -67,7 +67,7 @@ private NxsMeshType ParseConvexMesh(EndianReader reader) { byte[] unkSection1 = reader.ReadBytes(8); - // Sanity check to check a known piece of data for potential changes + // Sanity check to check a known piece of data for potential changes if (!unkSection1.SequenceEqual(unkDataSection1)) { throw new InvalidDataException("Unknown PhysX convex mesh data layout"); } @@ -76,7 +76,7 @@ private NxsMeshType ParseConvexMesh(EndianReader reader) { byte[] unkSection2 = reader.ReadBytes(4); - // Sanity check to check a known piece of data for potential changes + // Sanity check to check a known piece of data for potential changes if (!unkSection2.SequenceEqual(unkDataSection2)) { throw new InvalidDataException("Unknown PhysX convex mesh data layout"); } @@ -102,11 +102,27 @@ private NxsMeshType ParseConvexMesh(EndianReader reader) { uint unk10 = reader.ReadAdjustedUInt32(); for (int i = 0; i < faceCount; ++i) { - PhysXMeshFace face = new PhysXMeshFace( - reader.ReadByte(), - reader.ReadByte(), - reader.ReadByte() - ); + PhysXMeshFace face; + + if (vertexCount < 0x100) { + face = new PhysXMeshFace( + reader.ReadByte(), + reader.ReadByte(), + reader.ReadByte() + ); + } else if (vertexCount < 0x10000) { + face = new PhysXMeshFace( + reader.ReadUInt16(), + reader.ReadUInt16(), + reader.ReadUInt16() + ); + } else { + face = new PhysXMeshFace( + reader.ReadUInt32(), + reader.ReadUInt32(), + reader.ReadUInt32() + ); + } Faces.Add(face); @@ -141,11 +157,27 @@ private NxsMeshType ParseTriangleMesh(EndianReader reader) { } for (int i = 0; i < faceCount; ++i) { - PhysXMeshFace face = new PhysXMeshFace( - reader.ReadByte(), - reader.ReadByte(), - reader.ReadByte() - ); + PhysXMeshFace face; + + if (vertexCount < 0x100) { + face = new PhysXMeshFace( + reader.ReadByte(), + reader.ReadByte(), + reader.ReadByte() + ); + } else if (vertexCount < 0x10000) { + face = new PhysXMeshFace( + reader.ReadUInt16(), + reader.ReadUInt16(), + reader.ReadUInt16() + ); + } else { + face = new PhysXMeshFace( + reader.ReadUInt32(), + reader.ReadUInt32(), + reader.ReadUInt32() + ); + } Faces.Add(face); diff --git a/Maple2.File.IO/Nif/NifM2dArchive.cs b/Maple2.File.IO/Nif/PrefixedM2dReader.cs similarity index 100% rename from Maple2.File.IO/Nif/NifM2dArchive.cs rename to Maple2.File.IO/Nif/PrefixedM2dReader.cs diff --git a/Maple2.File.Parser/Enum/NxActorFlag.cs b/Maple2.File.Parser/Enum/NxActorFlag.cs deleted file mode 100644 index 12228ec..0000000 --- a/Maple2.File.Parser/Enum/NxActorFlag.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxActorFlag : uint { - None, - DisableCollision = 1 << 0, - DisableResponse = 1 << 1, - LockCenterOfMass = 1 << 2, - FluidDisableCollision = 1 << 3, - ContactModification = 1 << 4, - ForceConeFriction = 1 << 5, - UserActorPairFiltering = 1 << 6 -} diff --git a/Maple2.File.Parser/Enum/NxMeshShapeFlags.cs b/Maple2.File.Parser/Enum/NxMeshShapeFlags.cs deleted file mode 100644 index 51dfd53..0000000 --- a/Maple2.File.Parser/Enum/NxMeshShapeFlags.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxMeshShapeFlags : uint { - None = 0, - SmoothSphereCollisions = 1 << 0, - DoubleSided = 1 << 1 -} diff --git a/Maple2.File.Parser/Enum/NxPagingMode.cs b/Maple2.File.Parser/Enum/NxPagingMode.cs deleted file mode 100644 index 7a939e9..0000000 --- a/Maple2.File.Parser/Enum/NxPagingMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxPagingMode : uint { - Manual, - Fallback, - Auto -} diff --git a/Maple2.File.Parser/Enum/NxShapeFlag.cs b/Maple2.File.Parser/Enum/NxShapeFlag.cs deleted file mode 100644 index 0e98221..0000000 --- a/Maple2.File.Parser/Enum/NxShapeFlag.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxShapeFlag : uint { - None, - Visualization = 1 << 3, - DisableCollision = 1 << 4, - FeatureIndices = 1 << 5, - DisableRaycasting = 1 << 6, - PointContactForce = 1 << 7, - FluidDrain = 1 << 8, - FluidDisableCollision = 1 << 10, - FluidTwoWay = 1 << 11, - DisableResponse = 1 << 12, - DynamicDynamicCCD = 1 << 13, - DisableSceneQueries = 1 << 14, - ClothDrain = 1 << 15, - ClothDisableCollision = 1 << 16, - ClothTwoWay = 1 << 17, - SoftBodyDrain = 1 << 18, - SoftBodyDisableCollision = 1 << 19, - SoftBodyTwoWay = 1 << 20 -} - diff --git a/Maple2.File.Parser/Enum/NxShapeType.cs b/Maple2.File.Parser/Enum/NxShapeType.cs deleted file mode 100644 index 6c62e21..0000000 --- a/Maple2.File.Parser/Enum/NxShapeType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxShapeType : uint { - Plane, - Sphere, - Box, - Capsule, - Wheel, - Convex, - Mesh, - HeightField, - RawMesh, - Compound -} - diff --git a/Maple2.File.Parser/Enum/NxsMeshType.cs b/Maple2.File.Parser/Enum/NxsMeshType.cs deleted file mode 100644 index 94a7c02..0000000 --- a/Maple2.File.Parser/Enum/NxsMeshType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum NxsMeshType { - None, - Convex, - Triangle, - Cloth -} - diff --git a/Maple2.File.Parser/Enum/PhysXMeshFlags.cs b/Maple2.File.Parser/Enum/PhysXMeshFlags.cs deleted file mode 100644 index e087bbb..0000000 --- a/Maple2.File.Parser/Enum/PhysXMeshFlags.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Maple2.File.Parser.Enum; - -public enum PhysXMeshFlags : byte { - None = 0, - IsConvex = 0x1, - IsCloth = 0x2, - Hardware = 0x4, - CookedForWin32 = 0x8, - CookedForPS3 = 0x10, - CookedForXenon = 0x20 -} diff --git a/Maple2.File.Parser/Maple2.File.Parser.csproj b/Maple2.File.Parser/Maple2.File.Parser.csproj index 0ca034b..6f7971f 100644 --- a/Maple2.File.Parser/Maple2.File.Parser.csproj +++ b/Maple2.File.Parser/Maple2.File.Parser.csproj @@ -13,7 +13,7 @@ MapleStory2, File, Parser, m2d, xml true - 2.1.19 + 2.1.20 net8.0 README.md enable diff --git a/Maple2.File.Parser/Nif/Endian.cs b/Maple2.File.Parser/Nif/Endian.cs deleted file mode 100644 index b5bbf76..0000000 --- a/Maple2.File.Parser/Nif/Endian.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System.Buffers.Binary; -using System.Numerics; -using System.Text; - -namespace Maple2.File.Parser.Nif; -public class EndianReader { - public bool Swap { get; init; } - public byte[] Data { get; init; } - public int Index { get; private set; } - - public EndianReader(byte[] data, bool swap, int index = 0) { - Swap = swap; - Data = data; - Index = index; - } - - public bool ReadBool() { - bool value = BitConverter.ToBoolean(Data, Index); - - Index += 1; - - return value; - } - - public byte ReadByte() { - byte value = Data[Index]; - - Index += 1; - - return value; - } - - public ushort ReadUInt16() { - ushort value = BitConverter.ToUInt16(Data, Index); - - Index += 2; - - if (Swap) { - return BinaryPrimitives.ReverseEndianness(value); - } - - return value; - } - - public uint ReadUInt32() { - uint value = BitConverter.ToUInt32(Data, Index); - - Index += 4; - - if (Swap) { - return BinaryPrimitives.ReverseEndianness(value); - } - - return value; - } - - public int ReadInt32() { - int value = BitConverter.ToInt32(Data, Index); - - Index += 4; - - if (Swap) { - return BinaryPrimitives.ReverseEndianness(value); - } - - return value; - } - - public ulong ReadUInt64() { - ulong value = BitConverter.ToUInt64(Data, Index); - - Index += 8; - - if (Swap) { - return BinaryPrimitives.ReverseEndianness(value); - } - - return value; - } - - public float ReadFloat32() { - Span bytes = stackalloc byte[4] { Data[Index + 3], Data[Index + 2], Data[Index + 1], Data[Index] }; - - if (Swap) { - bytes.Reverse(); - } - - Index += 4; - - return BitConverter.ToSingle(bytes); - } - - public string ReadString(int length) { - string value = Encoding.UTF8.GetString(Data, Index, length); - - Index += length; - - return value; - } - - public string ReadStringLen32() { - int length = ReadInt32(); - - if (length == 0) { - return string.Empty; - } - - string value = Encoding.UTF8.GetString(Data, Index, length); - - Index += length; - - return value; - } - - // explicitly using 4x4 for matrix multiplication compatibility - public Matrix4x4 ReadMatrix4x3() { - Matrix4x4 matrix = new Matrix4x4(); - - for (int column = 0; column < 3; ++column) { - for (int row = 0; row < 3; ++row) { - matrix[row, column] = ReadFloat32(); - } - } - - // Translation - matrix.M41 = ReadFloat32(); - matrix.M42 = ReadFloat32(); - matrix.M43 = ReadFloat32(); - matrix.M44 = 1; - - return matrix; - } - - public Vector3 ReadVector3() { - float x = ReadFloat32(); - float y = ReadFloat32(); - float z = ReadFloat32(); - - return new Vector3(x, y, z); - } - - public void Advance(int distance) { - Index += distance; - } -} diff --git a/Maple2.File.Parser/Nif/NiPhysXActorDesc.cs b/Maple2.File.Parser/Nif/NiPhysXActorDesc.cs deleted file mode 100644 index 2c6f4dd..0000000 --- a/Maple2.File.Parser/Nif/NiPhysXActorDesc.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Maple2.File.Parser.Enum; -using System.Numerics; - -namespace Maple2.File.Parser.Nif; - -public class NiPhysXActorDesc : NifBlock { - public string ActorName; - public List Poses; - public NifBlock? BodyDesc; - public float Density = 1; - public NxActorFlag ActorFlags = NxActorFlag.None; - public ushort ActorGroup = 0; - public ushort DominanceGroup = 0; - public uint ContactReportFlags = 0; - public ushort ForceFieldMaterial = 0; - public List ShapeDescriptions; - public NiPhysXActorDesc? ActorParent; - public NifBlock? Source; - public NifBlock? Destination; - - public NiPhysXActorDesc(int blockIndex) : base("NiPhysXActorDesc", false, blockIndex) { } - - public override void Parse(NifDocument document) { - base.Parse(document); - - ActorName = document.ReadString(); - - int numPoses = document.Reader.ReadInt32(); - - Poses = new List(); - Poses.EnsureCapacity(numPoses); - - for (int i = 0; i < numPoses; ++i) { - Poses.Add(document.Reader.ReadMatrix4x3()); - } - - BodyDesc = document.ReadBlockRef(); - Density = document.Reader.ReadFloat32(); - ActorFlags = (NxActorFlag) document.Reader.ReadUInt32(); - ActorGroup = document.Reader.ReadUInt16(); - DominanceGroup = document.Reader.ReadUInt16(); - ContactReportFlags = document.Reader.ReadUInt32(); - ForceFieldMaterial = document.Reader.ReadUInt16(); - ShapeDescriptions = document.ReadBlockRefList(); - ActorParent = document.ReadBlockRef(); - Source = document.ReadBlockRef(); - Destination = document.ReadBlockRef(); - } -} - diff --git a/Maple2.File.Parser/Nif/NiPhysXMeshDesc.cs b/Maple2.File.Parser/Nif/NiPhysXMeshDesc.cs deleted file mode 100644 index fe1def6..0000000 --- a/Maple2.File.Parser/Nif/NiPhysXMeshDesc.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Maple2.File.Parser.Enum; - -namespace Maple2.File.Parser.Nif; - -public class NiPhysXMeshDesc : NifBlock { - public string MeshName; - public byte[] MeshData; - public NxMeshShapeFlags MeshFlags = NxMeshShapeFlags.None; - public NxPagingMode PagingMode = NxPagingMode.Manual; - public PhysXMeshFlags Flags = PhysXMeshFlags.None; - - public NiPhysXMeshDesc(int blockIndex) : base("NiPhysXMeshDesc", false, blockIndex) { } - - public override void Parse(NifDocument document) { - base.Parse(document); - - MeshName = document.ReadString(); - - int meshSize = document.Reader.ReadInt32(); - - MeshData = new byte[meshSize]; - - Buffer.BlockCopy(document.Reader.Data, document.Reader.Index, MeshData, 0, meshSize); - - document.Reader.Advance(meshSize); - - MeshFlags = (NxMeshShapeFlags) document.Reader.ReadInt32(); - PagingMode = (NxPagingMode) document.Reader.ReadInt32(); - Flags = (PhysXMeshFlags) document.Reader.ReadByte(); - } -} diff --git a/Maple2.File.Parser/Nif/NiPhysXProp.cs b/Maple2.File.Parser/Nif/NiPhysXProp.cs deleted file mode 100644 index 76f28d3..0000000 --- a/Maple2.File.Parser/Nif/NiPhysXProp.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Maple2.File.Parser.Nif; - -public class NiPhysXProp : NifBlock { - public List ExtraData; // NiExtraData - public NifBlock? Controller = null; // NiTimeController - public float PhysXToWorldScale = 1; - public List Sources; // NiPhysXSrc - public List Dests; // NiPhysXDest - public List ModifiedMeshes; // NiMesh - public bool KeepMeshes = false; - public NiPhysXPropDesc? Snapshot = null; - - public NiPhysXProp(int blockIndex) : base("NiPhysXProp", true, blockIndex) { } - - public override void Parse(NifDocument document) { - base.Parse(document); - - ExtraData = document.ReadBlockRefList(); - Controller = document.ReadBlockRef(); - PhysXToWorldScale = document.Reader.ReadFloat32(); - Sources = document.ReadBlockRefList(); - Dests = document.ReadBlockRefList(); - ModifiedMeshes = document.ReadBlockRefList(); - KeepMeshes = document.Reader.ReadBool(); - Snapshot = document.ReadBlockRef(); - - document.PhysXProps.Add(this); - } -} - diff --git a/Maple2.File.Parser/Nif/NiPhysXPropDesc.cs b/Maple2.File.Parser/Nif/NiPhysXPropDesc.cs deleted file mode 100644 index 48365b6..0000000 --- a/Maple2.File.Parser/Nif/NiPhysXPropDesc.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Maple2.File.Parser.Nif; - -public class NiPhysXPropDesc : NifBlock { - public class StateString { - public string String; - public uint Value; - - public StateString(string key, uint value) { - String = key; - Value = value; - } - } - - public class State { - public List Strings; - - public State() { - Strings = new List(); - } - } - - public List Actors; - public List Joints; - public List Clothes; - public Dictionary Materials; - public List StateNames; - public byte Flags; - - public NiPhysXPropDesc(int blockIndex) : base("NiPhysXPropDesc", false, blockIndex) { } - - public override void Parse(NifDocument document) { - base.Parse(document); - - Actors = document.ReadBlockRefList(); - Joints = document.ReadBlockRefList(); - Clothes = document.ReadBlockRefList(); - Materials = new Dictionary(); - StateNames = new List(); - - uint numMaterials = document.Reader.ReadUInt32(); - - for (uint i = 0; i < numMaterials; i++) { - ushort key = document.Reader.ReadUInt16(); - NifBlock material = document.ReadBlockRef(); - - Materials.Add(key, material); - } - - uint numStates = document.Reader.ReadUInt32(); - - StateNames.EnsureCapacity((int) numStates); - - for (uint i = 0; i < numStates; i++) { - State state = new State(); - - int numStrings = document.Reader.ReadInt32(); - - state.Strings.EnsureCapacity((int) numStrings); - - for (int j = 0; j < numStrings; j++) { - string key = document.ReadString(); - uint value = document.Reader.ReadUInt32(); - - state.Strings.Add(new StateString(key, value)); - } - - StateNames.Add(state); - } - - Flags = document.Reader.ReadByte(); - } -} diff --git a/Maple2.File.Parser/Nif/NiPhysXShapeDesc.cs b/Maple2.File.Parser/Nif/NiPhysXShapeDesc.cs deleted file mode 100644 index bb4bac7..0000000 --- a/Maple2.File.Parser/Nif/NiPhysXShapeDesc.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Maple2.File.Parser.Enum; -using System.Numerics; - -namespace Maple2.File.Parser.Nif; - -public class NiPhysXShapeDesc : NifBlock { - public NxShapeType ShapeType = NxShapeType.Plane; - public NxShapeFlag Flags = NxShapeFlag.Visualization | NxShapeFlag.ClothTwoWay | NxShapeFlag.SoftBodyTwoWay; - public Matrix4x4 LocalPose; - public ushort CollisionGroup; - public ushort MaterialIndex; - public float Density = 1; - public float Mass = 1; - public float SkinWidth = 0.01f; - public string ShapeName; - public uint NonInteractingCompartment; - public uint[] CollisionBits; - public NiPhysXMeshDesc? Mesh; - public Vector3 BoxHalfExtents; - - public NiPhysXShapeDesc(int blockIndex) : base("NiPhysXShapeDesc", false, blockIndex) { - CollisionBits = new uint[4]; - } - - public override void Parse(NifDocument document) { - base.Parse(document); - - ShapeType = (NxShapeType) document.Reader.ReadUInt32(); - Flags = (NxShapeFlag) document.Reader.ReadUInt32(); - LocalPose = document.Reader.ReadMatrix4x3(); - CollisionGroup = document.Reader.ReadUInt16(); - MaterialIndex = document.Reader.ReadUInt16(); - Density = document.Reader.ReadFloat32(); - Mass = document.Reader.ReadFloat32(); - SkinWidth = document.Reader.ReadFloat32(); - ShapeName = document.ReadString(); - NonInteractingCompartment = document.Reader.ReadUInt32(); - - for (int i = 0; i < 4; ++i) { - CollisionBits[i] = document.Reader.ReadUInt32(); - } - - switch (ShapeType) { - case NxShapeType.Box: - BoxHalfExtents = document.Reader.ReadVector3(); - break; - case NxShapeType.Mesh: - case NxShapeType.Convex: - Mesh = document.ReadBlockRef(); - break; - default: - throw new NotSupportedException($"Unsupported NiPhysXShapeDesc.ShapeType found: {ShapeType}"); - } - } -} - diff --git a/Maple2.File.Parser/Nif/NifBlock.cs b/Maple2.File.Parser/Nif/NifBlock.cs deleted file mode 100644 index 24027ae..0000000 --- a/Maple2.File.Parser/Nif/NifBlock.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Maple2.File.Parser.Nif; - -public class NifBlock { - public string BlockType { get; init; } - public bool HasName { get; init; } - public int BlockIndex { get; init; } - public string Name; - - public NifBlock(string blockType, bool hasName, int blockIndex) { - BlockType = blockType; - HasName = hasName; - BlockIndex = blockIndex; - Name = string.Empty; - } - - public virtual void Parse(NifDocument document) { - if (HasName) { - Name = document.ReadString(); - } - - document.Reading(this); - } -} diff --git a/Maple2.File.Parser/Nif/NifDocument.cs b/Maple2.File.Parser/Nif/NifDocument.cs deleted file mode 100644 index efeffdb..0000000 --- a/Maple2.File.Parser/Nif/NifDocument.cs +++ /dev/null @@ -1,263 +0,0 @@ -using System.Text; - -namespace Maple2.File.Parser.Nif; - -public class NifDocument { - private readonly byte[] fileData; - private NifDocumentHeader header; - public EndianReader Reader { get; private set; } - public string RelPath { get; init; } - private NifBlock?[] blocks; - public NifBlock? ReadingBlock { get; private set; } - - public List PhysXProps { get; init; } - public string VersionString { get => header.HeaderString; } - - public NifDocument(string relpath, byte[] fileData) { - PhysXProps = new List(); - this.fileData = fileData; - Reader = new EndianReader(Array.Empty(), false); - blocks = Array.Empty(); - header = new NifDocumentHeader(); - RelPath = relpath; - } - - private int ReadHeaderString() { - int index = 0; - int headerStringLength = 0; - - while (headerStringLength < fileData.Length && fileData[headerStringLength] != 0x0A) { - headerStringLength++; - } - - header.HeaderString = Encoding.UTF8.GetString(fileData, 0, headerStringLength); - - index += headerStringLength + 1; - - int versionStart = headerStringLength; - - while (versionStart - 1 > 0 && (fileData[versionStart - 1] == '.' || (fileData[versionStart - 1] >= '0' && fileData[versionStart - 1] <= '9'))) - --versionStart; - - for (int i = 0; i < 4; ++i) { - int versionEnd = versionStart; - - while (versionEnd < headerStringLength && fileData[versionEnd] != '.') - ++versionEnd; - - string versionText = Encoding.UTF8.GetString(fileData, versionStart, versionEnd - versionStart); - - header.Version[i] = ushort.Parse(versionText); - - versionStart = versionEnd + 1; - } - - return index; - } - - public NifBlock? GetBlock(int index) { - if (index == -1) { - return null; - } - - if (blocks[index] is not null) { - return blocks[index]; - } - - NifBlock block; - string blockType = header.BlockTypes[header.BlockTypeIndices[index]]; - - switch (blockType) { - case "NiPhysXProp": - block = new NiPhysXProp(index); - - break; - case "NiPhysXPropDesc": - block = new NiPhysXPropDesc(index); - - break; - case "NiPhysXActorDesc": - block = new NiPhysXActorDesc(index); - - break; - case "NiPhysXShapeDesc": - block = new NiPhysXShapeDesc(index); - - break; - case "NiPhysXMeshDesc": - block = new NiPhysXMeshDesc(index); - - break; - default: - block = new NifBlock(blockType, false, index); - - break; - } - - blocks[index] = block; - - return block; - } - - public T? GetBlock(int index) { - if (index == -1) { - return default; - } - - NifBlock? block = GetBlock(index); - - if (block is T nifBlock) { - return nifBlock; - } - - throw new InvalidCastException($"Invalid block handle <{typeof(T).Name}> referenced block {index}"); - } - - public T? ReadBlockRef() { - int index = Reader.ReadInt32(); - - if (index != -1) { - return GetBlock(index); - } - - return default; - } - - public List ReadBlockRefList() { - List blocks = new List(); - - int count = Reader.ReadInt32(); - - blocks.EnsureCapacity(count); - - for (int i = 0; i < count; ++i) { - T? block = ReadBlockRef(); - - if (block is null) { - throw new InvalidCastException($"Null/invalid block handle in block list <{typeof(T).Name}> of size {count}"); - } - - blocks.Add(block); - } - - return blocks; - } - - public string ReadString() { - uint stringIndex = Reader.ReadUInt32(); - - return header.Strings[stringIndex]; - } - - public void Reading(NifBlock block) { - ReadingBlock = block; - } - - public bool Parse() { - int index = ReadHeaderString(); - - if (header.Version[0] < 30) { - Console.WriteLine(RelPath); - Console.WriteLine($"NIF version number too low: {header.HeaderString}. Parser is built for v30+"); // is it possible to do warnings? - - return false; - } - - index += 4; - - bool isLittleEndian = fileData[index] != 0; - - Reader = new EndianReader(fileData, isLittleEndian != BitConverter.IsLittleEndian, index + 1); - - uint userVersion = Reader.ReadUInt32(); - int numBlocks = Reader.ReadInt32(); - int metaBlockSize = Reader.ReadInt32(); - - Reader.Advance(metaBlockSize); - - ushort numBlockTypes = Reader.ReadUInt16(); - - if (numBlockTypes == 0) { - return true; - } - - header.BlockTypes = new string[numBlockTypes]; - header.BlockTypeIndices = new ushort[numBlocks]; - header.BlockSizes = new int[numBlocks]; - blocks = new NifBlock?[numBlocks]; - - for (uint i = 0; i < numBlockTypes; i++) { - header.BlockTypes[i] = Reader.ReadStringLen32(); - } - - for (uint i = 0; i < numBlocks; i++) { - header.BlockTypeIndices[i] = (ushort) (0x7FFFU & Reader.ReadUInt16()); - } - - for (uint i = 0; i < numBlocks; i++) { - header.BlockSizes[i] = Reader.ReadInt32(); - } - - uint numStrings = Reader.ReadUInt32(); - uint maxStringLength = Reader.ReadUInt32(); - - header.Strings = new string[numStrings]; - - for (uint i = 0; i < numStrings; i++) { - header.Strings[i] = Reader.ReadStringLen32(); - } - - uint numGroups = Reader.ReadUInt32(); - - if (numGroups > 0) { - throw new NotSupportedException("NIF groups aren't currently supported"); - } - - for (int i = 0; i < numBlocks; ++i) { - string blockType = header.BlockTypes[header.BlockTypeIndices[i]]; - int blockSize = header.BlockSizes[i]; - - int blockStart = Reader.Index; - - - NifBlock? block = GetBlock(i); - - block?.Parse(this); - - int readBytes = Reader.Index - blockStart; - - if (readBytes != 0 && readBytes != blockSize) { - throw new TypeLoadException($"Failed to read in the proper block size for type {blockType} index {i}; read {readBytes}, block size: {blockSize}"); - } - - ReadingBlock = null; - - if (readBytes == 0) { - Reader.Advance(blockSize); - } - } - - return true; - } - - void ParseNiPhysXProp(uint blockIndex) { - - } - - void ParseNiPhysXPropDesc(uint blockIndex) { - - } - - void ParseNiPhysXActorDesc(uint blockIndex) { - - } - - void ParseNiPhysXShapeDesc(uint blockIndex) { - - } - - void ParseNiPhysXMeshDesc(uint blockIndex) { - - } -} - diff --git a/Maple2.File.Parser/Nif/NifDocumentHeader.cs b/Maple2.File.Parser/Nif/NifDocumentHeader.cs deleted file mode 100644 index 093510f..0000000 --- a/Maple2.File.Parser/Nif/NifDocumentHeader.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Maple2.File.Parser.Nif; - -public struct NifDocumentHeader { - public string HeaderString; - public ushort[] Version; - public string[] BlockTypes; - public ushort[] BlockTypeIndices; - public int[] BlockSizes; - public string[] Strings; - - public NifDocumentHeader() { - HeaderString = string.Empty; - Version = new ushort[4]; - BlockTypes = Array.Empty(); - BlockTypeIndices = Array.Empty(); - BlockSizes = Array.Empty(); - Strings = Array.Empty(); - } -} diff --git a/Maple2.File.Parser/Nif/NifM2dArchive.cs b/Maple2.File.Parser/Nif/NifM2dArchive.cs deleted file mode 100644 index 11d23b0..0000000 --- a/Maple2.File.Parser/Nif/NifM2dArchive.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Maple2.File.IO; - -namespace Maple2.File.Parser.Nif; - -public class NifM2dArchive { - public string PathPrefix { get; init; } - public M2dReader M2dReader { get; init; } - - public NifM2dArchive(string pathPrefix, M2dReader m2dReader) { - PathPrefix = pathPrefix; - M2dReader = m2dReader; - } -} diff --git a/Maple2.File.Parser/Nif/PhysXMesh.cs b/Maple2.File.Parser/Nif/PhysXMesh.cs deleted file mode 100644 index 94b7466..0000000 --- a/Maple2.File.Parser/Nif/PhysXMesh.cs +++ /dev/null @@ -1,204 +0,0 @@ -using Maple2.File.Parser.Enum; -using System.Numerics; -using System.Text; - -namespace Maple2.File.Parser.Nif; - -public struct PhysXMeshFace { - public uint Vert0; - public uint Vert1; - public uint Vert2; - - public PhysXMeshFace(uint vert0 = 0, uint vert1 = 0, uint vert2 = 0) { - Vert0 = vert0; - Vert1 = vert1; - Vert2 = vert2; - } -} - -public class PhysXMesh { - public NxsMeshType Type { get; init; } - public List Vertices { get; init; } - public List Faces { get; init; } - - public PhysXMesh(byte[] data) { - Vertices = new List(); - Faces = new List(); - - Type = ParseNxsMesh(data); - } - - private NxsMeshType ParseNxsMesh(byte[] data) { - if (data.Length < 8) { - throw new InvalidDataException("PhysX mesh data too small to fit header"); - } - - string headerPiece1 = Encoding.UTF8.GetString(data, 0, 3); - string headerPiece2 = Encoding.UTF8.GetString(data, 4, 4); - - if (headerPiece1 != "NXS") { - throw new InvalidDataException($"Invalid header found in PhysX mesh data: {Encoding.UTF8.GetString(data, 0, 8)}"); - } - - switch (headerPiece2) { - case "CVXM": - return ParseConvexMesh(data); - case "MESH": - return ParseTriangleMesh(data); - case "CLTH": - throw new NotSupportedException($"Cloth mesh not supported! Found unsupported PhysX cloth mesh in mesh data"); - default: - throw new InvalidDataException($"Unknown PhysX nxs mesh type {headerPiece2} found in mesh data"); - } - } - - private NxsMeshType ParseConvexMesh(byte[] data) { - EndianReader reader = new EndianReader(data, !BitConverter.IsLittleEndian, 8); - - uint unk1 = reader.ReadUInt32(); - uint unk2 = reader.ReadUInt32(); - - bool unkDataSectionMatches = false; - - unkDataSectionMatches |= data[reader.Index + 0] == 'I'; - unkDataSectionMatches |= data[reader.Index + 0] == 'C'; - unkDataSectionMatches |= data[reader.Index + 0] == 'E'; - unkDataSectionMatches |= data[reader.Index + 0] == 1; - unkDataSectionMatches |= data[reader.Index + 0] == 'C'; - unkDataSectionMatches |= data[reader.Index + 0] == 'L'; - unkDataSectionMatches |= data[reader.Index + 0] == 'H'; - unkDataSectionMatches |= data[reader.Index + 0] == 'L'; - - if (!unkDataSectionMatches) { - throw new InvalidDataException("Unknown PhysX convex mesh data layout"); - } - - reader.Advance(8); - - uint unk3 = reader.ReadUInt32(); - - unkDataSectionMatches = false; - - unkDataSectionMatches |= data[reader.Index + 0] == 'I'; - unkDataSectionMatches |= data[reader.Index + 0] == 'C'; - unkDataSectionMatches |= data[reader.Index + 0] == 'E'; - unkDataSectionMatches |= data[reader.Index + 0] == 1; - - if (!unkDataSectionMatches) { - throw new InvalidDataException("Unknown PhysX convex mesh data layout"); - } - - reader.Advance(4); - - uint unk4 = reader.ReadUInt32(); - uint unk5 = reader.ReadUInt32(); - - int vertexCount = reader.ReadInt32(); - int faceCount = reader.ReadInt32(); - - uint unk6 = reader.ReadUInt32(); - uint unk7 = reader.ReadUInt32(); - uint unk8 = reader.ReadUInt32(); - uint unk9 = reader.ReadUInt32(); - - Vertices.EnsureCapacity(vertexCount); - Faces.EnsureCapacity(faceCount); - - for (int i = 0; i < vertexCount; ++i) { - Vertices.Add(reader.ReadVector3()); - } - - uint unk10 = reader.ReadUInt32(); - - for (int i = 0; i < faceCount; ++i) { - PhysXMeshFace face; - - if (vertexCount < 0x100) { - face = new PhysXMeshFace( - reader.ReadByte(), - reader.ReadByte(), - reader.ReadByte() - ); - } else if (vertexCount < 0x10000) { - face = new PhysXMeshFace( - reader.ReadUInt16(), - reader.ReadUInt16(), - reader.ReadUInt16() - ); - } else { - face = new PhysXMeshFace( - reader.ReadUInt32(), - reader.ReadUInt32(), - reader.ReadUInt32() - ); - } - - Faces.Add(face); - - if (face.Vert0 > vertexCount || face.Vert1 > vertexCount || face.Vert2 > vertexCount) { - throw new IndexOutOfRangeException($"PhysX mesh data may be out of alignment for convex mesh format. Face index found out of bounds [{face.Vert0}, {face.Vert1}, {face.Vert2} with {vertexCount} vertices"); - } - } - - // There is more data, but none that is mesh relevant as far as I can tell - - return NxsMeshType.Convex; - } - - private NxsMeshType ParseTriangleMesh(byte[] data) { - EndianReader reader = new EndianReader(data, !BitConverter.IsLittleEndian, 8); - - uint unk1 = reader.ReadUInt32(); - uint unk2 = reader.ReadUInt32(); - float unk3 = reader.ReadFloat32(); - ulong unk4 = reader.ReadUInt64(); - - if (unk4 != 0xFF || unk1 != 1) { - throw new InvalidDataException("Unknown PhysX triangle mesh data format"); - } - - int vertexCount = reader.ReadInt32(); - int faceCount = reader.ReadInt32(); - - Vertices.EnsureCapacity(vertexCount); - Faces.EnsureCapacity(faceCount); - - for (int i = 0; i < vertexCount; ++i) { - Vertices.Add(reader.ReadVector3()); - } - - for (int i = 0; i < faceCount; ++i) { - PhysXMeshFace face; - - if (vertexCount < 0x100) { - face = new PhysXMeshFace( - reader.ReadByte(), - reader.ReadByte(), - reader.ReadByte() - ); - } else if (vertexCount < 0x10000) { - face = new PhysXMeshFace( - reader.ReadUInt16(), - reader.ReadUInt16(), - reader.ReadUInt16() - ); - } else { - face = new PhysXMeshFace( - reader.ReadUInt32(), - reader.ReadUInt32(), - reader.ReadUInt32() - ); - } - - Faces.Add(face); - - if (face.Vert0 > vertexCount || face.Vert1 > vertexCount || face.Vert2 > vertexCount) { - throw new IndexOutOfRangeException($"PhysX mesh data may be out of alignment for triangle mesh format. Face index found out of bounds [{face.Vert0}, {face.Vert1}, {face.Vert2} with {vertexCount} vertices"); - } - } - - // There is more data, but none that is mesh relevant as far as I can tell - - return NxsMeshType.Triangle; - } -}