public static XElement WriteObject(SetObject obj, SetObjectType type = null)
        {
            // Parameters
            var elem = new XElement(obj.ObjectType);

            for (int i = 0; i < obj.Parameters.Count; ++i)
            {
                elem.Add(new XElement((type == null) ?
                                      $"Parameter{i + 1}" : type.Parameters[i].Name,
                                      obj.Parameters[i].Data));
            }

            // MultiSetTransforms
            if (obj.Children.Length > 0)
            {
                var multiSetParam = new XElement("MultiSetParam");
                for (int i = 0; i < obj.Children.Length;)
                {
                    var multiSetElem = new XElement("Element");
                    multiSetElem.AddElem("Index", ++i);
                    WriteTransform(obj.Children[i], multiSetElem);
                    multiSetParam.Add(multiSetElem);
                }

                elem.AddElem("BaseLine", 0);
                elem.AddElem("Count", obj.Children.Length + 1); // TODO: Is this right?
                elem.AddElem("Direction", 0);
                elem.AddElem("Interval", 1.5f);
                elem.AddElem("IntervalBase", 0);
                elem.AddElem("PositionBase", 0);
                elem.AddElem("RotationBase", 0);

                elem.Add(multiSetParam);
            }

            // Transform
            WriteTransform(obj.Transform, elem);

            // Special Parameters
            elem.AddElem("Range", obj.GetCustomDataValue <float>("Range", 100));
            elem.AddElem("SetObjectID", obj.ObjectID);

            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Range")
                {
                    continue;
                }

                elem.Add(new XElement(
                             customData.Key, customData.Value));
            }

            return(elem);
        }
        protected bool WriteExtraParamData(
            BINAWriter writer, SetObject obj,
            KeyValuePair <string, SetObjectParam> customData)
        {
            var param = customData.Value;

            switch (customData.Key)
            {
            case "RangeIn":
                writer.Write((float)param.Data);
                writer.Write(obj.GetCustomDataValue <float>("RangeOut"));
                return(true);
            }

            return(false);
        }
Beispiel #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();

            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);
            }
        }
