示例#1
0
        // Methods
        public override void Load(Stream fileStream)
        {
            // BINA Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            string sig = reader.ReadSignature(4);

            if (sig != Signature)
            {
                throw new InvalidSignatureException(Signature, sig);
            }
            var unknown1 = reader.ReadUInt32(); //Might be part of the Header according to Skyth's spec?

            if (unknown1 != 1)
            {
                Console.WriteLine($"Unknown1 does not equal 1 in this file! It's actually set to {unknown1}");
            }
            var shapeCount = reader.ReadInt64();
            var unknown2   = reader.ReadUInt64();

            if (unknown2 != 24)
            {
                Console.WriteLine($"Unknown1 does not equal 24 in this file! It's actually set to {unknown1}");
            }
            Console.WriteLine(unknown2);

            for (int i = 0; i < shapeCount; i++)
            {
                SvShape shape           = new SvShape();
                var     shapeNameOffset = reader.ReadInt64();
                long    pos             = reader.BaseStream.Position;
                reader.JumpTo(shapeNameOffset, false);
                shape.Name = reader.ReadNullTerminatedString();
                reader.JumpTo(pos, true);

                shape.Unknown1            = reader.ReadUInt32();
                shape.Size                = reader.ReadVector3();
                shape.Position            = reader.ReadVector3();
                shape.Rotation            = reader.ReadQuaternion();
                shape.BoundingBox.Minimum = reader.ReadVector3();
                shape.BoundingBox.Maximum = reader.ReadVector3();
                shape.Unknown2            = reader.ReadUInt32();

                var sectorCount      = reader.ReadInt64();
                var sectorListOffset = reader.ReadInt64();
                pos = reader.BaseStream.Position;
                reader.JumpTo(sectorListOffset, false);
                for (int s = 0; s < sectorCount; s++)
                {
                    SvSector sector = new SvSector();
                    sector.SectorIndex = reader.Read();
                    sector.Visible     = reader.ReadBoolean();
                    shape.Sectors.Add(sector);
                }
                reader.JumpTo(pos, true);
                SvShapes.Add(shape);
            }
        }
示例#2
0
        public override void Load(Stream fileStream)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            VertexCountOffsetOffset = reader.ReadUInt32(); //Refered to in LibS06 as `geometry_address`
            PostFaceOffset          = reader.ReadUInt32(); //Refered to in LibS06 as `mopp_code_address`
            VertexCountOffset       = reader.ReadUInt32(); //Refered to in LibS06 as `vertex_section_address`
            FaceCountOffset         = reader.ReadUInt32(); //Refered to in LibS06 as `face_section_address`
            VertexCount             = reader.ReadUInt32();

            //Vertexes
            for (int i = 0; i < VertexCount; i++)
            {
                Vertices.Add(reader.ReadVector3());
            }

            //Faces
            FaceCount = reader.ReadUInt32();
            for (int i = 0; i < FaceCount; i++)
            {
                S06CollisionFace face = new S06CollisionFace();
                face.Vertex1 = reader.ReadUInt16();
                face.Vertex2 = reader.ReadUInt16();
                face.Vertex3 = reader.ReadUInt16();
                reader.JumpAhead(2);
                face.Flags = reader.ReadUInt32();
                Faces.Add(face);
            }
        }
示例#3
0
        // Methods
        public override void Load(Stream fileStream)
        {
            var reader = new BINAReader(fileStream);

            Header      = reader.ReadHeader();
            IsBigEndian = reader.IsBigEndian;

            System.Console.WriteLine(reader.BaseStream.Position);
            RangeIn       = reader.ReadSingle(); // Unused
            RangeDistance = reader.ReadSingle(); // Unused

            ModelName = reader.GetString();
            reader.JumpAhead(12);

            SkeletonName = reader.GetString();
            reader.JumpAhead(12);

            BoundingShape = (BoundingShapes)reader.ReadUInt32();

            BoundingSize = reader.ReadVector3();

            MeshName = reader.GetString();
            reader.JumpAhead(20);

            ShapeOffset = reader.ReadVector3();
            reader.JumpAhead(4);
            ShapeSizeOffset = reader.ReadSingle();

            RigidBodyType     = (RigidBodyTypes)reader.ReadByte();
            RigidBodyMaterial = (RigidBodyMaterials)reader.ReadByte();
            reader.JumpAhead(2);

            _PhysicsParam = new PhysicsParam(reader);

            ContactDamageType = (ContactDamageTypes)reader.ReadByte();
            RideOnDamage      = reader.ReadBoolean();
            AerialBounce      = reader.ReadBoolean();

            reader.JumpAhead(9);

            // ReactionData
            for (uint i = 0; i < ReactionDataCount; i++)
            {
                _ReactionData[i] = new ReactionData(reader);
            }
        }
