예제 #1
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);
            }
        }
예제 #2
0
        public void GensExportXML(Stream fileStream,
                                  Dictionary <string, SetObjectType> objectTemplates  = null,
                                  Dictionary <string, string> ColorstoGensRenamers    = null,
                                  Dictionary <string, string> ColorstoGensObjPhys     = null,
                                  Dictionary <string, string> ColorstoGensPosYMods    = null,
                                  Dictionary <string, string> ColorstoGensRotateXMods = null,
                                  Dictionary <string, string> ColorstoGensRotateYMods = null,
                                  Dictionary <string, string> ColorstoGensParamMods   = null)
        {
            // Convert to XML file and save
            var rootElem = new XElement("SetObject");

            foreach (var obj in Objects)
            {
                // Skip objects with no template.
                if (!objectTemplates.ContainsKey(obj.ObjectType))
                {
                    continue;
                }

                // Generate Object Element
                string GensObjName = obj.ObjectType;
                // Rename if applicable
                foreach (var node in ColorstoGensRenamers)
                {
                    if (GensObjName == node.Value)
                    {
                        GensObjName = node.Key;
                    }
                }

                var objElem = new XElement(GensObjName);

                // Generate CustomData Element
                // Messy use RangeOut value as Range value.
                foreach (var customData in obj.CustomData)
                {
                    // Experimental - use RangeIn as Range for SoundPoint
                    if (customData.Key == "RangeIn")
                    {
                        if (obj.ObjectType == "EnvSound")
                        {
                            objElem.Add(GenerateParamElementGens(
                                            customData.Value, "Range"));
                        }
                    }
                    else if (customData.Key == "RangeOut")
                    {
                        if (obj.ObjectType == "EnvSound")
                        {
                            objElem.Add(GenerateParamElementGens(
                                            customData.Value, "Radius"));
                        }
                        else
                        {
                            objElem.Add(GenerateParamElementGens(
                                            customData.Value, "Range"));
                        }
                    }
                }

                // Generate Parameters Element
                var template = objectTemplates?[obj.ObjectType];

                for (int i = 0; i < obj.Parameters.Count; ++i)
                {
                    string name = template?.Parameters[i].Name;
                    // Ignore parameters containing "Unknown"
                    if (!name.Contains("Unknown"))
                    {
                        objElem.Add(GenerateParamElementGens(obj.Parameters[i],
                                                             template?.Parameters[i].Name));
                    }
                }
                // Change to ObjectPhysics if necessary
                foreach (var node in ColorstoGensObjPhys)
                {
                    if (obj.ObjectType == node.Key)
                    {
                        var param = new SetObjectParam();
                        param.DataType = typeof(string);
                        param.Data     = obj.ObjectType;
                        objElem.Add(GenerateParamElementGens(param, "Type"));
                        objElem.Name = "ObjectPhysics";
                    }
                }

                // Generate Transforms Elements
                // Apply position to objects that need it
                float posYModifier = new float();
                foreach (var node in ColorstoGensPosYMods)
                {
                    if (obj.ObjectType == node.Key)
                    {
                        posYModifier = float.Parse(node.Value.ToString());
                        break;
                    }
                }
                objElem.Add(GeneratePositionElement(obj.Transform, obj.ObjectType, posYModifier));
                // Apply rotation to objects that need it
                // X
                float rotateXModifier = new float();
                foreach (var node in ColorstoGensRotateXMods)
                {
                    if (obj.ObjectType == node.Key)
                    {
                        rotateXModifier = float.Parse(node.Value.ToString());
                        break;
                    }
                }
                // Y
                float rotateYModifier = new float();
                foreach (var node in ColorstoGensRotateYMods)
                {
                    if (obj.ObjectType == node.Key)
                    {
                        rotateYModifier = float.Parse(node.Value.ToString());
                        break;
                    }
                }
                objElem.Add(GenerateRotationElement(obj.Transform, obj.ObjectType,
                                                    rotateXModifier, rotateYModifier));

                // Generate ID Element
                var objIDAttr = new XElement("SetObjectID", obj.ObjectID);
                objElem.Add(objIDAttr);

                // Generate MultiSet Elements
                if (obj.Children.Length > 0)
                {
                    var multiElem = new XElement("MultiSetParam");

                    for (int i = 0; i < obj.Children.Length; ++i)
                    {
                        var childElem = new XElement("Element");
                        childElem.Add(new XElement("Index", i + 1));
                        childElem.Add(GeneratePositionElement(obj.Children[i], obj.ObjectType,
                                                              posYModifier));
                        childElem.Add(GenerateRotationElement(obj.Children[i], obj.ObjectType,
                                                              rotateXModifier, rotateYModifier));
                        multiElem.Add(childElem);
                    }
                    multiElem.Add(new XElement("BaseLine", 1));
                    multiElem.Add(new XElement("Direction", 0));
                    multiElem.Add(new XElement("Interval", 1));
                    multiElem.Add(new XElement("IntervalBase", 0));
                    multiElem.Add(new XElement("PositionBase", 0));
                    multiElem.Add(new XElement("RotationBase", 0));
                    objElem.Add(multiElem);
                }

                // Add all of this to the XDocument
                rootElem.Add(objElem);
            }

            var xml = new XDocument(rootElem);

            xml.Save(fileStream);

            // Sub-Methods
            XElement GenerateParamElementGens(
                SetObjectParam param, string name)
            {
                var dataType = param.DataType;
                var elem     = new XElement((string.IsNullOrEmpty(name)) ?
                                            "Parameter" : name);

                if (dataType == typeof(Vector3))
                {
                    // Scale
                    var tempVector3 = new Vector3();
                    tempVector3   = (Vector3)param.Data;
                    tempVector3.X = (tempVector3.X / 10);
                    tempVector3.Y = (tempVector3.Y / 10);
                    tempVector3.Z = (tempVector3.Z / 10);
                    param.Data    = tempVector3;

                    Helpers.XMLWriteVector3(elem, (Vector3)param.Data);
                }
                else if (dataType == typeof(Vector4) || dataType == typeof(Quaternion))
                {
                    Helpers.XMLWriteVector4(elem, (Vector4)param.Data);
                }
                else if (dataType == typeof(Single))
                {
                    var singleValue = new Single();
                    singleValue = float.Parse(param.Data.ToString());
                    // Parameter scaling
                    foreach (var node in ColorstoGensParamMods)
                    {
                        if (name.Contains(node.Key))
                        {
                            singleValue = singleValue / float.Parse(node.Value.ToString());
                            break;
                        }
                    }

                    if (System.Math.Abs(singleValue) < 1)
                    {
                        elem.Value = singleValue.ToString("0.########################");
                        // Prevent scientific notation
                    }
                    else
                    {
                        elem.Value = singleValue.ToString(
                            "#################################.########################");
                        // Prevent scientific notation
                    }
                }
                else if ((name == "ACameraID") || (name == "BCameraID") ||
                         (name == "ALinkObjID") || (name == "BLinkObjID"))
                {
                    var targetIDAttr = new XElement("SetObjectID", param.Data.ToString());
                    elem.Add(targetIDAttr);
                }
                else
                {
                    elem.Value = param.Data.ToString();
                    // Boolean caps
                    if (param.Data.ToString() == "True")
                    {
                        elem.Value = "true";
                    }
                    else if (param.Data.ToString() == "False")
                    {
                        elem.Value = "false";
                    }
                }

                return(elem);
            }

            XElement GeneratePositionElement(
                SetObjectTransform transform, string name = "Transform", float posYModifier = 0)
            {
                // Convert Position into elements.
                var posElem = new XElement("Position");

                // Scaling
                transform.Position.X = (transform.Position.X / 10);
                transform.Position.Y = ((transform.Position.Y / 10) + posYModifier);
                transform.Position.Z = (transform.Position.Z / 10);

                Helpers.XMLWriteVector3(posElem, transform.Position);

                // Add elements to new position element and return it.
                return(new XElement(posElem));
            }

            XElement GenerateRotationElement(
                SetObjectTransform transform, string name = "Transform",
                float rotateXModifier = 0, float rotateYModifier = 0)
            {
                // Convert Rotation into elements.
                var rotElem = new XElement("Rotation");

                // Rotate objects that need it
                if (rotateXModifier != 0 || rotateYModifier != 0)
                {
                    var temp = transform.Rotation.ToEulerAngles();
                    // X
                    if (rotateXModifier != 0)
                    {
                        if ((temp.Y == 0) && (temp.Z == 0))
                        {
                            temp.X             = temp.X + rotateXModifier;
                            transform.Rotation = new Quaternion(temp);
                        }
                        else if ((temp.Y == 0) && (System.Math.Abs(rotateXModifier) == 90))
                        {
                            temp.X = -90 + System.Math.Abs(temp.Z);
                            temp.Y = rotateXModifier * -1;
                            temp.Z = -90;
                            Console.WriteLine("X rotation");
                            // This is necessary since conversion between
                            // Vector 3 and Quaternion is wonky
                            var   Rotation = new Quaternion(temp);
                            float temptemp = Rotation.Y;
                            Rotation.Y         = Rotation.W;
                            Rotation.W         = temptemp;
                            transform.Rotation = new Quaternion(Rotation);
                        }
                        else
                        {
                            Console.WriteLine("Unsupported X rotation modification detected");
                        }
                    }
                    // Y
                    if (rotateYModifier != 0)
                    {
                        temp.Y = temp.Y + rotateYModifier;
                        if ((rotateYModifier == 180) || (rotateYModifier == -180))
                        {
                            temp.X = temp.X * -1;
                        }
                        else if ((rotateYModifier == 90) || (rotateYModifier == -90))
                        {
                            float temptemp = temp.X;
                            temp.X = temp.Z;
                            temp.Z = temptemp;

                            if (rotateYModifier == 90)
                            {
                                temp.X = temp.X * -1;
                            }
                        }
                        else
                        {
                            Console.WriteLine("Y Rotation currently only supports 90, 180 or -90 degrees on Y axis.");
                        }
                        transform.Rotation = new Quaternion(temp);
                    }
                }

                Helpers.XMLWriteVector4(rotElem, transform.Rotation);

                // Add elements to new rotation element and return it.
                return(new XElement(rotElem));
            }
        }