Beispiel #4
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);
            }
        }
        public void ImportXML(Stream fileStream)
        {
            // Load XML and add loaded data to set data
            var  xml   = XDocument.Load(fileStream);
            uint objID = 0; // For Object elements with no ID attribute.

            foreach (var objElem in xml.Root.Elements("Object"))
            {
                // Generate Object
                var typeAttr  = objElem.Attribute("type");
                var objIDAttr = objElem.Attribute("id");
                if (typeAttr == null)
                {
                    continue;
                }

                var obj = new SetObject()
                {
                    ObjectType = typeAttr.Value,
                    ObjectID   = (objIDAttr == null) ?
                                 objID : Convert.ToUInt32(objIDAttr.Value),
                };

                // Assign CustomData to Object
                var customDataElem = objElem.Element("CustomData");
                if (customDataElem != null)
                {
                    foreach (var customData in customDataElem.Elements())
                    {
                        obj.CustomData.Add(customData.Name.LocalName,
                                           LoadParam(customData));
                    }
                }

                // Assign Parameters to Object
                var parametersElem = objElem.Element("Parameters");
                if (parametersElem != null)
                {
                    foreach (var paramElem in parametersElem.Elements())
                    {
                        obj.Parameters.Add(LoadParam(paramElem));
                    }
                }

                // Assign Transforms to Object
                var transformsElem = objElem.Element("Transforms");
                if (transformsElem != null)
                {
                    var transforms     = transformsElem.Elements("Transform");
                    int transformCount = transforms.Count();

                    if (transformCount > 0)
                    {
                        uint i = 0;
                        obj.Children = new SetObjectTransform[transformCount - 1];

                        foreach (var transformElem in transforms)
                        {
                            var transform = LoadTransform(transformElem);
                            if (i > 0)
                            {
                                obj.Children[i - 1] = transform;
                            }
                            else
                            {
                                obj.Transform = transform;
                            }

                            ++i;
                        }
                    }
                }

                ++objID;
                Objects.Add(obj);
            }

            // Sub-Methods
            SetObjectParam LoadParam(XElement paramElem)
            {
                // Groups
                var dataTypeAttr = paramElem.Attribute("type");

                if (dataTypeAttr == null)
                {
                    var  padAttr = paramElem.Attribute("padding");
                    uint?padding = null;

                    if (uint.TryParse(padAttr?.Value, out var pad))
                    {
                        padding = pad;
                    }

                    var group      = new SetObjectParamGroup(padding);
                    var parameters = group.Parameters;

                    foreach (var param in paramElem.Elements())
                    {
                        parameters.Add(LoadParam(param));
                    }

                    return(group);
                }

                // Parameters
                var    dataType = Types.GetTypeFromString(dataTypeAttr.Value);
                object data     = null;

                if (dataType == typeof(Vector2))
                {
                    data = Helpers.XMLReadVector2(paramElem);
                }
                else if (dataType == typeof(Vector3))
                {
                    data = Helpers.XMLReadVector3(paramElem);
                }
                else if (dataType == typeof(Vector4))
                {
                    data = Helpers.XMLReadVector4(paramElem);
                }
                else if (dataType == typeof(Quaternion))
                {
                    data = Helpers.XMLReadQuat(paramElem);
                }
                else if (dataType == typeof(uint[]))
                {
                    var  countAttr = paramElem.Attribute("count");
                    uint arrLength = 0;

                    if (countAttr != null)
                    {
                        uint.TryParse(countAttr.Value, out arrLength);
                    }

                    var values = paramElem.Value.Split(',');
                    var arr    = new uint[arrLength];
                    for (uint i = 0; i < arrLength; ++i)
                    {
                        if (i >= values.Length)
                        {
                            break;
                        }

                        uint.TryParse(values[i], out arr[i]);
                    }

                    data = arr;
                }
                else if (dataType == typeof(ForcesSetData.ObjectReference[]))
                {
                    var  countAttr = paramElem.Attribute("count");
                    uint arrLength = 0;

                    if (countAttr != null)
                    {
                        uint.TryParse(countAttr.Value, out arrLength);
                    }

                    uint i   = 0;
                    var  arr = new ForcesSetData.ObjectReference[arrLength];

                    foreach (var refElem in paramElem.Elements("ForcesObjectReference"))
                    {
                        var objRef = new ForcesSetData.ObjectReference();
                        objRef.ImportXML(refElem);
                        arr[i] = objRef;
                        ++i;
                    }

                    data = arr;
                }
                else if (dataType == typeof(ForcesSetData.ObjectReference))
                {
                    var objRef = new ForcesSetData.ObjectReference();
                    objRef.ImportXML(paramElem);
                    data = objRef;
                }
                else
                {
                    data = Convert.ChangeType(paramElem.Value, dataType);
                }

                return(new SetObjectParam(dataType, data));
            }

            SetObjectTransform LoadTransform(XElement elem)
            {
                var posElem   = elem.Element("Position");
                var rotElem   = elem.Element("Rotation");
                var scaleElem = elem.Element("Scale");

                return(new SetObjectTransform()
                {
                    Position = Helpers.XMLReadVector3(posElem),
                    Rotation = Helpers.XMLReadQuat(rotElem),
                    Scale = Helpers.XMLReadVector3(scaleElem)
                });
            }
        }
