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);
        }
        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);
                }
            }
        }
        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;
                }
            }
        }
Esempio n. 5
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);
        }