public void Read(PackFileDeserializer hkx, HKXSection section, BinaryReaderEx br, HKX.HKXVariation variation) { ClassNames = new List <HKXClassName>(); OffsetClassNamesMap = new Dictionary <uint, HKXClassName>(); while (br.ReadByte() != 0xFF) { br.Position -= 1; uint stringStart = (uint)br.Position + 5; var className = new HKXClassName(br); ClassNames.Add(className); OffsetClassNamesMap.Add(stringStart, className); if (br.Position == br.Length) { break; } } }
public void Serialize(IHavokObject rootObject, BinaryWriterEx bw) { // Hardcoded for DS3 for now bw.BigEndian = false; bw.WriteUInt32(0x57E0E057); // magic 1 bw.WriteUInt32(0x10C0C010); // magic 2 bw.WriteInt32(0); // User tag bw.WriteInt32(0x0B); // DS3 havok bw.WriteByte(8); // Pointer size bw.WriteByte(1); // Little endian bw.WriteByte(0); // Padding option bw.WriteByte(1); // Base class? bw.WriteInt32(3); // Always 3 sections // Hardcoded content stuff for now? bw.WriteInt32(2); // Content section index bw.WriteInt32(0); // Content section offset bw.WriteInt32(0); // Content class name section index bw.WriteInt32(0x4B); // Content class name section offset bw.WriteFixStr("hk_2014.1.0-r1", 16, 0xFF); // Version string bw.WriteInt32(0); // Flags bw.WriteInt16(21); // Unk bw.WriteInt16(16); // section offset bw.WriteInt32(20); // Unk bw.WriteInt32(0); // Unk bw.WriteInt32(0); // Unk bw.WriteInt32(0); // Unk // Initialize bookkeeping structures //_serializationQueue = new Queue<IHavokObject>(); //_serializationQueue.Enqueue(rootObject); _serializationQueues = new List <Queue <IHavokObject> >(); _serializationQueues.Add(new Queue <IHavokObject>()); _serializationQueues[0].Enqueue(rootObject); _serializedObjects = new HashSet <IHavokObject>(); _pendingVirtuals = new HashSet <IHavokObject>(); _pendingVirtuals.Add(rootObject); _virtualTableLookup = new Dictionary <string, uint>(); _virtualFixups = new List <VirtualFixup>(); _localWriteQueues = new List <Queue <Action> >(); _localWriteQueues.Add(new Queue <Action>()); _localFixups = new List <LocalFixup>(); // Memory stream for writing all the class definitions MemoryStream classms = new MemoryStream(); BinaryWriterEx classbw = new BinaryWriterEx(false, classms); // Data memory stream for havok objects MemoryStream datams = new MemoryStream(); BinaryWriterEx databw = new BinaryWriterEx(false, datams); // Populate class names with some stuff havok always has HKXClassName hkclass = new HKXClassName(); hkclass.ClassName = "hkClass"; hkclass.Signature = 0x33D42383; hkclass.Write(classbw); hkclass.ClassName = "hkClassMember"; hkclass.Signature = 0xB0EFA719; hkclass.Write(classbw); hkclass.ClassName = "hkClassEnum"; hkclass.Signature = 0x8A3609CF; hkclass.Write(classbw); hkclass.ClassName = "hkClassEnumItem"; hkclass.Signature = 0xCe6F8A6C; hkclass.Write(classbw); while (_serializationQueues.Count > 1 || _serializationQueues[0].Count > 0) { var sq = _serializationQueues.Last(); while (sq != null && sq.Count() == 0 && _serializationQueues.Count > 1) { if (_serializationQueues.Count > 1) { _serializationQueues.RemoveAt(_serializationQueues.Count - 1); } sq = _serializationQueues.Last(); } if (sq.Count == 0) { continue; } var obj = sq.Dequeue(); _currSerializationQueue = _serializationQueues.Count - 1; if (_serializedObjects.Contains(obj)) { continue; } // See if we need to add virtual bookkeeping if (_pendingVirtuals.Contains(obj)) { _pendingVirtuals.Remove(obj); var classname = obj.GetType().Name; if (!_virtualTableLookup.ContainsKey(classname)) { // Need to create a new class name entry and record the position HKXClassName cname = new HKXClassName(); cname.ClassName = classname; cname.Signature = obj.Signature; uint offset = (uint)classbw.Position; cname.Write(classbw); _virtualTableLookup.Add(classname, offset + 5); } // Create a new Virtual fixup for this object var vfu = new VirtualFixup(); vfu.Src = (uint)databw.Position; vfu.SectionIndex = 0; vfu.NameOffset = _virtualTableLookup[classname]; _virtualFixups.Add(vfu); // See if we have any pending global references to this object if (_pendingGlobals.ContainsKey(obj)) { // If so, create all the needed global fixups foreach (var src in _pendingGlobals[obj]) { var gfu = new GlobalFixup(); gfu.Src = src; gfu.Dst = (uint)databw.Position; gfu.DstSectionIndex = 2; _globalFixups.Add(gfu); } _pendingGlobals.Remove(obj); } // Add global lookup _globalLookup.Add(obj, (uint)databw.Position); } obj.Write(this, databw); _serializedObjects.Add(obj); databw.Pad(16); // Write local data (such as array contents and strings) while (_localWriteQueues.Count > 1 || _localWriteQueues[0].Count > 0) { var q = _localWriteQueues.Last(); while (q != null && q.Count() == 0 && _localWriteQueues.Count > 1) { if (_localWriteQueues.Count > 1) { _localWriteQueues.RemoveAt(_localWriteQueues.Count - 1); } q = _localWriteQueues.Last(); // Do alignment at the popping of a queue frame databw.Pad(16); } if (q.Count == 0) { continue; } var act = q.Dequeue(); _currWriteQueue = _localWriteQueues.Count - 1; act.Invoke(); } databw.Pad(16); } HKXSection classNames = new HKXSection(); classNames.SectionID = 0; classNames.SectionTag = "__classnames__"; classNames.SectionData = classms.ToArray(); classNames.WriteHeader(bw, HKX.HKXVariation.HKXDS3); HKXSection types = new HKXSection(); types.SectionID = 1; types.SectionTag = "__types__"; types.SectionData = new byte[0]; types.WriteHeader(bw, HKX.HKXVariation.HKXDS3); HKXSection data = new HKXSection(); data.SectionID = 2; data.SectionTag = "__data__"; data.SectionData = datams.ToArray(); data.VirtualFixups = _virtualFixups; data.GlobalFixups = _globalFixups.OrderBy((x) => x.Src).ToList(); data.LocalFixups = _localFixups.OrderBy((x) => x.Dst).ToList(); data.WriteHeader(bw, HKX.HKXVariation.HKXDS3); classNames.WriteData(bw); types.WriteData(bw); data.WriteData(bw); classms.Close(); datams.Close(); }