Beispiel #6
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);
            }
        }
        public static SetObject ReadObject(XElement element, string elemName = null,
                                           Dictionary <string, SetObjectType> objectTemplates = null)
        {
            // Parameters
            var parameters = new List <SetObjectParam>();
            var transform  = new SetObjectTransform();

            SetObjectTransform[] children = null;
            uint? objID = null;
            float?range = null;

            if (elemName == null)
            {
                elemName = element.Name.LocalName;
            }

            foreach (var paramElement in element.Elements())
            {
                // Special parameters
                string paramName = paramElement.Name.LocalName;
                switch (paramName.ToLower())
                {
                case "position":
                    transform.Position = paramElement.GetVector3();
                    continue;

                case "range":
                    range = float.Parse(paramElement.Value);
                    continue;

                case "rotation":
                    transform.Rotation = paramElement.GetQuaternion();
                    continue;

                case "setobjectid":
                    objID = uint.Parse(paramElement.Value);
                    continue;

                case "multisetparam":
                {
                    var countElem = paramElement.Element("Count");
                    if (countElem == null)
                    {
                        continue;
                    }

                    if (!int.TryParse(countElem.Value, out var childCount))
                    {
                        continue;
                    }

                    var childObjs = new List <SetObjectTransform>();
                    foreach (var specialElem in paramElement.Elements())
                    {
                        switch (specialElem.Name.LocalName.ToLower())
                        {
                        case "element":
                        {
                            var indexElem = specialElem.Element("Index");
                            var posElem   = specialElem.Element("Position");
                            var rotElem   = specialElem.Element("Rotation");

                            if (indexElem == null || !int.TryParse(
                                    indexElem.Value, out var index))
                            {
                                continue;
                            }

                            childObjs.Add(new SetObjectTransform()
                                    {
                                        Position = specialElem.GetVector3Elem("Position"),
                                        Rotation = specialElem.GetQuatElem("Rotation")
                                    });
                            break;
                        }

                            // TODO: Parse other elements.
                        }
                    }

                    children = childObjs.ToArray();
                    continue;
                }
                }

                // Type
                bool doAutoDetect = (objectTemplates == null ||
                                     !objectTemplates.ContainsKey(elemName));

                var templateParam = (!doAutoDetect) ?
                                    objectTemplates[elemName].GetParameter(paramName) : null;

                var paramType = (doAutoDetect || templateParam == null) ?
                                AutoDetectParamType(paramElement) :
                                templateParam.DataType;
                if (paramType == null)
                {
                    continue;
                }

                // Data
                object data =
                    (paramType == typeof(Vector3)) ? paramElement.GetVector3() :
                    (paramType == typeof(Quaternion)) ? paramElement.GetQuaternion() :
                    Helpers.ChangeType(paramElement.Value, paramType);

                // Add the Parameter to the list
                parameters.Add(new SetObjectParam()
                {
                    Data     = data,
                    DataType = paramType
                });
            }

            // Ensure Object has ID
            if (!objID.HasValue)
            {
                Console.WriteLine("WARNING: {0} \"{1}\" {2}",
                                  "Object of type", elemName,
                                  "is missing its object ID! Skipping this object...");
                return(null);
            }

            // Generate Object
            var obj = new SetObject()
            {
                ObjectType = elemName,
                Parameters = parameters,
                Transform  = transform,
                Children   = children ?? new SetObjectTransform[0],
                ObjectID   = objID.Value
            };

            if (range.HasValue)
            {
                obj.CustomData.Add("Range", new SetObjectParam(
                                       typeof(float), range.Value));
            }

            return(obj);
        }
        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);
        }
        protected void WriteObjectParameters(BINAWriter writer,
                                             SetObject obj, int objID)
        {
            uint arrIndex = 0, strIndex = 0;
            uint paramStartPos = (uint)writer.BaseStream.Position;

            writer.FillInOffsetLong($"objParamsOffset{objID}", false, false);

            // Write Normal Parameters
            foreach (var param in obj.Parameters)
            {
                WriteParameter(param);
            }

            // Padding
            uint rawLength = obj.GetCustomDataValue <uint>("RawByteLength");
            uint len       = (uint)(writer.BaseStream.Position - paramStartPos);

            if (rawLength > len)
            {
                writer.WriteNulls(rawLength - len);
            }

            // Write Arrays
            if (arrIndex < 1)
            {
                return; // Don't bother if there's not even any arrays
            }
            writer.FixPadding(8);
            arrIndex = 0;
            foreach (var param in obj.Parameters)
            {
                WriteArray(param);
            }

            // Sub-Methods
            void WriteParameter(SetObjectParam param)
            {
                FixPadding(writer, param.DataType);

                // Special Param Types
                if (param is SetObjectParamGroup group)
                {
                    foreach (var p in group.Parameters)
                    {
                        WriteParameter(p);
                    }

                    writer.FixPadding(group.Padding ?? 16);
                    return;
                }
                else if (param.DataType == typeof(ObjectReference[]))
                {
                    var   arr       = (param.Data as ObjectReference[]);
                    ulong arrLength = (ulong)arr.LongLength;

                    if (arrLength < 1)
                    {
                        writer.WriteNulls(24);
                        return;
                    }

                    writer.AddOffset($"obj{objID}ArrOffset{arrIndex}", 8);
                    writer.Write(arrLength);
                    writer.Write(arrLength);
                    ++arrIndex;
                    return;
                }
                else if (param.DataType == typeof(ObjectReference))
                {
                    var reference = (param.Data as ObjectReference);
                    if (reference == null)
                    {
                        writer.Write(0U);
                        return;
                    }

                    reference.Write(writer);
                    return;
                }
                else if (param.DataType == typeof(string))
                {
                    string str = (param.Data as string);
                    if (string.IsNullOrEmpty(str))
                    {
                        writer.Write(0UL);
                        writer.Write(0UL);
                        return;
                    }

                    writer.AddString($"obj{objID}StrOffset{strIndex}", str, 8);
                    writer.Write(0UL);
                    ++strIndex;
                    return;
                }

                // Data
                writer.WriteByType(param.DataType, param.Data);

                // Post-Param Padding
                if (param.DataType == typeof(Vector3))
                {
                    writer.Write(0U);
                }
            }

            void WriteArray(SetObjectParam param)
            {
                // Groups
                if (param is SetObjectParamGroup group)
                {
                    foreach (var p in group.Parameters)
                    {
                        WriteArray(p);
                    }

                    return;
                }

                // Array Values
                if (param.DataType == typeof(ObjectReference[]))
                {
                    var arr = (param.Data as ObjectReference[]);
                    if (arr == null || arr.Length < 1)
                    {
                        return;
                    }

                    writer.FillInOffsetLong($"obj{objID}ArrOffset{arrIndex}", false, false);
                    for (uint i = 0; i < arr.Length; ++i)
                    {
                        if (arr[i] == null)
                        {
                            writer.Write(0U);
                        }
                        else
                        {
                            arr[i].Write(writer);
                        }
                    }

                    ++arrIndex;
                }
            }
        }
        protected void WriteObject(BINAWriter writer, SetObject obj, int objID)
        {
            writer.Write(0UL);

            // Object Type
            writer.AddString($"objTypeOffset{objID}", obj.ObjectType, 8);

            // Object Name
            string name = "";

            if (obj.CustomData.ContainsKey("Name"))
            {
                name = (obj.CustomData["Name"].Data as string);
            }

            if (string.IsNullOrEmpty(name))
            {
                name = $"{obj.ObjectType}{objID}";
            }

            writer.AddString($"objNameOffset{objID}", name, 8);

            // Object Entry
            writer.Write((ushort)obj.ObjectID);
            writer.Write((obj.CustomData.ContainsKey("GroupID")) ?
                         (ushort)obj.CustomData["GroupID"].Data :
                         obj.GetCustomDataValue <ushort>("Unknown1"));

            writer.Write(obj.GetCustomDataValue <ushort>("ParentID"));
            writer.Write((obj.CustomData.ContainsKey("ParentGroupID")) ?
                         (ushort)obj.CustomData["ParentGroupID"].Data :
                         obj.GetCustomDataValue <ushort>("ParentUnknown1"));

            writer.Write(obj.Transform.Position);
            writer.Write(obj.Transform.Rotation.ToEulerAngles(true));

            writer.Write((obj.CustomData.ContainsKey("ChildPosOffset")) ?
                         (Vector3)obj.CustomData["ChildPosOffset"].Data :
                         obj.Transform.Position);

            writer.Write((obj.CustomData.ContainsKey("ChildRotOffset")) ?
                         (Vector3)obj.CustomData["ChildRotOffset"].Data :
                         obj.Transform.Rotation.ToEulerAngles(true));

            // Extra Parameter Entries
            uint extraParamCounts = (uint)obj.CustomData.Count;

            if (obj.CustomData.ContainsKey("Name"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("RangeOut"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("GroupID") ||
                obj.CustomData.ContainsKey("Unknown1"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ParentID"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ParentGroupID") ||
                obj.CustomData.ContainsKey("ParentUnknown1"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ChildPosOffset"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("ChildRotOffset"))
            {
                extraParamCounts -= 1;
            }

            if (obj.CustomData.ContainsKey("RawByteLength"))
            {
                extraParamCounts -= 1;
            }

            writer.AddOffset($"extraParamsOffset{objID}", 8);
            writer.Write((ulong)extraParamCounts); // TODO
            writer.Write((ulong)extraParamCounts); // TODO
            writer.Write(0UL);
            writer.AddOffset($"objParamsOffset{objID}", 8);
            writer.FixPadding(16);

            writer.FillInOffsetLong($"extraParamsOffset{objID}", false, false);
            writer.AddOffsetTable($"extraParamOffset{objID}", extraParamCounts, 8);
            writer.FixPadding(16); // TODO: Make sure this is correct

            int i = -1;

            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Name" || customData.Key == "GroupID" ||
                    customData.Key == "Unknown1" || customData.Key == "ParentID" ||
                    customData.Key == "ParentGroupID" || customData.Key == "ParentUnknown1" ||
                    customData.Key == "RangeOut" || customData.Key == "ChildPosOffset" ||
                    customData.Key == "ChildRotOffset" || customData.Key == "RawByteLength")
                {
                    continue;
                }

                writer.FillInOffsetLong(
                    $"extraParamOffset{objID}_{++i}", false, false);

                writer.Write(0UL);
                writer.AddString($"extraParamNameOffset{objID}{i}",
                                 (customData.Key == "RangeIn") ? "RangeSpawning" : customData.Key, 8);

                if (!WriteExtraParamLength(writer, customData))
                {
                    writer.Write(0);
                    Console.WriteLine(
                        $"WARNING: CustomData {customData.Key} skipped; Unknown Type!");
                }

                writer.AddOffset($"extraParamDataOffset{objID}{i}", 8);
            }

            // Extra Parameter Data
            foreach (var customData in obj.CustomData)
            {
                if (customData.Key == "Name" || customData.Key == "GroupID" ||
                    customData.Key == "Unknown1" || customData.Key == "ParentID" ||
                    customData.Key == "ParentGroupID" || customData.Key == "ParentUnknown1" ||
                    customData.Key == "RangeOut" || customData.Key == "ChildPosOffset" ||
                    customData.Key == "ChildRotOffset" || customData.Key == "RawByteLength")
                {
                    continue;
                }

                writer.FillInOffsetLong(
                    $"extraParamDataOffset{objID}{i}", false, false);

                if (!WriteExtraParamData(writer, obj, customData))
                {
                    writer.Write(0UL);
                }
            }
        }
Beispiel #11
0
        public static SetObject ReadObject(XElement element, string elemName = null,
                                           Dictionary <string, SetObjectType> objectTemplates = null)
        {
            // Parameters
            var parameters = new List <SetObjectParam>();
            var transform  = new SetObjectTransform();

            SetObjectTransform[] children = null;
            uint? objID = null;
            float?range = null;

            //float? drawDistance = null;
            //string objName = "";

            if (elemName == null)
            {
                elemName = element.Name.LocalName;
            }

            foreach (var paramElement in element.Elements())
            {
                // Special parameters
                string paramName = paramElement.Name.LocalName;
                switch (paramName.ToLower())
                {
                case "position":
                    transform.Position = paramElement.GetVector3();
                    continue;

                //case "range":
                //range = float.Parse(paramElement.Value);
                //continue;

                //case "drawdistance":
                //    drawDistance = float.Parse(paramElement.Value);
                //    continue;

                //case "objname":
                //    objName = paramElement.Value;
                //    continue;

                case "rotation":
                    transform.Rotation = paramElement.GetQuaternion();
                    continue;

                case "setobjectid":
                    objID = uint.Parse(paramElement.Value);
                    continue;

                case "multisetparam":
                {
                    var countElem = paramElement.Element("Count");
                    if (countElem == null)
                    {
                        continue;
                    }

                    if (!int.TryParse(countElem.Value, out var childCount))
                    {
                        continue;
                    }

                    var childObjs = new List <SetObjectTransform>();
                    foreach (var specialElem in paramElement.Elements())
                    {
                        switch (specialElem.Name.LocalName.ToLower())
                        {
                        case "element":
                        {
                            var indexElem = specialElem.Element("Index");
                            var posElem   = specialElem.Element("Position");
                            var rotElem   = specialElem.Element("Rotation");

                            if (indexElem == null || !int.TryParse(
                                    indexElem.Value, out var index))
                            {
                                continue;
                            }

                            childObjs.Add(new SetObjectTransform()
                                    {
                                        Position = specialElem.GetVector3Elem("Position"),
                                        Rotation = specialElem.GetQuatElem("Rotation")
                                    });
                            break;
                        }

                            // TODO: Parse other elements.
                        }
                    }

                    children = childObjs.ToArray();
                    continue;
                }
                }

                // Type
                bool doAutoDetect = (objectTemplates == null ||
                                     !objectTemplates.ContainsKey(elemName));

                var templateParam = (!doAutoDetect) ?
                                    objectTemplates[elemName].GetParameter(paramName) : null;

                var paramType = (doAutoDetect || templateParam == null) ?
                                AutoDetectParamType(paramElement) :
                                templateParam.DataType;
                if (paramType == null)
                {
                    continue;
                }

                // Data
                object data =
                    (paramType == typeof(Vector3)) ? paramElement.GetVector3() :
                    (paramType == typeof(Quaternion)) ? paramElement.GetQuaternion() :
                    Helpers.ChangeType(paramElement.Value, paramType);

                // Add the Parameter to the list
                parameters.Add(new SetObjectParam()
                {
                    Data     = data,
                    DataType = paramType
                });
            }

            // Ensure Object has ID
            if (!objID.HasValue)
            {
                Console.WriteLine("WARNING: {0} \"{1}\" {2}",
                                  "Object of type", elemName,
                                  "is missing its object ID! Skipping this object...");
                return(null);
            }

            // Generate Object
            var obj = new SetObject()
            {
                ObjectType = elemName,
                Parameters = parameters,
                Transform  = transform,
                Children   = children ?? new SetObjectTransform[0],
                ObjectID   = objID.Value,
                //ObjectName = objName
            };

            //if (range.HasValue)
            //{
            //    obj.CustomData.Add("Range", new SetObjectParam(
            //        typeof(float), range.Value));
            //}

            //if (drawDistance.HasValue)
            //{
            //    obj.DrawDistance = drawDistance.Value;
            //}
            //else
            //{
            //    obj.DrawDistance = 0;
            //}

            //Assign Unknown Bytes to object
            //var unknownBytesElem = element.Element("UnknownBytes");
            //int byteNumber = 0;
            //byte[] bytesXML = new byte[16];
            //if (unknownBytesElem != null)
            //{
            //    foreach (var bytes in unknownBytesElem.Elements())
            //    {
            //        bytesXML[byteNumber] = (byte)int.Parse(bytes.Value);
            //        byteNumber++;
            //    }
            //}
            //else
            //{
            //    bytesXML[0] = 64;
            //    bytesXML[1] = 0;
            //    bytesXML[2] = 0;
            //    bytesXML[3] = 0;
            //    bytesXML[4] = 0;
            //    bytesXML[5] = 0;
            //    bytesXML[6] = 0;
            //    bytesXML[7] = 0;
            //    bytesXML[8] = 0;
            //    bytesXML[9] = 0;
            //    bytesXML[10] = 0;
            //    bytesXML[11] = 0;
            //    bytesXML[12] = 0;
            //    bytesXML[13] = 0;
            //    bytesXML[14] = 0;
            //    bytesXML[15] = 0;
            //}
            //obj.UnknownBytes = bytesXML;

            return(obj);
        }
Beispiel #12
0
        private static void WriteObject(BINAWriter writer, SetObject obj, SOBJType type,
                                        bool rawDataMode = false) // true = full, false = only remaining bytes)
        {
            // Get a bunch of values from the object's custom data, if present.
            uint  unknown1 = obj.GetCustomDataValue <ushort>("Unknown1");
            uint  unknown2 = obj.GetCustomDataValue <uint>("Unknown2");
            uint  unknown3 = obj.GetCustomDataValue <uint>("Unknown3");
            float unknown4 = obj.GetCustomDataValue <float>("Unknown4");

            float rangeIn  = obj.GetCustomDataValue <float>("RangeIn");
            float rangeOut = obj.GetCustomDataValue <float>("RangeOut");
            uint  parent   = (type == SOBJType.LostWorld) ?
                             obj.GetCustomDataValue <uint>("Parent") : 0;

            var rawParamData = obj.GetCustomDataValue <byte[]>("RawParamData");

            // Combine the two values back into one so we can write with correct endianness.
            uint unknownData = (unknown1 << 16) | (obj.ObjectID & 0xFFFF);

            writer.Write(unknownData);

            writer.Write(unknown2);
            writer.Write(unknown3);
            writer.Write(unknown4);

            writer.Write(rangeIn);
            writer.Write(rangeOut);
            if (type == SOBJType.LostWorld)
            {
                writer.Write(parent);
            }
            writer.FixPadding(4);
            writer.AddOffset($"transformsOffset_{obj.ObjectID}");

            writer.Write((uint)obj.Children.Length + 1);
            writer.WriteNulls((type == SOBJType.LostWorld) ? 0xC : 4u);

            // Parameters
            long paramBegin = writer.BaseStream.Position;

            foreach (var param in obj.Parameters)
            {
                // Write Special Types/Fix Padding
                if (param.DataType == typeof(uint[]))
                {
                    // Data Info
                    var arr = (uint[])param.Data;
                    writer.FixPadding(4);

                    writer.AddOffset("arrOffset");
                    writer.Write((uint)arr.Length);
                    writer.WriteNulls(4); // TODO: Figure out what this is.

                    // Data
                    writer.FillInOffset("arrOffset", false);

                    foreach (uint value in arr)
                    {
                        writer.Write(value);
                    }

                    continue;
                }
                else if (param.DataType == typeof(string))
                {
                    // Data Info
                    string str = (string)param.Data;
                    writer.AddOffset("strOffset");
                    writer.WriteNulls(4); // TODO: Figure out what this is.

                    if (string.IsNullOrEmpty(str))
                    {
                        writer.FillInOffset("strOffset", 0, true);
                    }
                    else
                    {
                        writer.FillInOffset("strOffset", false);
                        writer.WriteNullTerminatedString(str);
                    }

                    continue;
                }
                else if (param.DataType == typeof(float) ||
                         param.DataType == typeof(int) || param.DataType == typeof(uint))
                {
                    writer.FixPadding(4);
                }
                else if (type == SOBJType.LostWorld && param.DataType == typeof(Vector3))
                {
                    writer.FixPadding(16);
                }

                // Write Data
                writer.WriteByType(param.DataType, param.Data);
            }

            // Write remaining raw data from loaded ORC
            if (rawDataMode == false)
            {
                writer.Write(rawParamData);
            }
            else
            {
                int knownParamLength = (int)(writer.BaseStream.Position - paramBegin);
                writer.Write(rawParamData, knownParamLength,
                             rawParamData.Length - knownParamLength);
            }

            writer.FixPadding(4);
        }
Beispiel #13
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);
        }