示例#4
0
                // Constructors
                public ProgramMotionData(BINAReader reader)
                {
                    MotionType = (MotionTypes)reader.ReadUInt32();
                    reader.JumpAhead(12);

                    Axis = reader.ReadVector3();
                    reader.JumpAhead(4);

                    Power      = reader.ReadSingle();
                    SpeedScale = reader.ReadSingle();
                    Time       = reader.ReadSingle();
                    reader.JumpAhead(4);
                }
示例#5
0
        public override void Load(Stream fileStream)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            var rfzoneCount   = reader.ReadUInt32();
            var rfzoneOffset  = reader.ReadUInt32(); //Seemingly always 16? (0x10)
            var entriesCount  = reader.ReadUInt32(); //Seemingly always the same as rfzoneCount?
            var entriesOffset = reader.ReadUInt32();

            for (int i = 0; i < rfzoneCount; i++)
            {
                S06RFZone rfZone = new S06RFZone();
                rfZone.Unknown1 = reader.ReadSingle();
                rfZone.Unknown2 = reader.ReadSingle();
                rfZone.Unknown3 = reader.ReadSingle();
                rfZone.Unknown4 = reader.ReadSingle();
                Zones.Add(rfZone);
            }

            for (int i = 0; i < entriesCount; i++)
            {
                S06RFEntry entry = new S06RFEntry();
                entry.VertexCount = reader.ReadUInt32();
                var vertexTableOffset = reader.ReadUInt32();
                var zoneIndex         = reader.ReadUInt32();

                long pos = reader.BaseStream.Position;
                reader.JumpTo(vertexTableOffset, false);

                for (int v = 0; v < entry.VertexCount; v++)
                {
                    entry.Verticies.Add(reader.ReadVector3());
                }

                reader.JumpTo(pos, true);
                Entries.Add(entry);
            }
        }
示例#6
0
        public const uint Signature   = 0x4658434F; // FXCO in ASCII

        // Methods
        public override void Load(Stream fileStream)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            uint sig = reader.ReadUInt32();

            if (sig != Signature)
            {
                throw new InvalidSignatureException("FXCO",
                                                    Encoding.ASCII.GetString(BitConverter.GetBytes(sig)));
            }

            uint  unknown1        = reader.ReadUInt32(); // Version number?
            ulong instanceCount   = reader.ReadUInt64();
            ulong instancesOffset = reader.ReadUInt64();

            ulong shapesCount  = reader.ReadUInt64();
            ulong shapesOffset = reader.ReadUInt64();

            ulong unknownCount  = reader.ReadUInt64();
            ulong unknownOffset = reader.ReadUInt64();

            // Instances
            reader.JumpTo((long)instancesOffset, false);
            for (uint i = 0; i < instanceCount; ++i)
            {
                reader.FixPadding(8);
                ulong nameOffset   = reader.ReadUInt64();
                byte  unknownFlag1 = reader.ReadByte();
                byte  unknownFlag2 = reader.ReadByte();
                byte  unknownFlag3 = reader.ReadByte();
                byte  unknownFlag4 = reader.ReadByte();

                var   vect1        = reader.ReadVector3(); // Position or size?
                ulong instPadding1 = reader.ReadUInt64();
                uint  instPadding2 = reader.ReadUInt32();
                uint  instUnknown1 = reader.ReadUInt32();

                ulong instPadding3 = reader.ReadUInt64();
                ulong instPadding4 = reader.ReadUInt64();
                ulong instPadding5 = reader.ReadUInt64();
                ulong instPadding6 = reader.ReadUInt64();

                ulong unknownString1 = reader.ReadUInt64();  // Always "none"?
                var   vect2          = reader.ReadVector3(); // Position or size?
                uint  instUnknown2   = reader.ReadUInt32();  // Always 0x00000080?
                uint  instPadding7   = reader.ReadUInt32();
                uint  instUnknown3   = reader.ReadUInt32();  // Always 0x00000080?

                float instUnknown4 = reader.ReadSingle();    // Always 1?
            }

            // Unknown
            reader.JumpTo((long)unknownOffset, false);
            for (uint i = 0; i < unknownCount; ++i)
            {
                ulong uk1 = reader.ReadUInt64(); // Maybe 8 indices?
            }

            // Shapes
            reader.JumpTo((long)shapesOffset, false);
            for (uint i = 0; i < shapesCount; ++i)
            {
                uint shapeUnknown1 = reader.ReadUInt32();
                uint shapeUnknown2 = reader.ReadUInt32();
                var  shapeUnknown3 = reader.ReadVector3();
                var  shapeUnknown4 = reader.ReadVector3();
            }
        }
