public void WriteClassPointer <T>(BinaryWriterEx bw, T d) where T : IHavokObject { if (d == null) { bw.WriteUInt64(0); return; } // If we're referencing an already serialized object, add a global ref if (_globalLookup.ContainsKey(d)) { GlobalFixup gfu = new GlobalFixup(); gfu.Src = (uint)bw.Position; gfu.DstSectionIndex = 2; gfu.Dst = _globalLookup[d]; _globalFixups.Add(gfu); } // Otherwise need to add a pending reference and mark the object for serialization else { if (!_pendingGlobals.ContainsKey(d)) { _pendingGlobals.Add(d, new List <uint>()); PushSerializationQueue(); _serializationQueues[_currSerializationQueue].Enqueue(d); PopSerializationQueue(bw); _pendingVirtuals.Add(d); } _pendingGlobals[d].Add((uint)bw.Position); } bw.WriteUInt64(0); }
internal HKXSection(BinaryReaderEx br, HKXVariation variation) { SectionTag = br.ReadFixStr(19); br.AssertByte(0xFF); var AbsoluteDataStart = br.ReadUInt32(); var LocalFixupsOffset = br.ReadUInt32(); var GlobalFixupsOffset = br.ReadUInt32(); var VirtualFixupsOffset = br.ReadUInt32(); var ExportsOffset = br.ReadUInt32(); var ImportsOffset = br.ReadUInt32(); var EndOffset = br.ReadUInt32(); // Read Data br.StepIn(AbsoluteDataStart); SectionData = br.ReadBytes((int)LocalFixupsOffset); br.StepOut(); // Local fixups LocalFixups = new List <LocalFixup>(); br.StepIn(AbsoluteDataStart + LocalFixupsOffset); for (int i = 0; i < (GlobalFixupsOffset - LocalFixupsOffset) / 8; i++) { if (br.ReadUInt32() != 0xFFFFFFFF) { br.Position -= 4; var f = new LocalFixup(br); _localMap.Add(f.Src, f); LocalFixups.Add(f); } } br.StepOut(); // Global fixups GlobalFixups = new List <GlobalFixup>(); br.StepIn(AbsoluteDataStart + GlobalFixupsOffset); for (int i = 0; i < (VirtualFixupsOffset - GlobalFixupsOffset) / 12; i++) { if (br.ReadUInt32() != 0xFFFFFFFF) { br.Position -= 4; var f = new GlobalFixup(br); _globalMap.Add(f.Src, f); GlobalFixups.Add(f); } } br.StepOut(); // Virtual fixups VirtualFixups = new List <VirtualFixup>(); br.StepIn(AbsoluteDataStart + VirtualFixupsOffset); for (int i = 0; i < (ExportsOffset - VirtualFixupsOffset) / 12; i++) { if (br.ReadUInt32() != 0xFFFFFFFF) { br.Position -= 4; var f = new VirtualFixup(br); _virtualMap.Add(f.Src, f); VirtualFixups.Add(f); } } br.StepOut(); if (variation == HKXVariation.HKXBloodBorne || variation == HKXVariation.HKXDS3) { br.AssertUInt32(0xFFFFFFFF); br.AssertUInt32(0xFFFFFFFF); br.AssertUInt32(0xFFFFFFFF); br.AssertUInt32(0xFFFFFFFF); } }
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(); }