internal void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bw.WriteASCII("BDF4"); bw.WriteBoolean(Flag1); bw.WriteBoolean(Flag2); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(0x10000); bw.WriteInt32(0); bw.WriteInt64(Unk1); bw.WriteFixStr(Timestamp, 8); bw.WriteInt64(0); bw.WriteInt64(0); }
public void WriteHeader(BinaryWriterEx bw, HKX.HKXVariation variation) { bw.WriteFixStr(SectionTag, 19); bw.WriteByte(0xFF); bw.ReserveUInt32("absoffset" + SectionID); bw.ReserveUInt32("locoffset" + SectionID); bw.ReserveUInt32("globoffset" + SectionID); bw.ReserveUInt32("virtoffset" + SectionID); bw.ReserveUInt32("expoffset" + SectionID); bw.ReserveUInt32("impoffset" + SectionID); bw.ReserveUInt32("endoffset" + SectionID); if (variation == HKX.HKXVariation.HKXBloodBorne || variation == HKX.HKXVariation.HKXDS3) { bw.WriteUInt32(0xFFFFFFFF); bw.WriteUInt32(0xFFFFFFFF); bw.WriteUInt32(0xFFFFFFFF); bw.WriteUInt32(0xFFFFFFFF); } }
internal void Write(BinaryWriterEx bw, List <BinderFile> files) { bw.BigEndian = BigEndian; bw.WriteASCII("BHF4"); bw.WriteBoolean(Flag1); bw.WriteBoolean(Flag2); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(0x10000); bw.WriteInt32(files.Count); bw.WriteInt64(0x40); bw.WriteFixStr(Timestamp, 8); bw.WriteInt64(Binder.FileHeaderSize(Format)); bw.WriteInt64(0); bw.WriteBoolean(Unicode); bw.WriteByte((byte)Format); bw.WriteByte(Extended); bw.WriteByte(0); bw.WriteInt32(0); if (Extended == 4) { bw.ReserveInt64("HashGroups"); } else { bw.WriteInt64(0); } for (int i = 0; i < files.Count; i++) { FileHeader.Write(bw, files[i], i, Format); } for (int i = 0; i < files.Count; i++) { BinderFile file = files[i]; bw.FillUInt32($"FileName{i}", (uint)bw.Position); if (Unicode) { bw.WriteUTF16(file.Name, true); } else { bw.WriteShiftJIS(file.Name, true); } } if (Extended == 4) { uint groupCount = 0; for (uint p = (uint)files.Count / 7; p <= 100000; p++) { if (SFUtil.IsPrime(p)) { groupCount = p; break; } } if (groupCount == 0) { throw new InvalidOperationException("Hash group count not determined in BXF4."); } var hashLists = new List <PathHash> [groupCount]; for (int i = 0; i < groupCount; i++) { hashLists[i] = new List <PathHash>(); } for (int i = 0; i < files.Count; i++) { var pathHash = new PathHash(i, files[i].Name); uint group = pathHash.Hash % groupCount; hashLists[group].Add(pathHash); } for (int i = 0; i < groupCount; i++) { hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash)); } var hashGroups = new List <HashGroup>(); var pathHashes = new List <PathHash>(); int count = 0; foreach (List <PathHash> hashList in hashLists) { int index = count; foreach (PathHash pathHash in hashList) { pathHashes.Add(pathHash); count++; } hashGroups.Add(new HashGroup(index, count - index)); } bw.Pad(0x8); bw.FillInt64("HashGroups", bw.Position); bw.ReserveInt64("PathHashes"); bw.WriteUInt32(groupCount); bw.WriteInt32(0x00080810); foreach (HashGroup hashGroup in hashGroups) { hashGroup.Write(bw); } // No padding after section 1 bw.FillInt64("PathHashes", bw.Position); foreach (PathHash pathHash in pathHashes) { pathHash.Write(bw); } } }
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(); }