예제 #3
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);
            }
        }
예제 #4
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 SetObjectParam ReadParameter(BINAReader reader, SetObjectTypeParam param)
        {
            FixPadding(reader, param.DataType);

            // Special Param Types
            if (param is SetObjectTypeParamGroup group)
            {
                var g           = new SetObjectParamGroup(group.Padding);
                var groupParams = g.Parameters;

                foreach (var p in group.Parameters)
                {
                    groupParams.Add(ReadParameter(reader, p));
                }

                reader.FixPadding(group.Padding ?? 16);
                return(g);
            }
            else if (param.DataType == typeof(ObjectReference[]))
            {
                long  arrOffset  = reader.ReadInt64();
                ulong arrLength  = reader.ReadUInt64();
                ulong arrLength2 = reader.ReadUInt64();
                long  curPos     = reader.BaseStream.Position;

                if (arrLength != arrLength2)
                {
                    Console.WriteLine(
                        "WARNING: ArrLength ({0}) != ArrLength2 ({1})",
                        arrLength, arrLength2);
                }

                var arr = new ObjectReference[arrLength];
                if (arrLength > 0 && arrOffset > 0)
                {
                    reader.JumpTo(arrOffset, false);
                    for (uint i = 0; i < arrLength; ++i)
                    {
                        arr[i] = new ObjectReference(reader);
                    }

                    reader.JumpTo(curPos);
                }

                return(new SetObjectParam(param.DataType, arr));
            }
            else if (param.DataType == typeof(ObjectReference))
            {
                return(new SetObjectParam(typeof(ObjectReference),
                                          new ObjectReference(reader)));
            }
            else if (param.DataType == typeof(string))
            {
                var  stringParam   = new SetObjectParam(typeof(string), string.Empty);
                long offset        = reader.ReadInt64();
                long stringPadding = reader.ReadInt64();

                if (offset > 0)
                {
                    long curPos = reader.BaseStream.Position;
                    reader.JumpTo(offset, false);
                    stringParam.Data = reader.ReadNullTerminatedString();
                    reader.JumpTo(curPos);
                }

                if (stringPadding != 0)
                {
                    Console.WriteLine("WARNING: String Padding != 0 ({0:X})!!", stringPadding);
                }

                //reader.FixPadding(16);
                return(stringParam);
            }

            // Data
            var objParam = new SetObjectParam(param.DataType,
                                              reader.ReadByType(param.DataType));

            // Post-Param Padding
            if (param.DataType == typeof(Vector3))
            {
                uint vecPadding = reader.ReadUInt32();
                if (vecPadding != 0)
                {
                    Console.WriteLine("WARNING: Vector Padding != 0 ({0:X})!!", vecPadding);
                }
            }

            return(objParam);
        }
