internal override void WriteTypeData(BinaryWriterEx bw) { bw.WriteInt64(UnkT00); bw.WriteNull(0x18, false); }
internal void WriteHeader(BinaryWriterEx bw, int i) { bw.WriteInt64(ID); bw.ReserveInt64($"RowOffset{i}"); bw.ReserveInt64($"NameOffset{i}"); }
internal override void WriteTypeData(BinaryWriterEx bw) { bw.WriteInt64(UnkT00); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { if (layout == null) { throw new InvalidOperationException("Params cannot be written without a layout."); } Rows.Sort((r1, r2) => r1.ID.CompareTo(r2.ID)); bw.BigEndian = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ID, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i, layout); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, i); } }
internal void WriteDefaultValue(BinaryWriterEx bw) { if (ValueToAssert != null) { WriteAssertValue(bw); } else if (DefaultValue == null) { switch (Type) { case ParamType.aob: for (int i = 0; i < AobLength; i++) { bw.WriteByte(0); } break; case ParamType.b: case ParamType.u8: case ParamType.x8: bw.WriteByte(0); break; case ParamType.s8: bw.WriteSByte(0); break; case ParamType.u16: case ParamType.x16: bw.WriteUInt16(0); break; case ParamType.s16: bw.WriteInt16(0); break; case ParamType.u32: case ParamType.x32: bw.WriteUInt32(0); break; case ParamType.s32: bw.WriteInt32(0); break; case ParamType.u64: case ParamType.x64: bw.WriteUInt64(0); break; case ParamType.s64: bw.WriteInt64(0); break; case ParamType.f32: bw.WriteSingle(0); break; case ParamType.f64: bw.WriteDouble(0); break; default: throw new Exception($"Invalid ParamTemplate ParamType: {Type.ToString()}"); } } else { switch (Type) { case ParamType.aob: var assertAob = (byte[])DefaultValue; bw.WriteBytes(assertAob); break; case ParamType.b: case ParamType.u8: case ParamType.x8: bw.WriteByte((byte)DefaultValue); break; case ParamType.s8: bw.WriteSByte((sbyte)DefaultValue); break; case ParamType.u16: case ParamType.x16: bw.WriteUInt16((ushort)DefaultValue); break; case ParamType.s16: bw.WriteInt16((short)DefaultValue); break; case ParamType.u32: case ParamType.x32: bw.WriteUInt32((uint)DefaultValue); break; case ParamType.s32: bw.WriteInt32((int)DefaultValue); break; case ParamType.u64: case ParamType.x64: bw.WriteUInt64((ulong)DefaultValue); break; case ParamType.s64: bw.WriteInt64((long)DefaultValue); break; case ParamType.f32: bw.WriteSingle((float)DefaultValue); break; case ParamType.f64: bw.WriteDouble((double)DefaultValue); break; default: throw new Exception($"Invalid ParamTemplate ParamType: {Type.ToString()}"); } } }
internal void WriteHeader(BinaryWriterEx bw, int i) { bw.WriteInt64(ID); bw.ReserveInt64($"AnimationOffset{i}"); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { if (AppliedParamdef == null) { throw new InvalidOperationException("Params cannot be written without applying a paramdef."); } bw.BigEndian = BigEndian; void WriteFormat() { bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte(Format2D); bw.WriteByte(Format2E); bw.WriteByte(Format2F); } // DeS, DS1 if ((Format2D & 0x7F) < 3) { bw.ReserveUInt32("StringsOffset"); bw.ReserveUInt16("DataStart"); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, (byte)((Format2D & 0x7F) < 2 ? 0x20 : 0x00)); WriteFormat(); } // DS2 else if ((Format2D & 0x7F) == 3) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x20); WriteFormat(); bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } // SotFS, BB else if ((Format2D & 0x7F) == 4) { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteFixStr(ParamType, 0x20, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } // DS3, SDT else { bw.ReserveUInt32("StringsOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk06); bw.WriteInt16(Unk08); bw.WriteUInt16((ushort)Rows.Count); bw.WriteInt32(0); bw.ReserveInt64("IDOffset"); bw.WritePattern(0x14, 0x00); WriteFormat(); bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, Format2D, i); } if ((Format2D & 0x7F) < 2) { bw.WritePattern(0x20, 0x00); } if ((Format2D & 0x7F) < 3) { bw.FillUInt16("DataStart", (ushort)bw.Position); } else if ((Format2D & 0x7F) == 3) { bw.FillUInt32("DataStart", (uint)bw.Position); } else { bw.FillInt64("DataStart", bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, Format2D, i); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if ((Format2D & 0x7F) > 4) { bw.FillInt64("IDOffset", bw.Position); bw.WriteASCII(ParamType, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, Format2D, Format2E, i); } // DeS and BB sometimes (but not always) include some useless padding here }
internal void Write(BinaryWriterEx bw) { bw.WriteInt64(StartOffset); bw.WriteInt64(EndOffset); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bool wide = Version == FMGVersion.DarkSouls3; bw.WriteByte(0); bw.WriteBoolean(bw.BigEndian); bw.WriteByte((byte)Version); bw.WriteByte(0); bw.ReserveInt32("FileSize"); bw.WriteByte(1); bw.WriteByte((byte)(Version == FMGVersion.DemonsSouls ? 0xFF : 0x00)); bw.WriteByte(0); bw.WriteByte(0); bw.ReserveInt32("GroupCount"); bw.WriteInt32(Entries.Count); if (wide) { bw.WriteInt32(0xFF); } if (wide) { bw.ReserveInt64("StringOffsets"); } else { bw.ReserveInt32("StringOffsets"); } if (wide) { bw.WriteInt64(0); } else { bw.WriteInt32(0); } int groupCount = 0; Entries.Sort((e1, e2) => e1.ID.CompareTo(e2.ID)); for (int i = 0; i < Entries.Count; i++) { bw.WriteInt32(i); bw.WriteInt32(Entries[i].ID); while (i < Entries.Count - 1 && Entries[i + 1].ID == Entries[i].ID + 1) { i++; } bw.WriteInt32(Entries[i].ID); if (wide) { bw.WriteInt32(0); } groupCount++; } bw.FillInt32("GroupCount", groupCount); if (wide) { bw.FillInt64("StringOffsets", bw.Position); } else { bw.FillInt32("StringOffsets", (int)bw.Position); } for (int i = 0; i < Entries.Count; i++) { if (wide) { bw.ReserveInt64($"StringOffset{i}"); } else { bw.ReserveInt32($"StringOffset{i}"); } } for (int i = 0; i < Entries.Count; i++) { string text = Entries[i].Text; if (wide) { bw.FillInt64($"StringOffset{i}", text == null ? 0 : bw.Position); } else { bw.FillInt32($"StringOffset{i}", text == null ? 0 : (int)bw.Position); } if (text != null) { bw.WriteUTF16(Entries[i].Text, true); } } bw.FillInt32("FileSize", (int)bw.Position); }
internal void Write(BinaryWriterEx bw, long nameOffset, int version, bool longOffsets) { bw.WriteUInt32(Unk00); bw.WriteUInt32(Unk04); bw.WriteUInt32(Unk08); bw.WriteUInt32(Unk0C); if (longOffsets) { bw.WriteInt64(nameOffset); } else { bw.WriteInt32((int)nameOffset); } bw.WriteUInt32((uint)Type); bw.WriteBoolean(Unk1C); bw.WriteByte(DiffuseColor.R); bw.WriteByte(DiffuseColor.G); bw.WriteByte(DiffuseColor.B); bw.WriteSingle(DiffusePower); bw.WriteByte(SpecularColor.R); bw.WriteByte(SpecularColor.G); bw.WriteByte(SpecularColor.B); bw.WriteBoolean(CastShadows); bw.WriteSingle(SpecularPower); bw.WriteSingle(ConeAngle); bw.WriteSingle(Unk30); bw.WriteSingle(Unk34); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteInt32(Unk50); bw.WriteSingle(Unk54); bw.WriteSingle(Radius); bw.WriteInt32(Unk5C); bw.WriteInt32(0); bw.WriteBytes(Unk64); bw.WriteSingle(Unk68); bw.WriteByte(ShadowColor.R); bw.WriteByte(ShadowColor.G); bw.WriteByte(ShadowColor.B); bw.WriteByte(ShadowColor.A); bw.WriteSingle(Unk70); bw.WriteSingle(FlickerIntervalMin); bw.WriteSingle(FlickerIntervalMax); bw.WriteSingle(FlickerBrightnessMult); bw.WriteInt32(Unk80); bw.WriteBytes(Unk84); bw.WriteSingle(Unk88); bw.WriteInt32(0); bw.WriteSingle(Unk90); bw.WriteInt32(0); bw.WriteSingle(Unk98); bw.WriteSingle(NearClip); bw.WriteBytes(UnkA0); bw.WriteSingle(Sharpness); bw.WriteInt32(0); bw.WriteSingle(UnkAC); if (longOffsets) { bw.WriteInt64(0); } else { bw.WriteInt32(0); } bw.WriteSingle(Width); bw.WriteSingle(UnkBC); bw.WriteBytes(UnkC0); bw.WriteSingle(UnkC4); if (version >= 16) { bw.WriteSingle(UnkC8); bw.WriteSingle(UnkCC); bw.WriteSingle(UnkD0); bw.WriteSingle(UnkD4); bw.WriteSingle(UnkD8); bw.WriteInt32(UnkDC); bw.WriteSingle(UnkE0); bw.WriteInt32(0); } }
/// <summary> /// Writes BND4 data to a BinaryWriterEx. /// </summary> internal override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bw.WriteASCII("BND4"); 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.ReserveInt64("DataStart"); 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++) { WriteFile(Files[i], bw, i, Format); } if (Binder.HasName(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 BND4."); } 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); } } bw.FillInt64("DataStart", bw.Position); for (int i = 0; i < Files.Count; i++) { BinderFile file = Files[i]; if (file.Bytes.LongLength > 0) { bw.Pad(0x10); } bw.FillUInt32($"FileData{i}", (uint)bw.Position); int compressedSize = file.Bytes.Length; if (Binder.IsCompressed(file.Flags)) { if (Format == Binder.Format.x2E) { byte[] bytes = DCX.Compress(file.Bytes, DCX.Type.DemonsSoulsEDGE); bw.WriteBytes(bytes); compressedSize = bytes.Length; } else { compressedSize = SFUtil.WriteZlib(bw, 0x9C, file.Bytes); } } else { bw.WriteBytes(file.Bytes); } bw.FillInt64($"CompressedSize{i}", compressedSize); } }
// Writes a placeholder in the source object and updates the local offset public void WritePlaceholder(BinaryWriterEx bw, uint sectionBaseOffset) { SourceLocalOffset = (uint)bw.Position - SourceObject.SectionOffset - sectionBaseOffset; bw.WriteInt64(sectionBaseOffset); }
internal override void WriteTypeData(BinaryWriterEx bw) { bw.WriteInt64(UnkT00); bw.WritePattern(0x18, 0x00); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bw.ReserveInt32("FileSize"); bw.WriteInt16((short)(Version >= 201 ? 0xFF : 0x30)); bw.WriteInt16(Unk06); bw.WriteInt16((short)Fields.Count); if (Version == 101) { bw.WriteInt16(0x8C); } else if (Version == 102) { bw.WriteInt16(0xAC); } else if (Version == 103) { bw.WriteInt16(0x6C); } else if (Version == 104) { bw.WriteInt16(0xB0); } else if (Version == 201) { bw.WriteInt16(0xD0); } bw.WriteFixStr(ParamType, 0x20, (byte)(Version >= 201 ? 0x00 : 0x20)); bw.WriteSByte((sbyte)(BigEndian ? -1 : 0)); bw.WriteBoolean(Unicode); bw.WriteInt16(Version); if (Version >= 201) { bw.WriteInt64(0x38); } for (int i = 0; i < Fields.Count; i++) { Fields[i].Write(bw, this, i); } long descriptionsStart = bw.Position; for (int i = 0; i < Fields.Count; i++) { Fields[i].WriteDescription(bw, this, i); } if (Version >= 104) { long descriptionsLength = bw.Position - descriptionsStart; if (descriptionsLength % 0x10 != 0) { bw.WritePattern((int)(0x10 - descriptionsLength % 0x10), 0x00); } } else { bw.Pad(0x10); } bw.FillInt32("FileSize", (int)bw.Position); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { if (AppliedParamdef == null) { throw new InvalidOperationException("Params cannot be written without applying a paramdef."); } bw.BigEndian = BigEndian; bw.ReserveUInt32("StringsOffset"); if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset) || Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.WriteInt16(0); } else { bw.ReserveUInt16("DataStart"); } bw.WriteInt16(Unk06); bw.WriteInt16(ParamdefDataVersion); bw.WriteUInt16((ushort)Rows.Count); if (Format2D.HasFlag(FormatFlags1.OffsetParamType)) { bw.WriteInt32(0); bw.ReserveInt64("ParamTypeOffset"); bw.WritePattern(0x14, 0x00); } else { // This padding heuristic isn't completely accurate, not that it matters bw.WriteFixStr(ParamType, 0x20, (byte)(Format2D.HasFlag(FormatFlags1.Flag01) ? 0x20 : 0x00)); } bw.WriteByte((byte)(BigEndian ? 0xFF : 0x00)); bw.WriteByte((byte)Format2D); bw.WriteByte((byte)Format2E); bw.WriteByte(ParamdefFormatVersion); if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset)) { bw.ReserveUInt32("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } else if (Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.ReserveInt64("DataStart"); bw.WriteInt64(0); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, this, i); } // This is probably pretty stupid if (Format2D == FormatFlags1.Flag01) { bw.WritePattern(0x20, 0x00); } if (Format2D.HasFlag(FormatFlags1.Flag01) && Format2D.HasFlag(FormatFlags1.IntDataOffset)) { bw.FillUInt32("DataStart", (uint)bw.Position); } else if (Format2D.HasFlag(FormatFlags1.LongDataOffset)) { bw.FillInt64("DataStart", bw.Position); } else { bw.FillUInt16("DataStart", (ushort)bw.Position); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, this, i); } bw.FillUInt32("StringsOffset", (uint)bw.Position); if (Format2D.HasFlag(FormatFlags1.OffsetParamType)) { bw.FillInt64("ParamTypeOffset", bw.Position); bw.WriteASCII(ParamType, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, this, i); } // DeS and BB sometimes (but not always) include some useless padding here }
internal void Write(BinaryWriterEx bw, NGPVersion version) { long start = bw.Position; bw.WriteInt32(Unk00); bw.ReserveInt32("MeshLength"); bw.WriteInt32(Unk08); if (version == NGPVersion.Scholar) { bw.WriteInt32(0); } bw.WriteVector3(BoundingBoxMin); bw.WriteVector3(BoundingBoxMax); bw.WriteInt32(Vertices.Count); bw.WriteInt16((short)Faces.Count); bw.WriteInt16((short)Struct4s.Count); bw.WriteInt16(Unk30); bw.WriteInt16(Unk32); bw.WriteByte(1); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0); if (version == NGPVersion.Scholar) { bw.WriteInt64(0); } bw.ReserveVarint("VerticesOffset"); bw.ReserveVarint("Struct2sOffset"); bw.ReserveVarint("FacesOffset"); bw.ReserveVarint("Struct4sOffset"); bw.ReserveVarint("Struct5sOffset"); bw.ReserveVarint("Struct6sOffset"); bw.FillVarint("VerticesOffset", bw.Position); foreach (Vector3 vertex in Vertices) { bw.WriteVector3(vertex); } bw.Pad(bw.VarintSize); bw.FillVarint("Struct2sOffset", bw.Position); foreach (int struct2 in Struct2s) { bw.WriteInt32(struct2); } bw.Pad(bw.VarintSize); bw.FillVarint("FacesOffset", bw.Position); foreach (Face face in Faces) { face.Write(bw); } bw.Pad(bw.VarintSize); bw.FillVarint("Struct4sOffset", bw.Position); foreach (Struct4 struct4 in Struct4s) { struct4.Write(bw); } bw.Pad(bw.VarintSize); bw.FillVarint("Struct5sOffset", bw.Position); short index = 0; Struct5Root.Write(bw, ref index); bw.Pad(bw.VarintSize); bw.FillVarint("Struct6sOffset", bw.Position); index = 0; int faceIndexIndex = 0; Struct5Root.WriteFaceIndices(bw, ref index, ref faceIndexIndex); bw.Pad(bw.VarintSize); bw.FillInt32("MeshLength", (int)(bw.Position - start)); }
internal override void Write(BinaryWriterEx bw) { bw.WriteASCII("TAE "); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0xFF); bw.WriteInt32(0x1000D); bw.ReserveInt32("FileSize"); bw.WriteInt64(0x40); bw.WriteInt64(1); bw.WriteInt64(0x50); bw.WriteInt64(0x80); bw.WriteInt64(Unk30); bw.WriteInt64(0); bw.WriteBytes(Flags); bw.WriteInt64(1); bw.WriteInt32(ID); bw.WriteInt32(Animations.Count); bw.ReserveInt64("AnimsOffset"); bw.ReserveInt64("AnimGroupsOffset"); bw.WriteInt64(0xA0); bw.WriteInt64(Animations.Count); bw.ReserveInt64("FirstAnimOffset"); bw.WriteInt64(1); bw.WriteInt64(0x90); bw.WriteInt32(ID); bw.WriteInt32(ID); bw.WriteInt64(0x50); bw.WriteInt64(0); bw.WriteInt64(0xB0); bw.ReserveInt64("SkeletonName"); bw.ReserveInt64("SibName"); bw.WriteInt64(0); bw.WriteInt64(0); bw.FillInt64("SkeletonName", bw.Position); bw.WriteUTF16(SkeletonName, true); bw.Pad(0x10); bw.FillInt64("SibName", bw.Position); bw.WriteUTF16(SibName, true); bw.Pad(0x10); Animations.Sort((a1, a2) => a1.ID.CompareTo(a2.ID)); bw.FillInt64("AnimsOffset", bw.Position); var animOffsets = new List <long>(Animations.Count); for (int i = 0; i < Animations.Count; i++) { animOffsets.Add(bw.Position); Animations[i].WriteHeader(bw, i); } bw.FillInt64("AnimGroupsOffset", bw.Position); bw.ReserveInt64("AnimGroupsCount"); bw.ReserveInt64("AnimGroupsOffset"); int groupCount = 0; long groupStart = bw.Position; for (int i = 0; i < Animations.Count; i++) { int firstIndex = i; bw.WriteInt32((int)Animations[i].ID); while (i < Animations.Count - 1 && Animations[i + 1].ID == Animations[i].ID + 1) { i++; } bw.WriteInt32((int)Animations[i].ID); bw.WriteInt64(animOffsets[firstIndex]); groupCount++; } bw.FillInt64("AnimGroupsCount", groupCount); if (groupCount == 0) { bw.FillInt64("AnimGroupsOffset", 0); } else { bw.FillInt64("AnimGroupsOffset", groupStart); } bw.FillInt64("FirstAnimOffset", bw.Position); for (int i = 0; i < Animations.Count; i++) { Animations[i].WriteBody(bw, i); } for (int i = 0; i < Animations.Count; i++) { Animations[i].WriteAnimFile(bw, i); long timeStart = bw.Position; Animations[i].WriteTimes(bw, i); var eventHeaderOffsets = Animations[i].WriteEventHeaders(bw, i, timeStart); Animations[i].WriteEventData(bw, i); Animations[i].WriteEventGroupHeaders(bw, i); Animations[i].WriteEventGroupData(bw, i, eventHeaderOffsets); } bw.FillInt32("FileSize", (int)bw.Position); }
internal void Write(BinaryWriterEx bw, List <File> 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.WriteASCII(Timestamp.PadRight(8, '\0')); if (Format == 0x0C || Format == 0x30) { bw.WriteInt64(0x18); } else if (Format == 0x2E || Format == 0x74) { bw.WriteInt64(0x24); } else if (Format == 0x3E) { bw.WriteInt64(0x28); } bw.WriteInt64(0); bw.WriteBoolean(Unicode); bw.WriteByte(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++) { File file = files[i]; bw.FillInt32($"FileName{i}", (int)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 (Util.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); } } }
internal void Write(BinaryWriterEx bw) { bw.WriteInt64(Unk1); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bw.ReserveInt32("FileSize"); bw.WriteInt16((short)(FormatVersion >= 200 ? 0xFF : 0x30)); bw.WriteInt16(DataVersion); bw.WriteInt16((short)Fields.Count); if (FormatVersion == 101) { bw.WriteInt16(0x8C); } else if (FormatVersion == 102) { bw.WriteInt16(0xAC); } else if (FormatVersion == 103) { bw.WriteInt16(0x6C); } else if (FormatVersion == 104) { bw.WriteInt16(0xB0); } else if (FormatVersion == 201) { bw.WriteInt16(0xD0); } else if (FormatVersion == 202) { bw.WriteInt16(0x68); } if (FormatVersion >= 202) { bw.WriteInt32(0); bw.ReserveInt64("ParamTypeOffset"); bw.WriteInt64(0); bw.WriteInt64(0); bw.WriteInt32(0); } else { bw.WriteFixStr(ParamType, 0x20, (byte)(FormatVersion >= 200 ? 0x00 : 0x20)); } bw.WriteSByte((sbyte)(BigEndian ? -1 : 0)); bw.WriteBoolean(Unicode); bw.WriteInt16(FormatVersion); if (FormatVersion >= 200) { bw.WriteInt64(0x38); } for (int i = 0; i < Fields.Count; i++) { Fields[i].Write(bw, this, i); } if (FormatVersion >= 202) { bw.FillInt64("ParamTypeOffset", bw.Position); bw.WriteShiftJIS(ParamType, true); } long fieldStringsStart = bw.Position; var sharedStringOffsets = new Dictionary <string, long>(); for (int i = 0; i < Fields.Count; i++) { Fields[i].WriteStrings(bw, this, i, sharedStringOffsets); } if (FormatVersion >= 104 && FormatVersion < 202) { long fieldStringsLength = bw.Position - fieldStringsStart; if (fieldStringsLength % 0x10 != 0) { bw.WritePattern((int)(0x10 - fieldStringsLength % 0x10), 0x00); } } else { if (FormatVersion >= 202 && bw.Position % 0x10 == 0) { bw.WritePattern(0x10, 0x00); } bw.Pad(0x10); } bw.FillInt32("FileSize", (int)bw.Position); }