示例#7
0
        // Methods
        public override void Load(Stream fileStream,
                                  Dictionary <string, SetObjectType> objectTemplates)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            reader.JumpAhead(0x2C); // Skip "test" string
            uint objectLength = reader.ReadUInt32();
            uint objectOffset = reader.ReadUInt32();
            uint groupLength  = reader.ReadUInt32();
            uint groupOffset  = reader.ReadUInt32();

            Console.WriteLine($"Object Count: {objectLength}");
            Console.WriteLine($"Object Table Offset Location: {objectOffset}");
            Console.WriteLine($"Group Count: {groupLength}");
            Console.WriteLine($"Group Table Offset Location: {groupOffset}");

            //Groups
            reader.JumpTo(groupOffset, false);
            for (uint i = 0; i < groupLength; ++i)
            {
                //What we know so far:
                //First 4 bytes is a name for the group (usually GroupHelperXX?)
                //Second 4 bytes are the type? (according to LibS06), might be a second name (stuff like next_set/GroupHelperXX)?
                //Third 4 bytes is the amount of objects in this group.
                //Last 4 bytes is a list of the object IDs in this group.

                uint nameOffset        = reader.ReadUInt32(); //Name
                uint typeOffset        = reader.ReadUInt32(); //Type?
                uint groupObjectCount  = reader.ReadUInt32(); //Count
                uint groupObjectOffset = reader.ReadUInt32(); //Address of Objects

                string groupName = string.Empty;
                string groupType = string.Empty;

                long pos = reader.BaseStream.Position;

                reader.JumpTo(nameOffset, false);
                groupName = reader.ReadNullTerminatedString();
                groupNames.Add(groupName);

                reader.JumpTo(typeOffset, false);
                groupType = reader.ReadNullTerminatedString();
                groupTypes.Add(groupType);

                reader.JumpTo(groupObjectOffset, false);
                for (int c = 0; c < groupObjectCount; c++)
                {
                    reader.JumpAhead(4);
                    uint objID = reader.ReadUInt32();
                    objGroupData.Add($"{groupName}|{groupType}|{objID}");
                    groupIDs.Add(objID);
                }

                reader.JumpTo(pos, true);
            }

            // Data
            reader.JumpTo(objectOffset, false);
            for (uint i = 0; i < objectLength; ++i)
            {
                Objects.Add(ReadObject(i));
            }

            // TODO: Read Footer

            // Sub-Methods
            SetObject ReadObject(uint id)
            {
                // Object Entry
                var  obj        = new SetObject();
                uint nameOffset = reader.ReadUInt32();
                uint typeOffset = reader.ReadUInt32();

                reader.JumpAhead(16);

                obj.Transform.Position = reader.ReadVector3();
                reader.JumpAhead(4);
                obj.Transform.Rotation = new Quaternion(reader.ReadVector4());

                uint paramCount  = reader.ReadUInt32();
                uint paramOffset = reader.ReadUInt32();

                // Object Parameters
                long pos = reader.BaseStream.Position;

                for (uint i = 0; i < paramCount; ++i)
                {
                    reader.JumpTo(paramOffset + i * 0x14, false);
                    obj.Parameters.Add(ReadParam());
                }

                // Object Name
                reader.JumpTo(nameOffset, false);
                obj.CustomData.Add("Name", new SetObjectParam(
                                       typeof(string), reader.ReadNullTerminatedString()));

                // Object Type
                reader.JumpTo(typeOffset, false);
                obj.ObjectType = reader.ReadNullTerminatedString();
                obj.ObjectID   = id;

                //Object Group
                if (!groupIDs.Contains(id))
                {
                    obj.CustomData.Add("GroupName", new SetObjectParam(
                                           typeof(string), ""));
                    obj.CustomData.Add("GroupType", new SetObjectParam(
                                           typeof(string), ""));
                }
                else
                {
                    string[] groupData = objGroupData[groupIDs.IndexOf(id)].Split('|');
                    obj.CustomData.Add("GroupName", new SetObjectParam(
                                           typeof(string), groupData[0]));
                    obj.CustomData.Add("GroupType", new SetObjectParam(
                                           typeof(string), groupData[1]));
                }

                reader.JumpTo(pos, true);
                return(obj);
            }

            SetObjectParam ReadParam()
            {
                var  param = new SetObjectParam();
                uint type  = reader.ReadUInt32();

                switch (type)
                {
                case 0:
                    param.DataType = typeof(bool);
                    param.Data     = (reader.ReadUInt32() == 1);
                    break;

                case 1:
                    param.DataType = typeof(int);
                    param.Data     = reader.ReadInt32();
                    break;

                case 2:
                    param.DataType = typeof(float);
                    param.Data     = reader.ReadSingle();
                    break;

                case 3:
                    uint offset = reader.ReadUInt32();
                    uint amount = reader.ReadUInt32();

                    if (amount != 1)
                    {
                        Console.WriteLine($"WARNING: Amount != 1. ({amount})");
                    }

                    long pos = reader.BaseStream.Position;
                    reader.JumpTo(offset, false);

                    param.DataType = typeof(string);
                    param.Data     = reader.ReadNullTerminatedString();
                    reader.JumpTo(pos, true);
                    break;

                case 4:
                    param.DataType = typeof(Vector3);
                    param.Data     = reader.ReadVector3();
                    break;

                case 6:
                    param.DataType = typeof(uint);
                    param.Data     = reader.ReadUInt32();
                    break;

                default:
                    Console.WriteLine($"WARNING: Unknown object param type {type}!");
                    return(null);
                }

                return(param);
            }
        }