Beispiel #14
0
        // Methods
        public static List <SetObject> Read(ExtendedBinaryReader reader,
                                            Dictionary <string, SetObjectType> objectTemplates, SOBJType type)
        {
            var objs = new List <SetObject>();

            // SOBJ Header
            var sig = reader.ReadChars(4);

            if (!reader.IsBigEndian)
            {
                Array.Reverse(sig);
            }

            string sigString = new string(sig);

            if (sigString != Signature)
            {
                throw new InvalidSignatureException(Signature, sigString);
            }

            uint unknown1             = reader.ReadUInt32();
            uint objTypeCount         = reader.ReadUInt32();
            uint objTypeOffsetsOffset = reader.ReadUInt32();

            reader.JumpAhead(4);
            uint objOffsetsOffset = reader.ReadUInt32();
            uint objCount         = reader.ReadUInt32();
            uint unknown2         = reader.ReadUInt32(); // Probably just padding

            if (unknown2 != 0)
            {
                Console.WriteLine("WARNING: Unknown2 != 0! ({0})", unknown2);
            }

            uint transformsCount = reader.ReadUInt32();

            // Object Offsets
            var objOffsets = new uint[objCount];

            reader.JumpTo(objOffsetsOffset, false);

            for (uint i = 0; i < objCount; ++i)
            {
                objOffsets[i] = reader.ReadUInt32();
                objs.Add(new SetObject());
            }

            // Object Types
            reader.JumpTo(objTypeOffsetsOffset, false);

            for (uint i = 0; i < objTypeCount; ++i)
            {
                // Object Type
                string objName          = reader.GetString();
                uint   objOfTypeCount   = reader.ReadUInt32();
                uint   objIndicesOffset = reader.ReadUInt32();
                long   curTypePos       = reader.BaseStream.Position;

                // Objects
                reader.JumpTo(objIndicesOffset, false);

                for (uint i2 = 0; i2 < objOfTypeCount; ++i2)
                {
                    ushort objIndex = reader.ReadUInt16();
                    long   curPos   = reader.BaseStream.Position;
                    var    obj      = new SetObject();

                    // We do this check here so we can print an offset that's actually helpful
                    if (!objectTemplates.ContainsKey(objName))
                    {
                        Console.WriteLine("{0} \"{1}\" (Offset: 0x{2:X})! Skipping this object...",
                                          "WARNING: No object template exists for object type",
                                          objName, (objOffsets[objIndex] + reader.Offset));

                        // Object Data without a template
                        reader.JumpTo(objOffsets[objIndex], false);
                        obj = ReadObject(reader,
                                         null, objName, type);
                    }
                    else
                    {
                        // Object Data with a template
                        reader.JumpTo(objOffsets[objIndex], false);
                        obj = ReadObject(reader,
                                         objectTemplates[objName], objName, type);
                    }

                    objs[objIndex]             = obj;
                    reader.BaseStream.Position = curPos;
                }

                reader.BaseStream.Position = curTypePos;
            }
            return(objs);
        }