public override void Save(Stream fileStream) { if (Objects.Count > HeroesObjectLimit) { throw new Exception("Heroes set data is limited to 2048 objects!"); } // Object Entries var writer = new ExtendedBinaryWriter(fileStream, Encoding.ASCII, true); byte objList, objType; // Defined here so we can re-use them. for (ushort i = 0; i < HeroesObjectLimit; ++i) { // If we have less than 2048 objects, write the other null entries. // (Yes the Heroes set data format requires us to do this... awful design, huh?) if (i >= Objects.Count) { writer.WriteNulls((uint) (HeroesObjectLimit - Objects.Count) * MainEntryLength); break; } // Check if object type is valid var obj = Objects[i]; string type1 = obj.ObjectType.Substring(0, 2), type2 = obj.ObjectType.Substring(3, 2); if (obj.ObjectType.Length != 5 || !byte.TryParse(type1, NumberStyles.HexNumber, null, out objList) || !byte.TryParse(type2, NumberStyles.HexNumber, null, out objType)) { Console.WriteLine("WARNING: Object #{0} {1} ({2})!", i, "was skipped, invalid Heroes obj type", obj.ObjectType); writer.WriteNulls(MainEntryLength); continue; } // Write object entries var rot = obj.Transform.Rotation.ToEulerAngles(false); writer.Write(obj.Transform.Position); writer.Write((int)(rot.X * 32768.0 / 180.0)); writer.Write((int)(rot.Y * 32768.0 / 180.0)); writer.Write((int)(rot.Z * 32768.0 / 180.0)); // Yeah in the actual game the same thing is just written twice for some reason byte stageType = obj.GetCustomDataValue <byte>("StageType"); writer.Write((ushort)2); writer.Write(stageType); writer.Write((byte)9); // unknown 2 writer.Write(0u); // unknown 3 writer.Write((ushort)2); writer.Write(stageType); writer.Write((byte)9); // unknown 2 writer.Write(0u); // unknown 3 writer.Write(objList); writer.Write(objType); writer.Write(obj.GetCustomDataValue <byte>("LinkID")); writer.Write((obj.CustomData.ContainsKey("RenderDistance")) ? (byte)obj.CustomData["RenderDistance"].Data : (byte)20); writer.Write((ushort)0); // unknown 5 writer.Write((ushort)(i + 1)); } // Object Parameters writer.WriteNulls(MiscEntryLength); // The first entry has to be null because screw me for (ushort i = 0; i < Objects.Count; ++i) { var obj = Objects[i]; long pos = writer.BaseStream.Position; writer.Write((ushort)0x0100); writer.Write((ushort)(i + 1)); foreach (var param in obj.Parameters) { writer.WriteByType(param.DataType, param.Data); } // Pad-out the entry to make sure it's 0x24 bytes writer.WriteNulls(MiscEntryLength - (uint)(writer.BaseStream.Position - pos)); } }