internal void Write(BinaryWriterEx bw) { long start = bw.Position; bw.ReserveInt64("NameOffset"); bw.WriteUInt32((uint)Type); bw.WriteInt32(ID); bw.WriteInt32(modelIndex); bw.WriteInt32(0); bw.ReserveInt64("PlaceholderOffset"); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteVector3(Scale); bw.WriteUInt32(DrawGroup1); bw.WriteUInt32(DrawGroup2); bw.WriteUInt32(DrawGroup3); bw.WriteUInt32(DrawGroup4); bw.WriteUInt32(DispGroup1); bw.WriteUInt32(DispGroup2); bw.WriteUInt32(DispGroup3); bw.WriteUInt32(DispGroup4); bw.WriteInt32(UnkF01); bw.WriteInt32(UnkF02); bw.WriteInt32(UnkF03); bw.WriteInt32(UnkF04); bw.WriteInt32(UnkF05); bw.WriteInt32(UnkF06); bw.WriteInt32(UnkF07); bw.WriteInt32(UnkF08); bw.WriteInt32(UnkF09); bw.WriteInt32(UnkF10); bw.WriteInt32(UnkF11); bw.WriteInt32(UnkF12); bw.WriteInt32(UnkF13); bw.WriteInt32(UnkF14); bw.WriteInt32(UnkF15); bw.WriteInt32(UnkF16); bw.WriteInt32(UnkF17); bw.WriteInt32(UnkF18); bw.WriteInt32(0); bw.ReserveInt64("BaseDataOffset"); bw.ReserveInt64("TypeDataOffset"); bw.ReserveInt64("UnkOffset1"); bw.ReserveInt64("UnkOffset2"); bw.FillInt64("NameOffset", bw.Position - start); bw.WriteUTF16(Name, true); if (Placeholder == null) { bw.FillInt64("PlaceholderOffset", 0); } else { bw.FillInt64("PlaceholderOffset", bw.Position - start); bw.WriteUTF16(Placeholder, true); } bw.Pad(8); bw.FillInt64("BaseDataOffset", bw.Position - start); bw.WriteInt32(EventEntityID); bw.WriteSByte(LightID); bw.WriteSByte(FogID); bw.WriteSByte(ScatterID); bw.WriteSByte(LensFlareID); bw.WriteInt32(0); bw.WriteSByte(LanternID); bw.WriteSByte(LodParamID); bw.WriteSByte(UnkB0E); bw.WriteBoolean(IsShadowDest); bw.WriteBoolean(IsShadowOnly); bw.WriteBoolean(DrawByReflectCam); bw.WriteBoolean(DrawOnlyReflectCam); bw.WriteBoolean(UseDepthBiasFloat); bw.WriteBoolean(DisablePointLightEffect); bw.WriteByte(UnkB15); bw.WriteByte(UnkB16); bw.WriteByte(UnkB17); bw.WriteInt32(UnkB18); bw.WriteInt32(UnkB1C); bw.WriteInt32(UnkB20); bw.WriteInt32(UnkB24); bw.WriteInt32(UnkB28); bw.WriteInt32(-1); bw.WriteInt32(UnkB30); bw.WriteInt32(UnkB34); bw.WriteInt32(UnkB38); bw.WriteInt32(0); bw.FillInt64("TypeDataOffset", bw.Position - start); if (UnkOffset1Delta == 0) { bw.FillInt64("UnkOffset1", 0); } else { bw.FillInt64("UnkOffset1", bw.Position - start + UnkOffset1Delta); } if (UnkOffset2Delta == 0) { bw.FillInt64("UnkOffset2", 0); } else { bw.FillInt64("UnkOffset2", bw.Position - start + UnkOffset2Delta); } WriteSpecific(bw); }
internal void WriteHeader(BinaryWriterEx bw, int i) { bw.WriteInt64(ID); bw.ReserveInt64($"AnimationOffset{i}"); }
internal 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 override void Write(BinaryWriterEx bw) { bw.WriteASCII("EVD\0"); if (Game == GameType.DS1) { bw.WriteUInt32(0); bw.WriteUInt32(0xCC); } else if (Game == GameType.BB) { bw.WriteUInt32(0xFF00); bw.WriteUInt32(0xCC); } else if (Game == GameType.DS3) { bw.WriteUInt32(0x1FF00); bw.WriteUInt32(0xCD); } void ReserveIntW(string name, bool?isWide = null) { if (isWide ?? Game != GameType.DS1) { bw.ReserveInt64(name); } else { bw.ReserveInt32(name); } } void FillIntW(string name, long value, bool?isWide = null) { if (isWide ?? Game != GameType.DS1) { bw.FillInt64(name, value); } else { bw.FillInt32(name, (int)value); } } void WriteIntW(long value, bool?isWide = null) { if (isWide ?? Game != GameType.DS1) { bw.WriteInt64(value); } else { bw.WriteInt32((int)value); } } if (Game == GameType.BB) { bw.ReserveInt64("FileLength"); } else { bw.ReserveInt32("FileLength"); } WriteIntW(Events.Count); ReserveIntW("EventsOffset"); ReserveIntW("InstructionsCount"); ReserveIntW("InstructionsOffset"); //Dummy count. Always empty. WriteIntW(0); // Same as EventLayersOffset because it's always empty. ReserveIntW("DummiesOffset"); ReserveIntW("EventLayersCount"); ReserveIntW("EventLayersOffset"); ReserveIntW("ParametersCount"); ReserveIntW("ParametersOffset"); WriteIntW(LinkedFileStringIndices.Count); ReserveIntW("LinkedFilesOffset"); ReserveIntW("ArgsBlockSize"); ReserveIntW("ArgsBlockOffset"); ReserveIntW("StringsBlockSize"); ReserveIntW("StringsBlockOffset"); if (Game == GameType.DS1) { bw.WriteInt32(0); } // Events FillIntW("EventsOffset", bw.Position); for (int i = 0; i < Events.Count; i++) { Events[i].Write(bw, Game, i); } // Instructions long instructionsOffset = bw.Position; FillIntW("InstructionsOffset", instructionsOffset); long instructionsCount = 0; for (int i = 0; i < Events.Count; i++) { FillIntW($"EventInstructionsOffset{i}", bw.Position - instructionsOffset); for (int j = 0; j < Events[i].Instructions.Count; j++) { Events[i].Instructions[j].Write(bw, Game, i, j); } instructionsCount += Events[i].Instructions.Count; } FillIntW("InstructionsCount", instructionsCount); // Dummies FillIntW("DummiesOffset", bw.Position); // EventLayers long eventLayersOffset = bw.Position; FillIntW("EventLayersOffset", eventLayersOffset); long eventLayersCount = 0; for (int i = 0; i < Events.Count; i++) { for (int j = 0; j < Events[i].Instructions.Count; j++) { if (Events[i].Instructions[j].Layer != null) { if (Game == GameType.DS3) { bw.FillInt64($"InstructionLayerOffset{i}:{j}", bw.Position - eventLayersOffset); } else { bw.FillInt32($"InstructionLayerOffset{i}:{j}", (int)(bw.Position - eventLayersOffset)); } Events[i].Instructions[j].Layer.Write(bw, Game); eventLayersCount++; } } } FillIntW("EventLayersCount", eventLayersCount); // Args long argsBlockOffset = bw.Position; FillIntW("ArgsBlockOffset", argsBlockOffset); for (int i = 0; i < Events.Count; i++) { for (int j = 0; j < Events[i].Instructions.Count; j++) { if (Events[i].Instructions[j].Args.Length > 0) { bw.FillInt32($"InstructionArgsOffset{i}:{j}", (int)(bw.Position - argsBlockOffset)); bw.WriteBytes(Events[i].Instructions[j].Args); //bw.Pad(4); } } } if (Game == GameType.DS1) { if ((bw.Position - argsBlockOffset) % 16 > 0) { bw.WritePattern(16 - (int)(bw.Position - argsBlockOffset) % 16, 0x00); } } else { bw.Pad(16); } FillIntW("ArgsBlockSize", bw.Position - argsBlockOffset); // Parameters long parametersOffset = bw.Position; FillIntW("ParametersOffset", parametersOffset); long parametersCount = 0; for (int i = 0; i < Events.Count; i++) { if (Events[i].Parameters.Count > 0) { if (Game == GameType.DS3) { bw.FillInt64($"EventParametersOffset{i}", bw.Position - parametersOffset); } else { bw.FillInt32($"EventParametersOffset{i}", (int)(bw.Position - parametersOffset)); } for (int j = 0; j < Events[i].Parameters.Count; j++) { Events[i].Parameters[j].Write(bw, Game); } parametersCount += Events[i].Parameters.Count; } } FillIntW("ParametersCount", parametersCount); // Linked Files FillIntW("LinkedFilesOffset", bw.Position); for (int i = 0; i < LinkedFileStringIndices.Count; i++) { ReserveIntW($"LinkedFileStringOffset{i}"); } // Strings FillIntW("StringsBlockOffset", bw.Position); long stringsStartOffset = bw.Position; List <long> stringTableOffsets = new List <long>(); for (int i = 0; i < StringTable.Count; i++) { stringTableOffsets.Add(bw.Position - stringsStartOffset); bw.WriteUTF16(StringTable[i], terminate: true); } FillIntW("StringsBlockSize", bw.Position - stringsStartOffset); // Linked Files - Second Pass for (int i = 0; i < LinkedFileStringIndices.Count; i++) { FillIntW($"LinkedFileStringOffset{i}", stringTableOffsets[LinkedFileStringIndices[i]]); } if (Game == GameType.BB) { bw.FillInt64("FileLength", bw.Position); } else { bw.FillInt32("FileLength", (int)bw.Position); } }
internal override void Write(BinaryWriterEx bw) { bw.WriteASCII("TAE "); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0xFF); bw.WriteInt32(0x1000C); 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 override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte((byte)(Long ? 2 : 1)); bw.WriteByte(0); bw.ReserveInt32("FileSize"); bw.WriteInt32(1); bw.ReserveInt32("GroupCount"); bw.WriteInt32(Entries.Count); if (Long) { bw.WriteInt32(0xFF); } if (Long) { bw.ReserveInt64("StringOffsets"); } else { bw.ReserveInt32("StringOffsets"); } bw.WriteInt32(0); 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 (Long) { bw.WriteInt32(0); } groupCount++; } bw.FillInt32("GroupCount", groupCount); if (Long) { bw.FillInt64("StringOffsets", bw.Position); } else { bw.FillInt32("StringOffsets", (int)bw.Position); } for (int i = 0; i < Entries.Count; i++) { if (Long) { bw.ReserveInt64($"StringOffset{i}"); } else { bw.ReserveInt32($"StringOffset{i}"); } } for (int i = 0; i < Entries.Count; i++) { string text = Entries[i].Text; if (Long) { bw.FillInt64($"StringOffset{i}", text == null ? 0 : bw.Position); } else { bw.FillInt64($"StringOffset{i}", text == null ? 0 : (int)bw.Position); } if (text != null) { bw.WriteUTF16(Entries[i].Text, true); } } 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; 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 }
/// <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 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, 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 override void Write(BinaryWriterEx bw, int id) { long start = bw.Position; bw.ReserveInt64("NameOffset"); bw.WriteUInt32((uint)Type); bw.WriteInt32(id); bw.WriteUInt32((uint)Shape.Type); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteInt32(Unk2C); bw.ReserveInt64("BaseDataOffset1"); bw.ReserveInt64("BaseDataOffset2"); bw.WriteInt32(-1); bw.WriteInt32(MapStudioLayer); bw.ReserveInt64("ShapeDataOffset"); bw.ReserveInt64("BaseDataOffset3"); bw.ReserveInt64("TypeDataOffset"); bw.FillInt64("NameOffset", bw.Position - start); bw.WriteUTF16(Name, true); bw.Pad(4); bw.FillInt64("BaseDataOffset1", bw.Position - start); bw.WriteInt16((short)UnkA.Count); bw.WriteInt16s(UnkA); bw.Pad(4); bw.FillInt64("BaseDataOffset2", bw.Position - start); bw.WriteInt16((short)UnkB.Count); bw.WriteInt16s(UnkB); bw.Pad(8); if (Shape.HasShapeData) { bw.FillInt64("ShapeDataOffset", bw.Position - start); Shape.WriteShapeData(bw); } else { bw.FillInt64("ShapeDataOffset", 0); } bw.FillInt64("BaseDataOffset3", bw.Position - start); bw.WriteInt32(UnkC00); bw.WriteInt32(UnkC04); if (HasTypeData) { if (Type == RegionType.Region23 || Type == RegionType.PartsGroup || Type == RegionType.AutoDrawGroup) { bw.Pad(8); } bw.FillInt64("TypeDataOffset", bw.Position - start); WriteTypeData(bw); } else { bw.FillInt64("TypeDataOffset", 0); } bw.Pad(8); }
internal void Write(BinaryWriterEx bw) { long start = bw.Position; bw.ReserveInt64("DescOffset"); bw.ReserveInt64("NameOffset"); bw.WriteInt32(ModelLocalID); bw.WriteUInt32((uint)Type); bw.WriteInt32(ID); bw.WriteInt32(modelIndex); bw.ReserveInt64("PlaceholderOffset"); bw.WriteVector3(Position); bw.WriteVector3(Rotation); bw.WriteVector3(Scale); bw.WriteUInt32s(DrawGroups); bw.WriteUInt32s(DispGroups); bw.WriteUInt32s(BackreadGroups); bw.WriteInt32(UnkFA4); bw.ReserveInt64("BaseDataOffset"); bw.ReserveInt64("TypeDataOffset"); bw.ReserveInt64("UnkOffset1"); bw.ReserveInt64("UnkOffset2"); bw.FillInt64("DescOffset", bw.Position - start); bw.WriteUTF16(Description, true); bw.FillInt64("NameOffset", bw.Position - start); bw.WriteUTF16(Name, true); if (Placeholder == null) { bw.FillInt64("PlaceholderOffset", 0); } else { bw.FillInt64("PlaceholderOffset", bw.Position - start); bw.WriteUTF16(Placeholder, true); } bw.Pad(8); bw.FillInt64("BaseDataOffset", bw.Position - start); bw.WriteInt32(EventEntityID); bw.WriteSByte(OldLightID); bw.WriteSByte(OldFogID); bw.WriteSByte(OldScatterID); bw.WriteSByte(OldLensFlareID); bw.WriteInt32(0); bw.WriteSByte(OldLanternID); bw.WriteSByte(OldLodParamID); bw.WriteSByte(UnkB0E); bw.WriteBoolean(OldIsShadowDest); bw.FillInt64("TypeDataOffset", bw.Position - start); if (UnkOffset1Delta == 0) { bw.FillInt64("UnkOffset1", 0); } else { bw.FillInt64("UnkOffset1", bw.Position - start + UnkOffset1Delta); } if (UnkOffset2Delta == 0) { bw.FillInt64("UnkOffset2", 0); } else { bw.FillInt64("UnkOffset2", bw.Position - start + UnkOffset2Delta); } WriteSpecific(bw); }
internal void Write(BinaryWriterEx bw, PARAMDEF def, int index) { if (def.FormatVersion >= 202) { bw.ReserveInt64($"DisplayNameOffset{index}"); } else if (def.Unicode) { bw.WriteFixStrW(DisplayName, 0x40, (byte)(def.FormatVersion >= 104 ? 0x00 : 0x20)); } else { bw.WriteFixStr(DisplayName, 0x40, (byte)(def.FormatVersion >= 104 ? 0x00 : 0x20)); } byte padding = (byte)(def.FormatVersion >= 200 ? 0x00 : 0x20); bw.WriteFixStr(DisplayType.ToString(), 8, padding); bw.WriteFixStr(DisplayFormat, 8, padding); bw.WriteSingle(Default); bw.WriteSingle(Minimum); bw.WriteSingle(Maximum); bw.WriteSingle(Increment); bw.WriteInt32((int)EditFlags); bw.WriteInt32(ParamUtil.GetValueSize(DisplayType) * (ParamUtil.IsArrayType(DisplayType) ? ArrayLength : 1)); if (def.FormatVersion >= 200) { bw.ReserveInt64($"DescriptionOffset{index}"); } else { bw.ReserveInt32($"DescriptionOffset{index}"); } if (def.FormatVersion >= 202) { bw.ReserveInt64($"InternalTypeOffset{index}"); } else { bw.WriteFixStr(InternalType, 0x20, padding); } if (def.FormatVersion >= 202) { bw.ReserveInt64($"InternalNameOffset{index}"); } else if (def.FormatVersion >= 102) { bw.WriteFixStr(MakeInternalName(), 0x20, padding); } if (def.FormatVersion >= 104) { bw.WriteInt32(SortID); } if (def.FormatVersion >= 200) { bw.WriteInt32(0); bw.ReserveInt64($"UnkB8Offset{index}"); bw.ReserveInt64($"UnkC0Offset{index}"); bw.ReserveInt64($"UnkC8Offset{index}"); } }
public static void Write(BinaryWriterEx bw, List <BinderFileHeader> files) { 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("Could not determine hash group count."); } 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.ReserveInt64("HashesOffset"); bw.WriteUInt32(groupCount); bw.WriteByte(0x10); bw.WriteByte(8); bw.WriteByte(8); bw.WriteByte(0); foreach (HashGroup hashGroup in hashGroups) { hashGroup.Write(bw); } bw.FillInt64("HashesOffset", bw.Position); foreach (PathHash pathHash in pathHashes) { pathHash.Write(bw); } }
internal 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 = false; bw.ReserveInt32("NameOffset"); bw.WriteInt16(0); bw.WriteInt16(Unk1); bw.WriteInt16(Unk2); bw.WriteUInt16((ushort)Rows.Count); if (FixStrID) { bw.WriteFixStr(ID, 0x20); } else { bw.WriteInt32(0); bw.ReserveInt32("IDOffset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.WriteByte(0); bw.WriteByte(Unk3); bw.WriteByte(Unk4); bw.WriteByte(0); bw.ReserveInt64("DataStart"); bw.WriteInt32(0); bw.WriteInt32(0); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteHeader(bw, i); } bw.FillInt64("DataStart", bw.Position); for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteCells(bw, i, layout); } bw.FillInt32("NameOffset", (int)bw.Position); if (FixStrID) { if (Unk4 == 6) { bw.WriteShiftJIS(Name, true); } else if (Unk4 == 7) { bw.WriteUTF16(Name, true); } } else { bw.WriteShiftJIS(Name, true); bw.FillInt32("IDOffset", (int)bw.Position); bw.WriteASCII(ID, true); } for (int i = 0; i < Rows.Count; i++) { Rows[i].WriteName(bw, i, Unk4); } }
/// <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); if (Format == 0x0C) { bw.WriteInt64(0x18); } else if (Format == 0x70) { bw.WriteInt64(0x1C); } else { bw.WriteInt64(0x24); } bw.ReserveInt64("DataStart"); 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++) { Files[i].Write(bw, 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 (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++) { File file = Files[i]; if (file.Bytes.LongLength > 0) { bw.Pad(0x10); } bw.FillInt32($"FileData{i}", (int)bw.Position); byte[] bytes = file.Bytes; int compressedSize = bytes.Length; if (file.Flags == 0x03 || file.Flags == 0xC0) { compressedSize = SFUtil.WriteZlib(bw, 0x9C, bytes); } else { bw.WriteBytes(bytes); } bw.FillInt64($"CompressedSize{i}", bytes.Length); } }
internal void WriteHeader(BinaryWriterEx bw, int i) { bw.WriteInt64(ID); bw.ReserveInt64($"RowOffset{i}"); bw.ReserveInt64($"NameOffset{i}"); }
/// <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); }