public override void Save(Stream fileStream) { // Header var writer = new BINAWriter(fileStream, Header); writer.Write(0UL); writer.Write(0UL); writer.AddOffset("objectTableOffset", 8); writer.Write((ulong)Objects.Count); writer.Write((ulong)Objects.Count); writer.Write(0UL); // Objects writer.FillInOffsetLong("objectTableOffset", false, false); writer.AddOffsetTable("objectOffset", (uint)Objects.Count, 8); writer.FixPadding(16); for (int i = 0; i < Objects.Count; ++i) { var obj = Objects[i]; writer.FillInOffsetLong($"objectOffset_{i}", false, false); WriteObject(writer, obj, i); } writer.FixPadding(16); // Object Parameters for (int i = 0; i < Objects.Count; ++i) { writer.FixPadding(16); WriteObjectParameters(writer, Objects[i], i); } writer.FinishWrite(Header); }
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); } } }
public static void Write(BINAWriter writer, List <SetObject> objects, SOBJType type) { // Get some data we need to write the file var objectsByType = new Dictionary <string, List <int> >(); uint transformCount = 0, objTypeCount = 0; for (int objIndex = 0; objIndex < objects.Count; ++objIndex) { var obj = objects[objIndex]; if (!objectsByType.ContainsKey(obj.ObjectType)) { objectsByType.Add(obj.ObjectType, new List <int>() { objIndex }); ++objTypeCount; } else { objectsByType[obj.ObjectType].Add(objIndex); } transformCount += (uint)obj.Children.Length + 1; } // SOBJ Header var sig = Signature.ToCharArray(); if (!writer.IsBigEndian) { Array.Reverse(sig); } writer.Write(sig); writer.Write(1u); // TODO: Figure out what this value is. writer.Write(objTypeCount); writer.AddOffset("objTypeOffsetsOffset"); writer.Write((type == SOBJType.LostWorld) ? 0 : 0xFFFFFFFF); // I doubt this matters at all tbh. writer.AddOffset("objOffsetsOffset"); writer.Write(objects.Count); writer.WriteNulls(4); writer.Write(transformCount); // Object Offsets writer.FillInOffset("objOffsetsOffset", false); writer.AddOffsetTable("objOffset", (uint)objects.Count); // Object Types uint i = 0; writer.FillInOffset("objTypeOffsetsOffset", false); foreach (var obj in objectsByType) { writer.AddString($"objName_{i}", obj.Key); writer.Write((uint)obj.Value.Count); writer.AddOffset($"objIndicesOffset_{i}"); ++i; } // Object Indices ushort i2 = 0; i = 0; foreach (var obj in objectsByType) { writer.FillInOffset($"objIndicesOffset_{i}", false); for (int i3 = 0; i3 < obj.Value.Count; ++i3) { writer.Write(i2); ++i2; } ++i; } // Objects writer.FixPadding(4); i = 0; foreach (var objType in objectsByType) { foreach (int objIndex in objType.Value) { writer.FillInOffset($"objOffset_{i}", false); WriteObject(writer, objects[objIndex], type); writer.FixPadding(0x4); ++i; } } // TODO: Clean this up writer.FixPadding(4); foreach (var objType in objectsByType) { foreach (int objIndex in objType.Value) { // Transforms writer.FixPadding(0x4); writer.FillInOffset($"transformsOffset_{objects[objIndex].ObjectID}", false); WriteTransform(writer, objects[objIndex].Transform, type == SOBJType.LostWorld); foreach (var childTransform in objects[objIndex].Children) { WriteTransform(writer, childTransform, type == SOBJType.LostWorld); } } } }