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; } } }
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); }