示例#8
0
        // Methods
        public override void Load(Stream fileStream,
                                  Dictionary <string, SetObjectType> objectTemplates)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            reader.JumpAhead(0x2C); // Skip "test" string
            uint objectLength = reader.ReadUInt32();
            uint objectOffset = reader.ReadUInt32();
            uint groupLength  = reader.ReadUInt32();
            uint groupOffset  = reader.ReadUInt32();

            // Data
            reader.JumpTo(objectOffset, false);
            for (uint i = 0; i < objectLength; ++i)
            {
                Objects.Add(ReadObject());
            }

            // TODO: Read Groups
            // TODO: Read Footer

            // Sub-Methods
            SetObject ReadObject()
            {
                // Object Entry
                var  obj        = new SetObject();
                uint nameOffset = reader.ReadUInt32();
                uint typeOffset = reader.ReadUInt32();

                reader.JumpAhead(16);

                obj.Transform.Position = reader.ReadVector3();
                reader.JumpAhead(4);
                obj.Transform.Rotation = new Quaternion(reader.ReadVector4());

                uint paramCount  = reader.ReadUInt32();
                uint paramOffset = reader.ReadUInt32();

                // Object Parameters
                long pos = reader.BaseStream.Position;

                for (uint i = 0; i < paramCount; ++i)
                {
                    reader.JumpTo(paramOffset + i * 0x14, false);
                    obj.Parameters.Add(ReadParam());
                }

                // TODO: Read Object Name

                // Object Type
                reader.JumpTo(typeOffset, false);
                obj.ObjectType = reader.ReadNullTerminatedString();

                reader.JumpTo(pos, true);
                return(obj);
            }

            SetObjectParam ReadParam()
            {
                var  param = new SetObjectParam();
                uint type  = reader.ReadUInt32();

                switch (type)
                {
                case 0:
                    param.DataType = typeof(bool);
                    param.Data     = (reader.ReadUInt32() == 1);
                    break;

                case 1:
                    param.DataType = typeof(int);
                    param.Data     = reader.ReadInt32();
                    break;

                case 2:
                    param.DataType = typeof(float);
                    param.Data     = reader.ReadSingle();
                    break;

                case 3:
                    uint offset = reader.ReadUInt32();
                    uint amount = reader.ReadUInt32();

                    if (amount != 1)
                    {
                        Console.WriteLine($"WARNING: Amount != 1. ({amount})");
                    }

                    long pos = reader.BaseStream.Position;
                    reader.JumpTo(offset, false);

                    param.DataType = typeof(string);
                    param.Data     = reader.ReadNullTerminatedString();
                    reader.JumpTo(pos, true);
                    break;

                case 4:
                    param.DataType = typeof(Vector3);
                    param.Data     = reader.ReadVector3();
                    break;

                case 6:
                    param.DataType = typeof(uint);
                    param.Data     = reader.ReadUInt32();
                    break;

                default:
                    Console.WriteLine($"WARNING: Unknown object param type {type}!");
                    return(null);
                }

                return(param);
            }
        }