예제 #6
0
        private static SetObject ReadObject(ExtendedBinaryReader reader,
                                            SetObjectType objTemplate, string objType, SOBJType type,
                                            bool rawDataMode = false) // true = full, false = only remaining bytes
        {
            // For some reason these separate values are saved as one uint rather than two ushorts.
            // Because of this, the values are in a different order depending on endianness, and
            // this is the easiest known way to read them.
            uint   unknownValue = reader.ReadUInt32();
            ushort unknown1     = (ushort)((unknownValue >> 16) & 0xFFFF);
            ushort objID        = (ushort)(unknownValue & 0xFFFF);

            var obj = new SetObject()
            {
                ObjectType = objType,
                ObjectID   = objID
            };

            uint  unknown2 = reader.ReadUInt32();
            uint  unknown3 = reader.ReadUInt32();
            float unknown4 = reader.ReadSingle();

            float rangeIn          = reader.ReadSingle();
            float rangeOut         = reader.ReadSingle();
            uint  parent           = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;
            uint  transformsOffset = reader.ReadUInt32();

            uint transformCount = reader.ReadUInt32();
            uint unknown5       = reader.ReadUInt32();
            uint unknown6       = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;
            uint unknown7       = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0;

            // Call me crazy, but I have a weird feeling these values aren't JUST padding
            if (unknown3 != 0 || unknown5 != 0 || unknown6 != 0 || unknown7 != 0)
            {
                Console.WriteLine("WARNING: Not padding?! ({0},{1},{2},{3})",
                                  unknown3, unknown5, unknown6, unknown7);
            }

            // Add custom data to object
            obj.CustomData.Add("Unknown1", new SetObjectParam(typeof(ushort), unknown1));
            obj.CustomData.Add("Unknown2", new SetObjectParam(typeof(uint), unknown2));
            obj.CustomData.Add("Unknown3", new SetObjectParam(typeof(uint), unknown3));
            obj.CustomData.Add("Unknown4", new SetObjectParam(typeof(float), unknown4));
            obj.CustomData.Add("RangeIn", new SetObjectParam(typeof(float), rangeIn));
            obj.CustomData.Add("RangeOut", new SetObjectParam(typeof(float), rangeOut));

            if (type == SOBJType.LostWorld)
            {
                obj.CustomData.Add("Parent", new SetObjectParam(typeof(uint), parent));
            }

            // Skip loading parameters if template doesn't exist
            if (objTemplate != null)
            {
                // Get Raw Byte Length
                var  rawDataLenExtra = objTemplate.GetExtra("RawByteLength");
                long paramBegin      = reader.BaseStream.Position;
                int  rawLength       = 0;

                if (rawDataLenExtra != null &&
                    !string.IsNullOrEmpty(rawDataLenExtra.Value))
                {
                    int.TryParse(rawDataLenExtra.Value, out rawLength);
                }

                // Read all the data then return to beginning
                if (rawDataMode == true && rawLength != 0)
                {
                    obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]),
                                                                          reader.ReadBytes(rawLength)));
                    reader.JumpTo(paramBegin);
                }

                // Parameters
                foreach (var param in objTemplate.Parameters)
                {
                    // For compatibility with SonicGlvl templates.
                    if (param.Name == "Unknown1" || param.Name == "Unknown2" ||
                        param.Name == "Unknown3" || param.Name == "RangeIn" ||
                        param.Name == "RangeOut" || param.Name == "Parent")
                    {
                        continue;
                    }

                    // Read Special Types/Fix Padding
                    if (param.DataType == typeof(uint[]))
                    {
                        // Data Info
                        reader.FixPadding(4);
                        uint arrOffset  = reader.ReadUInt32();
                        uint arrLength  = reader.ReadUInt32();
                        uint arrUnknown = reader.ReadUInt32();
                        long curPos     = reader.BaseStream.Position;

                        // Data
                        var arr = new uint[arrLength];
                        reader.JumpTo(arrOffset, false);

                        for (uint i = 0; i < arrLength; ++i)
                        {
                            arr[i] = reader.ReadUInt32();
                        }

                        obj.Parameters.Add(new SetObjectParam(param.DataType, arr));
                        reader.BaseStream.Position = curPos;
                        continue;
                    }
                    else if (param.DataType == typeof(string))
                    {
                        // Data Info
                        uint   strOffset  = reader.ReadUInt32();
                        uint   strUnknown = reader.ReadUInt32();
                        string str        = null;

                        // Data
                        if (strOffset != 0)
                        {
                            long curPos = reader.BaseStream.Position;
                            reader.JumpTo(strOffset, false);

                            str = reader.ReadNullTerminatedString();
                            reader.BaseStream.Position = curPos;
                        }

                        obj.Parameters.Add(new SetObjectParam(param.DataType, str));
                        continue;
                    }
                    else if (param.DataType == typeof(float) ||
                             param.DataType == typeof(int) || param.DataType == typeof(uint))
                    {
                        reader.FixPadding(4);
                    }
                    else if (type == SOBJType.LostWorld && param.DataType == typeof(Vector3))
                    {
                        reader.FixPadding(16);
                    }

                    // Read Data
                    var objParam = new SetObjectParam(param.DataType,
                                                      reader.ReadByType(param.DataType));
                    obj.Parameters.Add(objParam);
                }

                if (rawDataMode == false)
                {
                    long knownParamLength = (reader.BaseStream.Position - paramBegin);
                    long remainingBytes   = (rawLength - knownParamLength);

                    obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]),
                                                                          reader.ReadBytes((int)remainingBytes)));
                }
            }

            // Transforms
            uint childCount = transformCount - 1;

            obj.Children = new SetObjectTransform[childCount];
            reader.JumpTo(transformsOffset, false);

            obj.Transform = ReadTransform(reader, type == SOBJType.LostWorld);
            for (uint i = 0; i < childCount; ++i)
            {
                obj.Children[i] = ReadTransform(reader,
                                                type == SOBJType.LostWorld);
            }

            return(obj);
        }