示例#9
0
        // Methods
        public override void Load(Stream fileStream,
                                  Dictionary <string, SetObjectType> objectTemplates)
        {
            // Header
            var reader = new BINAReader(fileStream);

            Header = reader.ReadHeader();

            //Set Name (hardcoded to ASSUME it's four characters long)
            long namePosition = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters

            reader.JumpAhead(0xC);
            Name = reader.ReadNullTerminatedString();
            reader.JumpTo(namePosition, true);
            reader.JumpAhead(0x2C);

            uint objectCount       = reader.ReadUInt32();
            uint objectTableOffset = reader.ReadUInt32();
            uint groupCount        = reader.ReadUInt32();
            uint groupTableOffset  = reader.ReadUInt32();

            //Objects
            reader.JumpTo(objectTableOffset, false);
            for (uint i = 0; i < objectCount; i++)
            {
                var obj = new SetObject();
                obj.ObjectID = i;
                uint objectNameOffset = reader.ReadUInt32();
                uint objectTypeOffset = reader.ReadUInt32();
                obj.UnknownBytes       = reader.ReadBytes(16); //parameter.Unknown 16 bytes (pattern tends to be 40 00 00 00/01 (depending on whether object is activated by a group) 00 00 00 00 00 00 00 00 00 00 00 00)
                obj.Transform.Position = reader.ReadVector3();
                obj.DrawDistance       = reader.ReadSingle();
                obj.Transform.Rotation = reader.ReadQuaternion();
                uint parameterCount  = reader.ReadUInt32();
                uint parameterOffset = reader.ReadUInt32();

                long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters

                //Object Name and Type
                reader.JumpTo(objectNameOffset, false);
                obj.ObjectName = reader.ReadNullTerminatedString();
                reader.JumpTo(objectTypeOffset, false);
                obj.ObjectType = reader.ReadNullTerminatedString();

                reader.JumpTo(parameterOffset, false);
                //Object Parameters
                for (uint c = 0; c < parameterCount; c++)
                {
                    var  parameter     = new SetObjectParam();
                    uint parameterType = reader.ReadUInt32();
                    switch (parameterType)
                    {
                    case 0:     //boolean
                        parameter.DataType = typeof(bool);
                        parameter.Data     = reader.ReadUInt32() == 1;
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 1:     //int
                        parameter.DataType = typeof(int);
                        parameter.Data     = reader.ReadInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 2:     //single
                        parameter.DataType = typeof(float);
                        parameter.Data     = reader.ReadSingle();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 3:     //string
                        uint offset = reader.ReadUInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();

                        long stringParameterPosition = reader.BaseStream.Position;     //Save position so we can jump back after reading name, type and parameters
                        reader.JumpTo(offset, false);

                        parameter.DataType = typeof(string);
                        parameter.Data     = reader.ReadNullTerminatedString();

                        reader.JumpTo(stringParameterPosition, true);
                        break;

                    case 4:     //Vector3
                        parameter.DataType = typeof(Vector3);
                        parameter.Data     = reader.ReadVector3();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    case 6:     //uint
                        parameter.DataType = typeof(uint);
                        parameter.Data     = reader.ReadUInt32();
                        parameter.Unknown1 = reader.ReadUInt32();
                        parameter.Unknown2 = reader.ReadUInt32();
                        parameter.Unknown3 = reader.ReadUInt32();
                        break;

                    default:
                        Console.WriteLine("Unhandled Data Type!");
                        break;
                    }
                    obj.Parameters.Add(parameter);
                }

                //Save Object and jump back for the next one
                Objects.Add(obj);
                reader.JumpTo(position, true);
            }

            //Groups
            reader.JumpTo(groupTableOffset, false);
            for (uint i = 0; i < groupCount; i++)
            {
                var  group           = new SetGroup();
                uint groupNameOffset = reader.ReadUInt32();
                uint groupTypeOffset = reader.ReadUInt32();
                group.GroupObjectCount = reader.ReadUInt32();
                uint groupObjectListOffset = reader.ReadUInt32();

                long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and object list

                //Group Name and Type
                reader.JumpTo(groupNameOffset, false);
                group.GroupName = reader.ReadNullTerminatedString();
                reader.JumpTo(groupTypeOffset, false);
                group.GroupType = reader.ReadNullTerminatedString();

                //Group Object List
                reader.JumpTo(groupObjectListOffset, false);
                for (uint c = 0; c < group.GroupObjectCount; c++)
                {
                    reader.JumpAhead(4);
                    group.ObjectIDs.Add(reader.ReadUInt32());
                }

                //Save Group and jump back for the next one
                Groups.Add(group);
                reader.JumpTo(position, true);
            }
        }
        protected SetObject ReadObject(BINAReader reader,
                                       Dictionary <string, SetObjectType> objectTemplates)
        {
            var   obj           = new SetObject();
            ulong padding1      = reader.ReadUInt64();
            long  objTypeOffset = reader.ReadInt64();
            long  objNameOffset = reader.ReadInt64();

            ushort id            = reader.ReadUInt16();
            ushort groupID       = reader.ReadUInt16();
            ushort parentID      = reader.ReadUInt16();
            ushort parentGroupID = reader.ReadUInt16();

            obj.CustomData.Add("ParentID", new SetObjectParam(
                                   typeof(ushort), parentID));
            obj.CustomData.Add("ParentGroupID", new SetObjectParam(
                                   typeof(ushort), parentGroupID));

            obj.ObjectID = id;
            obj.CustomData.Add("GroupID", new SetObjectParam(
                                   typeof(ushort), groupID));

            var pos            = reader.ReadVector3();
            var rot            = reader.ReadVector3();
            var childPosOffset = reader.ReadVector3();
            var childRotOffset = reader.ReadVector3();

            obj.CustomData.Add("ChildPosOffset", new SetObjectParam(
                                   typeof(Vector3), childPosOffset));

            obj.CustomData.Add("ChildRotOffset", new SetObjectParam(
                                   typeof(Vector3), childRotOffset));

            obj.Transform.Position = pos;
            obj.Transform.Rotation = new Quaternion(rot, true);

            long  extraParamsOffset = reader.ReadInt64();
            ulong unknownCount1     = reader.ReadUInt64();
            ulong unknownCount2     = reader.ReadUInt64();
            ulong padding3          = reader.ReadUInt64();

            long objParamsOffset = reader.ReadInt64();

            // Unknown Count Checks
            if (unknownCount1 != unknownCount2)
            {
                Console.WriteLine(
                    "WARNING: UnknownCount1 ({0}) != UnknownCount2 ({1})",
                    unknownCount1, unknownCount2);
            }

            if (unknownCount1 > 1)
            {
                Console.WriteLine(
                    "WARNING: UnknownCount1 > 1 ({0})",
                    unknownCount1);
            }

            // Extra Parameter Offsets
            var extraParamOffsets = new long[unknownCount1];

            reader.JumpTo(extraParamsOffset, false);

            for (uint i = 0; i < unknownCount1; ++i)
            {
                extraParamOffsets[i] = reader.ReadInt64();
                ulong padding5 = reader.ReadUInt64(); // TODO: Make sure this is correct
            }

            // Extra Parameters
            for (uint i = 0; i < unknownCount1; ++i)
            {
                reader.JumpTo(extraParamOffsets[i], false);
                ulong padding6 = reader.ReadUInt64();

                long  extraParamNameOffset = reader.ReadInt64();
                ulong extraParamLength     = reader.ReadUInt64();
                long  extraParamDataOffset = reader.ReadInt64();

                // Extra Parameter Data
                reader.JumpTo(extraParamDataOffset, false);
                var data = reader.ReadBytes((int)extraParamLength);

                // Extra Parameter Name
                reader.JumpTo(extraParamNameOffset, false);
                string name = reader.ReadNullTerminatedString();

                // Parse Data
                switch (name)
                {
                case "RangeSpawning":
                {
                    obj.CustomData.Add("RangeIn", new SetObjectParam(
                                           typeof(float), BitConverter.ToSingle(data, 0)));

                    obj.CustomData.Add("RangeOut", new SetObjectParam(
                                           typeof(float), BitConverter.ToSingle(data, 4)));
                    continue;
                }
                }

                Console.WriteLine($"WARNING: Unknown extra parameter type {name}");
                obj.CustomData.Add(name, new SetObjectParam(
                                       data.GetType(), data));
            }

            // Object Name
            reader.JumpTo(objNameOffset, false);
            string objName = reader.ReadNullTerminatedString();

            obj.CustomData.Add("Name", new SetObjectParam(typeof(string), objName));

            // Object Type
            reader.JumpTo(objTypeOffset, false);
            string objType = reader.ReadNullTerminatedString();

            obj.ObjectType = objType;

            if (!objectTemplates.ContainsKey(objType))
            {
                Console.WriteLine(
                    "WARNING: Skipped {0} because there is no template for type {1}!",
                    objName, objType);
                Console.WriteLine("Params at: {0:X}",
                                  objParamsOffset + reader.Offset);
                return(null);
            }

            //Console.WriteLine("\"{1}\" Params at: {0:X}",
            //    objParamsOffset + reader.Offset, objName);
            var template = objectTemplates[objType];

            // Object Parameters
            reader.JumpTo(objParamsOffset, false);
            foreach (var param in template.Parameters)
            {
                obj.Parameters.Add(ReadParameter(reader, param));
            }

            // Additional Padding
            var rawDataLenExtra = template.GetExtra("RawByteLength");

            if (uint.TryParse(rawDataLenExtra?.Value, out var rawLength))
            {
                uint paramLen = (uint)(reader.BaseStream.Position -
                                       objParamsOffset - reader.Offset);

                if (paramLen != rawLength)
                {
                    obj.CustomData.Add("RawByteLength", new SetObjectParam(
                                           typeof(uint), rawLength));
                }
            }

            // Padding Checks
            if (padding1 != 0)
            {
                Console.WriteLine($"WARNING: Obj Padding1 != 0 ({padding1})");
            }

            if (padding3 != 0)
            {
                Console.WriteLine($"WARNING: Obj Padding3 != 0 ({padding3})");
            }

            return(obj);
        }