internal override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteUInt32((uint)Version); bw.BigEndian = Version == CCMVer.DemonsSouls; bw.ReserveInt32("FileSize"); bw.WriteInt16(FullWidth); bw.WriteInt16(TexWidth); bw.WriteInt16(TexHeight); if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { bw.WriteInt16(Unk0E); bw.ReserveInt16("CodeGroupCount"); bw.WriteInt16((short)Glyphs.Count); } else if (Version == CCMVer.DarkSouls2) { bw.ReserveInt16("TexRegionCount"); bw.WriteInt16((short)Glyphs.Count); bw.WriteInt16(0); } bw.WriteInt32(0x20); bw.ReserveInt32("GlyphOffset"); bw.WriteByte(Unk1C); bw.WriteByte(Unk1D); bw.WriteByte(TexCount); bw.WriteByte(0); var codes = new List <int>(Glyphs.Keys); codes.Sort(); if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { var codeGroups = new List <CodeGroup>(); for (int i = 0; i < Glyphs.Count;) { int startCode = codes[i]; int glyphIndex = i; for (i++; i < Glyphs.Count && codes[i] == codes[i - 1] + 1; i++) { ; } int endCode = codes[i - 1]; codeGroups.Add(new CodeGroup(startCode, endCode, glyphIndex)); } bw.FillInt16("CodeGroupCount", (short)codeGroups.Count); foreach (CodeGroup group in codeGroups) { group.Write(bw); } bw.FillInt32("GlyphOffset", (int)bw.Position); foreach (int code in codes) { Glyph glyph = Glyphs[code]; bw.WriteVector2(glyph.UV1); bw.WriteVector2(glyph.UV2); bw.WriteInt16(glyph.PreSpace); bw.WriteInt16(glyph.Width); bw.WriteInt16(glyph.Advance); bw.WriteInt16(glyph.TexIndex); } } else if (Version == CCMVer.DarkSouls2) { var texRegionsByCode = new Dictionary <int, TexRegion>(Glyphs.Count); var texRegions = new HashSet <TexRegion>(); foreach (int code in codes) { Glyph glyph = Glyphs[code]; short x1 = (short)Math.Round(glyph.UV1.X * TexWidth); short y1 = (short)Math.Round(glyph.UV1.Y * TexHeight); short x2 = (short)Math.Round(glyph.UV2.X * TexWidth); short y2 = (short)Math.Round(glyph.UV2.Y * TexHeight); var region = new TexRegion(x1, y1, x2, y2); texRegionsByCode[code] = region; texRegions.Add(region); } bw.FillInt16("TexRegionCount", (short)texRegions.Count); var texRegionOffsets = new Dictionary <TexRegion, int>(texRegions.Count); foreach (TexRegion region in texRegions) { texRegionOffsets[region] = (int)bw.Position; region.Write(bw); } bw.FillInt32("GlyphOffset", (int)bw.Position); foreach (int code in codes) { Glyph glyph = Glyphs[code]; bw.WriteInt32(code); bw.WriteInt32(texRegionOffsets[texRegionsByCode[code]]); bw.WriteInt16(glyph.TexIndex); bw.WriteInt16(glyph.PreSpace); bw.WriteInt16(glyph.Width); bw.WriteInt16(glyph.Advance); bw.WriteInt32(0); bw.WriteInt32(0); } } bw.FillInt32("FileSize", (int)bw.Position); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteASCII(LongFormat ? "fsSL" : "fSSL"); bw.WriteInt32(1); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(0x54); bw.ReserveInt32("DataSize"); bw.WriteInt32(6); bw.WriteInt32(LongFormat ? 0x48 : 0x2C); bw.WriteInt32(1); bw.WriteInt32(LongFormat ? 0x20 : 0x10); bw.WriteInt32(StateGroups.Count); int stateSize = LongFormat ? 0x48 : 0x24; bw.WriteInt32(stateSize); bw.WriteInt32(StateGroups.Values.Sum(sg => sg.Count + (sg.Count == 1 ? 0 : 1))); bw.WriteInt32(LongFormat ? 0x38 : 0x1C); bw.ReserveInt32("ConditionCount"); bw.WriteInt32(LongFormat ? 0x18 : 0x10); bw.ReserveInt32("CommandCallCount"); bw.WriteInt32(LongFormat ? 0x10 : 0x8); bw.ReserveInt32("CommandArgCount"); bw.ReserveInt32("ConditionOffsetsOffset"); bw.ReserveInt32("ConditionOffsetsCount"); bw.ReserveInt32("NameBlockOffset"); bw.WriteInt32(Name == null ? 0 : Name.Length + 1); bw.ReserveInt32("UnkOffset1"); bw.WriteInt32(0); bw.ReserveInt32("UnkOffset2"); bw.WriteInt32(0); long dataStart = bw.Position; bw.WriteInt32(1); bw.WriteInt32(Unk70); bw.WriteInt32(Unk74); bw.WriteInt32(Unk78); bw.WriteInt32(Unk7C); if (LongFormat) { bw.WriteInt32(0); } ReserveVarint(bw, LongFormat, "StateGroupsOffset"); WriteVarint(bw, LongFormat, StateGroups.Count); ReserveVarint(bw, LongFormat, "NameOffset"); WriteVarint(bw, LongFormat, Name == null ? 0 : Name.Length + 1); long unkNull = DarkSoulsCount == 1 ? 0 : -1; WriteVarint(bw, LongFormat, unkNull); WriteVarint(bw, LongFormat, unkNull); // Collect and sort all the IDs so everything is definitely in the same order everywhere List <long> stateGroupIDs = StateGroups.Keys.ToList(); stateGroupIDs.Sort(); var stateIDs = new Dictionary <long, List <long> >(); foreach (long groupID in stateGroupIDs) { stateIDs[groupID] = StateGroups[groupID].Keys.ToList(); stateIDs[groupID].Sort(); } if (StateGroups.Count == 0) { FillVarint(bw, LongFormat, "StateGroupsOffset", -1); } else { FillVarint(bw, LongFormat, "StateGroupsOffset", bw.Position - dataStart); foreach (long groupID in stateGroupIDs) { WriteVarint(bw, LongFormat, groupID); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1"); WriteVarint(bw, LongFormat, StateGroups[groupID].Count); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2"); } } var stateOffsets = new Dictionary <long, Dictionary <long, long> >(); var weirdStateOffsets = new List <long[]>(); foreach (long groupID in stateGroupIDs) { stateOffsets[groupID] = new Dictionary <long, long>(); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1", bw.Position - dataStart); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2", bw.Position - dataStart); long firstStateOffset = bw.Position; foreach (long stateID in stateIDs[groupID]) { stateOffsets[groupID][stateID] = bw.Position - dataStart; StateGroups[groupID][stateID].WriteHeader(bw, LongFormat, groupID, stateID); } if (StateGroups[groupID].Count > 1) { weirdStateOffsets.Add(new long[] { firstStateOffset, bw.Position }); bw.Position += stateSize; } } // Make a list of every unique condition var conditions = new Dictionary <long, List <Condition> >(); foreach (long groupID in stateGroupIDs) { conditions[groupID] = new List <Condition>(); void addCondition(Condition cond) { if (!conditions[groupID].Any(c => ReferenceEquals(cond, c))) { conditions[groupID].Add(cond); foreach (Condition subCond in cond.Subconditions) { addCondition(subCond); } } } foreach (State state in StateGroups[groupID].Values) { foreach (Condition cond in state.Conditions) { addCondition(cond); } } } bw.FillInt32("ConditionCount", conditions.Values.Sum(group => group.Count)); // Yes, I do in fact want this to be keyed by reference var conditionOffsets = new Dictionary <Condition, long>(); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { Condition cond = conditions[groupID][i]; conditionOffsets[cond] = bw.Position - dataStart; cond.WriteHeader(bw, LongFormat, groupID, i, stateOffsets[groupID]); } } var commands = new List <CommandCall>(); foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { StateGroups[groupID][stateID].WriteCommandCalls(bw, LongFormat, groupID, stateID, dataStart, commands); } for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteCommandCalls(bw, LongFormat, groupID, i, dataStart, commands); } } bw.FillInt32("CommandCallCount", commands.Count); bw.FillInt32("CommandArgCount", commands.Sum(command => command.Arguments.Count)); for (int i = 0; i < commands.Count; i++) { commands[i].WriteArgs(bw, LongFormat, i, dataStart); } bw.FillInt32("ConditionOffsetsOffset", (int)(bw.Position - dataStart)); int conditionOffsetsCount = 0; foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { conditionOffsetsCount += StateGroups[groupID][stateID].WriteConditionOffsets(bw, LongFormat, groupID, stateID, dataStart, conditionOffsets); } for (int i = 0; i < conditions[groupID].Count; i++) { conditionOffsetsCount += conditions[groupID][i].WriteConditionOffsets(bw, LongFormat, groupID, i, dataStart, conditionOffsets); } } bw.FillInt32("ConditionOffsetsCount", conditionOffsetsCount); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteEvaluator(bw, LongFormat, groupID, i, dataStart); } } for (int i = 0; i < commands.Count; i++) { commands[i].WriteBytecode(bw, LongFormat, i, dataStart); } bw.FillInt32("NameBlockOffset", (int)(bw.Position - dataStart)); if (Name == null) { FillVarint(bw, LongFormat, "NameOffset", -1); } else { bw.Pad(2); FillVarint(bw, LongFormat, "NameOffset", bw.Position - dataStart); bw.WriteUTF16(Name, true); } bw.FillInt32("UnkOffset1", (int)(bw.Position - dataStart)); bw.FillInt32("UnkOffset2", (int)(bw.Position - dataStart)); bw.FillInt32("DataSize", (int)(bw.Position - dataStart)); if (DarkSoulsCount == 1) { bw.Pad(4); } else if (DarkSoulsCount == 2) { bw.Pad(0x10); } foreach (long[] offsets in weirdStateOffsets) { bw.Position = offsets[0]; byte[] bytes = new byte[stateSize]; bw.Stream.Read(bytes, 0, stateSize); bw.Position = offsets[1]; bw.WriteBytes(bytes); } }
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); }
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); } }
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); }
/// <summary> /// Writes FLVER data to a BinaryWriterEx. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = Header.BigEndian; bw.WriteASCII("FLVER\0"); bw.WriteASCII(Header.BigEndian ? "B\0" : "L\0"); bw.WriteInt32(Header.Version); bw.ReserveInt32("DataOffset"); bw.ReserveInt32("DataSize"); bw.WriteInt32(Dummies.Count); bw.WriteInt32(Materials.Count); bw.WriteInt32(Bones.Count); bw.WriteInt32(Meshes.Count); bw.WriteInt32(Meshes.Sum(m => m.VertexBuffers.Count)); bw.WriteVector3(Header.BoundingBoxMin); bw.WriteVector3(Header.BoundingBoxMax); int trueFaceCount = 0; int totalFaceCount = 0; foreach (Mesh mesh in Meshes) { bool allowPrimitiveRestarts = mesh.Vertices.Length < ushort.MaxValue; foreach (FaceSet faceSet in mesh.FaceSets) { faceSet.AddFaceCounts(allowPrimitiveRestarts, ref trueFaceCount, ref totalFaceCount); } } bw.WriteInt32(trueFaceCount); bw.WriteInt32(totalFaceCount); byte vertexIndicesSize = 0; if (Header.Version < 0x20013) { vertexIndicesSize = 16; foreach (Mesh mesh in Meshes) { foreach (FaceSet fs in mesh.FaceSets) { vertexIndicesSize = (byte)Math.Max(vertexIndicesSize, fs.GetVertexIndexSize()); } } } bw.WriteByte(vertexIndicesSize); bw.WriteBoolean(Header.Unicode); bw.WriteBoolean(Header.Unk4A); bw.WriteByte(0); bw.WriteInt32(Header.Unk4C); bw.WriteInt32(Meshes.Sum(m => m.FaceSets.Count)); bw.WriteInt32(BufferLayouts.Count); bw.WriteInt32(Materials.Sum(m => m.Textures.Count)); bw.WriteByte(Header.Unk5C); bw.WriteByte(Header.Unk5D); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(Header.Unk68); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); foreach (FLVER.Dummy dummy in Dummies) { dummy.Write(bw, Header.Version); } for (int i = 0; i < Materials.Count; i++) { Materials[i].Write(bw, i); } for (int i = 0; i < Bones.Count; i++) { Bones[i].Write(bw, i); } for (int i = 0; i < Meshes.Count; i++) { Meshes[i].Write(bw, i); } int faceSetIndex = 0; foreach (Mesh mesh in Meshes) { for (int i = 0; i < mesh.FaceSets.Count; i++) { int indexSize = vertexIndicesSize; if (indexSize == 0) { indexSize = mesh.FaceSets[i].GetVertexIndexSize(); } mesh.FaceSets[i].Write(bw, Header, indexSize, faceSetIndex + i); } faceSetIndex += mesh.FaceSets.Count; } int vertexBufferIndex = 0; foreach (Mesh mesh in Meshes) { for (int i = 0; i < mesh.VertexBuffers.Count; i++) { mesh.VertexBuffers[i].Write(bw, Header, vertexBufferIndex + i, i, BufferLayouts, mesh.Vertices.Length); } vertexBufferIndex += mesh.VertexBuffers.Count; } for (int i = 0; i < BufferLayouts.Count; i++) { BufferLayouts[i].Write(bw, i); } int textureIndex = 0; for (int i = 0; i < Materials.Count; i++) { Materials[i].WriteTextures(bw, i, textureIndex); textureIndex += Materials[i].Textures.Count; } if (Header.Version >= 0x2001A) { SekiroUnk.Write(bw); } bw.Pad(0x10); for (int i = 0; i < BufferLayouts.Count; i++) { BufferLayouts[i].WriteMembers(bw, i); } bw.Pad(0x10); for (int i = 0; i < Meshes.Count; i++) { Meshes[i].WriteBoundingBox(bw, i, Header); } bw.Pad(0x10); int boneIndicesStart = (int)bw.Position; for (int i = 0; i < Meshes.Count; i++) { Meshes[i].WriteBoneIndices(bw, i, boneIndicesStart); } bw.Pad(0x10); faceSetIndex = 0; for (int i = 0; i < Meshes.Count; i++) { bw.FillInt32($"MeshFaceSetIndices{i}", (int)bw.Position); for (int j = 0; j < Meshes[i].FaceSets.Count; j++) { bw.WriteInt32(faceSetIndex + j); } faceSetIndex += Meshes[i].FaceSets.Count; } bw.Pad(0x10); vertexBufferIndex = 0; for (int i = 0; i < Meshes.Count; i++) { bw.FillInt32($"MeshVertexBufferIndices{i}", (int)bw.Position); for (int j = 0; j < Meshes[i].VertexBuffers.Count; j++) { bw.WriteInt32(vertexBufferIndex + j); } vertexBufferIndex += Meshes[i].VertexBuffers.Count; } bw.Pad(0x10); var gxOffsets = new List <int>(); foreach (GXList gxList in GXLists) { gxOffsets.Add((int)bw.Position); gxList.Write(bw, Header); } for (int i = 0; i < Materials.Count; i++) { Materials[i].FillGXOffset(bw, i, gxOffsets); } bw.Pad(0x10); textureIndex = 0; for (int i = 0; i < Materials.Count; i++) { Material material = Materials[i]; material.WriteStrings(bw, Header, i); for (int j = 0; j < material.Textures.Count; j++) { material.Textures[j].WriteStrings(bw, Header, textureIndex + j); } textureIndex += material.Textures.Count; } bw.Pad(0x10); for (int i = 0; i < Bones.Count; i++) { Bones[i].WriteStrings(bw, Header.Unicode, i); } int alignment = Header.Version <= 0x2000E ? 0x20 : 0x10; bw.Pad(alignment); if (Header.Version == 0x2000F || Header.Version == 0x20010) { bw.Pad(0x20); } int dataStart = (int)bw.Position; bw.FillInt32("DataOffset", dataStart); faceSetIndex = 0; vertexBufferIndex = 0; for (int i = 0; i < Meshes.Count; i++) { Mesh mesh = Meshes[i]; for (int j = 0; j < mesh.FaceSets.Count; j++) { int indexSize = vertexIndicesSize; if (indexSize == 0) { indexSize = mesh.FaceSets[j].GetVertexIndexSize(); } bw.Pad(alignment); mesh.FaceSets[j].WriteVertices(bw, indexSize, faceSetIndex + j, dataStart); } faceSetIndex += mesh.FaceSets.Count; foreach (FLVER.Vertex vertex in mesh.Vertices) { vertex.PrepareWrite(); } for (int j = 0; j < mesh.VertexBuffers.Count; j++) { bw.Pad(alignment); mesh.VertexBuffers[j].WriteBuffer(bw, vertexBufferIndex + j, BufferLayouts, mesh.Vertices, dataStart, Header); } foreach (FLVER.Vertex vertex in mesh.Vertices) { vertex.FinishWrite(); } vertexBufferIndex += mesh.VertexBuffers.Count; } bw.Pad(alignment); bw.FillInt32("DataSize", (int)bw.Position - dataStart); if (Header.Version == 0x2000F || Header.Version == 0x20010) { bw.Pad(0x20); } }
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 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}"); } }
internal void WriteHeaderOffset(BinaryWriterEx bw, int groupIndex) { bw.ReserveInt32($"GroupHeaderOffset{groupIndex}"); }
internal override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteUTF16("filt"); bw.WriteInt32(3); bw.WriteInt32(0); bw.WriteInt32(Groups.Count); bw.WriteInt32(Unk1); bw.WriteInt32(0x50); bw.ReserveInt32("GroupHeadersOffset"); bw.ReserveInt32("ParamHeaderOffsetsOffset"); bw.ReserveInt32("ParamHeadersOffset"); bw.ReserveInt32("ValuesOffset"); bw.ReserveInt32("UnkOffset1"); bw.ReserveInt32("UnkOffset2"); bw.WriteInt32(Unk3s.Count); bw.ReserveInt32("UnkOffset3"); bw.ReserveInt32("Unk3ValuesOffset"); bw.WriteInt32(0); bw.ReserveInt32("CommentOffsetsOffsetsOffset"); bw.ReserveInt32("CommentOffsetsOffset"); bw.ReserveInt32("CommentsOffset"); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeaderOffset(bw, i); } int groupHeadersOffset = (int)bw.Position; bw.FillInt32("GroupHeadersOffset", groupHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeader(bw, i, groupHeadersOffset); } int paramHeaderOffsetsOffset = (int)bw.Position; bw.FillInt32("ParamHeaderOffsetsOffset", paramHeaderOffsetsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaderOffsets(bw, i, paramHeaderOffsetsOffset); } int paramHeadersOffset = (int)bw.Position; bw.FillInt32("ParamHeadersOffset", paramHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaders(bw, i, paramHeadersOffset); } int valuesOffset = (int)bw.Position; bw.FillInt32("ValuesOffset", valuesOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteValues(bw, i, valuesOffset); } int unkOffset1 = (int)bw.Position; bw.FillInt32("UnkOffset1", (int)bw.Position); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteUnk1(bw, i, unkOffset1); } bw.FillInt32("UnkOffset2", (int)bw.Position); bw.WriteBytes(UnkBlock2); bw.FillInt32("UnkOffset3", (int)bw.Position); for (int i = 0; i < Unk3s.Count; i++) { Unk3s[i].WriteHeader(bw, i); } int unk3ValuesOffset = (int)bw.Position; bw.FillInt32("Unk3ValuesOffset", unk3ValuesOffset); for (int i = 0; i < Unk3s.Count; i++) { Unk3s[i].WriteValues(bw, i, unk3ValuesOffset); } bw.FillInt32("CommentOffsetsOffsetsOffset", (int)bw.Position); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteCommentOffsetsOffset(bw, i); } int commentOffsetsOffset = (int)bw.Position; bw.FillInt32("CommentOffsetsOffset", commentOffsetsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteCommentOffsets(bw, i, commentOffsetsOffset); } int commentsOffset = (int)bw.Position; bw.FillInt32("CommentsOffset", commentsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteComments(bw, i, commentsOffset); } }
internal void Write(BinaryWriterEx bw, List <CustomData> allCustomData, List <long> customDataValueOffsets) { bw.WriteFixStrW(Name, 0x40, 0x00); bw.WriteUInt32((uint)Type); bw.WriteInt32(Type == DataType.Color ? 3 : 0); int length = -1; if (Type == DataType.String) { length = SFEncoding.UTF16.GetByteCount((string)Value + '\0'); if (length % 0x10 != 0) { length += 0x10 - length % 0x10; } } else if (Type == DataType.Custom) { length = ((byte[])Value).Length; if (length % 4 != 0) { throw new InvalidDataException($"Unexpected custom data custom length: {length}"); } } else if (Type == DataType.Color) { length = 4; } long valueOffset = bw.Position; switch (Type) { case DataType.Bool: bw.WriteBoolean((bool)Value); break; case DataType.SByte: bw.WriteSByte((sbyte)Value); break; case DataType.Byte: bw.WriteByte((byte)Value); break; case DataType.Short: bw.WriteInt16((short)Value); break; case DataType.Int: bw.WriteInt32((int)Value); break; case DataType.UInt: bw.WriteUInt32((uint)Value); break; case DataType.Float: bw.WriteSingle((float)Value); break; case DataType.String: case DataType.Custom: case DataType.Color: bw.WriteInt32(length); break; default: throw new NotImplementedException($"Unimplemented custom data type: {Type}"); } if (Type == DataType.Bool || Type == DataType.SByte || Type == DataType.Byte) { bw.WriteByte(0); bw.WriteInt16(0); } else if (Type == DataType.Short) { bw.WriteInt16(0); } // This is probably wrong for the 64-bit format bw.WriteInt32(0); bw.ReserveInt32($"SequencesOffset[{allCustomData.Count}]"); bw.WriteInt32(Sequences.Count); bw.WriteInt32(0); bw.WriteInt32(0); if (Type == DataType.String) { bw.WriteFixStrW((string)Value, length, 0x00); } else if (Type == DataType.Custom) { bw.WriteBytes((byte[])Value); } else if (Type == DataType.Color) { var color = (Color)Value; valueOffset = bw.Position; bw.WriteByte(color.R); bw.WriteByte(color.G); bw.WriteByte(color.B); bw.WriteByte(0); } allCustomData.Add(this); customDataValueOffsets.Add(valueOffset); }
internal void WriteHeader(BinaryWriterEx bw, int index) { bw.WriteInt32(ID); bw.WriteInt32(Values.Count); bw.ReserveInt32($"Unk3ValuesOffset{index}"); }
internal void WriteCommentOffsetsOffset(BinaryWriterEx bw, int index) { bw.ReserveInt32($"CommentOffsetsOffset{index}"); }
internal override void Write(BinaryWriterEx bw) { bw.BigEndian = false; if (Game == GPGame.DarkSouls2) { bw.WriteASCII("filt"); } else { bw.WriteUTF16("filt"); } bw.WriteUInt32((uint)Game); bw.WriteByte(0); bw.WriteBoolean(Unk0D); bw.WriteInt16(0); bw.WriteInt32(Groups.Count); bw.WriteInt32(Unk14); bw.ReserveInt32("HeaderSize"); bw.ReserveInt32("GroupHeadersOffset"); bw.ReserveInt32("ParamHeaderOffsetsOffset"); bw.ReserveInt32("ParamHeadersOffset"); bw.ReserveInt32("ValuesOffset"); bw.ReserveInt32("ValueIDsOffset"); bw.ReserveInt32("UnkOffset2"); bw.WriteInt32(Unk3s.Count); bw.ReserveInt32("UnkOffset3"); bw.ReserveInt32("Unk3ValuesOffset"); bw.WriteInt32(0); if (Game == GPGame.DarkSouls3 || Game == GPGame.Sekiro) { bw.ReserveInt32("CommentOffsetsOffsetsOffset"); bw.ReserveInt32("CommentOffsetsOffset"); bw.ReserveInt32("CommentsOffset"); } if (Game == GPGame.Sekiro) { bw.WriteSingle(Unk50); } bw.FillInt32("HeaderSize", (int)bw.Position); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeaderOffset(bw, i); } int groupHeadersOffset = (int)bw.Position; bw.FillInt32("GroupHeadersOffset", groupHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeader(bw, Game, i, groupHeadersOffset); } int paramHeaderOffsetsOffset = (int)bw.Position; bw.FillInt32("ParamHeaderOffsetsOffset", paramHeaderOffsetsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaderOffsets(bw, i, paramHeaderOffsetsOffset); } int paramHeadersOffset = (int)bw.Position; bw.FillInt32("ParamHeadersOffset", paramHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaders(bw, Game, i, paramHeadersOffset); } int valuesOffset = (int)bw.Position; bw.FillInt32("ValuesOffset", valuesOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteValues(bw, i, valuesOffset); } int valueIDsOffset = (int)bw.Position; bw.FillInt32("ValueIDsOffset", (int)bw.Position); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteValueIDs(bw, Game, i, valueIDsOffset); } bw.FillInt32("UnkOffset2", (int)bw.Position); bw.WriteBytes(UnkBlock2); bw.FillInt32("UnkOffset3", (int)bw.Position); for (int i = 0; i < Unk3s.Count; i++) { Unk3s[i].WriteHeader(bw, Game, i); } int unk3ValuesOffset = (int)bw.Position; bw.FillInt32("Unk3ValuesOffset", unk3ValuesOffset); for (int i = 0; i < Unk3s.Count; i++) { Unk3s[i].WriteValues(bw, Game, i, unk3ValuesOffset); } if (Game == GPGame.DarkSouls3 || Game == GPGame.Sekiro) { bw.FillInt32("CommentOffsetsOffsetsOffset", (int)bw.Position); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteCommentOffsetsOffset(bw, i); } int commentOffsetsOffset = (int)bw.Position; bw.FillInt32("CommentOffsetsOffset", commentOffsetsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteCommentOffsets(bw, i, commentOffsetsOffset); } int commentsOffset = (int)bw.Position; bw.FillInt32("CommentsOffset", commentsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteComments(bw, i, commentsOffset); } } }
internal void WriteHeader(BinaryWriterEx bw, int index, TPFPlatform platform, byte flag2) { if (platform == TPFPlatform.PC) { DDS dds = new DDS(Bytes); if (dds.dwCaps2.HasFlag(DDS.DDSCAPS2.CUBEMAP)) { Type = TexType.Cubemap; } else if (dds.dwCaps2.HasFlag(DDS.DDSCAPS2.VOLUME)) { Type = TexType.Volume; } else { Type = TexType.Texture; } Mipmaps = (byte)dds.dwMipMapCount; } bw.ReserveUInt32($"FileData{index}"); bw.ReserveInt32($"FileSize{index}"); bw.WriteByte(Format); bw.WriteByte((byte)Type); bw.WriteByte(Mipmaps); bw.WriteByte(Flags1); if (platform != TPFPlatform.PC) { bw.WriteInt16(Header.Width); bw.WriteInt16(Header.Height); if (platform == TPFPlatform.Xbox360) { bw.WriteInt32(0); } else if (platform == TPFPlatform.PS3) { bw.WriteInt32(Header.Unk1); if (flag2 != 0) { bw.WriteInt32(Header.Unk2); } } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { bw.WriteInt32(Header.TextureCount); bw.WriteInt32(Header.Unk2); } } bw.ReserveUInt32($"FileName{index}"); bw.WriteInt32(FloatStruct == null ? 0 : 1); if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { bw.WriteInt32(Header.DXGIFormat); } if (FloatStruct != null) { FloatStruct.Write(bw); } }
internal void WriteParamHeaderOffset(BinaryWriterEx bw, int groupIndex, int paramIndex) { bw.ReserveInt32($"ParamHeaderOffset{groupIndex}:{paramIndex}"); }
internal void Write(BinaryWriterEx bw, int index) { bw.WriteInt32(Count); bw.ReserveInt32($"FileHeadersOffset{index}"); }
internal override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteASCII("filt"); bw.WriteInt32(2); bw.WriteInt32(0); bw.WriteInt32(Groups.Count); bw.WriteInt32(Unk1); bw.WriteInt32(0x40); bw.ReserveInt32("GroupHeadersOffset"); bw.ReserveInt32("ParamHeaderOffsetsOffset"); bw.ReserveInt32("ParamHeadersOffset"); bw.ReserveInt32("ValuesOffset"); bw.ReserveInt32("UnkBlock1Offset"); bw.ReserveInt32("UnkBlock2Offset"); bw.WriteInt32(Unk2); bw.ReserveInt32("UnkBlock3Offset"); bw.ReserveInt32("UnkBlock4Offset"); bw.WriteInt32(0); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeaderOffset(bw, i); } int groupHeadersOffset = (int)bw.Position; bw.FillInt32("GroupHeadersOffset", groupHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteHeader(bw, i, groupHeadersOffset); } int paramHeaderOffsetsOffset = (int)bw.Position; bw.FillInt32("ParamHeaderOffsetsOffset", paramHeaderOffsetsOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaderOffsets(bw, i, paramHeaderOffsetsOffset); } int paramHeadersOffset = (int)bw.Position; bw.FillInt32("ParamHeadersOffset", paramHeadersOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteParamHeaders(bw, i, paramHeadersOffset); } int valuesOffset = (int)bw.Position; bw.FillInt32("ValuesOffset", valuesOffset); for (int i = 0; i < Groups.Count; i++) { Groups[i].WriteValues(bw, i, valuesOffset); } bw.FillInt32("UnkBlock1Offset", (int)bw.Position); bw.WriteBytes(UnkBlock1); bw.FillInt32("UnkBlock2Offset", (int)bw.Position); bw.WriteBytes(UnkBlock2); bw.FillInt32("UnkBlock3Offset", (int)bw.Position); bw.WriteBytes(UnkBlock3); bw.FillInt32("UnkBlock4Offset", (int)bw.Position); bw.WriteBytes(UnkBlock4); }
protected override void Write(BinaryWriterEx bw) { bw.WriteASCII("FXR\0"); bw.WriteInt16(0); bw.WriteUInt16((ushort)Version); bw.WriteInt32(1); bw.WriteInt32(ID); bw.ReserveInt32("Section1Offset"); bw.WriteInt32(1); bw.ReserveInt32("Section2Offset"); bw.WriteInt32(Section1Tree.Section2s.Count); bw.ReserveInt32("Section3Offset"); bw.ReserveInt32("Section3Count"); bw.ReserveInt32("Section4Offset"); bw.ReserveInt32("Section4Count"); bw.ReserveInt32("Section5Offset"); bw.ReserveInt32("Section5Count"); bw.ReserveInt32("Section6Offset"); bw.ReserveInt32("Section6Count"); bw.ReserveInt32("Section7Offset"); bw.ReserveInt32("Section7Count"); bw.ReserveInt32("Section8Offset"); bw.ReserveInt32("Section8Count"); bw.ReserveInt32("Section9Offset"); bw.ReserveInt32("Section9Count"); bw.ReserveInt32("Section10Offset"); bw.ReserveInt32("Section10Count"); bw.ReserveInt32("Section11Offset"); bw.ReserveInt32("Section11Count"); bw.WriteInt32(1); bw.WriteInt32(0); if (Version == FXRVersion.Sekiro) { bw.ReserveInt32("Section12Offset"); bw.WriteInt32(Section12s.Count); bw.ReserveInt32("Section13Offset"); bw.WriteInt32(Section13s.Count); bw.ReserveInt32("Section14Offset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.FillInt32("Section1Offset", (int)bw.Position); Section1Tree.Write(bw); bw.Pad(0x10); bw.FillInt32("Section2Offset", (int)bw.Position); Section1Tree.WriteSection2s(bw); bw.Pad(0x10); bw.FillInt32("Section3Offset", (int)bw.Position); List <Section2> section2s = Section1Tree.Section2s; var section3s = new List <Section3>(); for (int i = 0; i < section2s.Count; i++) { section2s[i].WriteSection3s(bw, i, section3s); } bw.FillInt32("Section3Count", section3s.Count); bw.Pad(0x10); bw.FillInt32("Section4Offset", (int)bw.Position); var section4s = new List <Section4>(); Section4Tree.Write(bw, section4s); Section4Tree.WriteSection4s(bw, section4s); bw.FillInt32("Section4Count", section4s.Count); bw.Pad(0x10); bw.FillInt32("Section5Offset", (int)bw.Position); int section5Count = 0; for (int i = 0; i < section4s.Count; i++) { section4s[i].WriteSection5s(bw, i, ref section5Count); } bw.FillInt32("Section5Count", section5Count); bw.Pad(0x10); bw.FillInt32("Section6Offset", (int)bw.Position); section5Count = 0; var section6s = new List <FFXDrawEntityHost>(); for (int i = 0; i < section4s.Count; i++) { section4s[i].WriteSection6s(bw, i, ref section5Count, section6s); } bw.FillInt32("Section6Count", section6s.Count); bw.Pad(0x10); bw.FillInt32("Section7Offset", (int)bw.Position); var section7s = new List <FFXProperty>(); for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection7s(bw, i, section7s); } bw.FillInt32("Section7Count", section7s.Count); bw.Pad(0x10); bw.FillInt32("Section8Offset", (int)bw.Position); var section8s = new List <Section8>(); for (int i = 0; i < section7s.Count; i++) { section7s[i].WriteSection8s(bw, i, section8s); } bw.FillInt32("Section8Count", section8s.Count); bw.Pad(0x10); bw.FillInt32("Section9Offset", (int)bw.Position); var section9s = new List <Section9>(); for (int i = 0; i < section8s.Count; i++) { section8s[i].WriteSection9s(bw, i, section9s); } bw.FillInt32("Section9Count", section9s.Count); bw.Pad(0x10); bw.FillInt32("Section10Offset", (int)bw.Position); var section10s = new List <Section10>(); for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection10s(bw, i, section10s); } bw.FillInt32("Section10Count", section10s.Count); bw.Pad(0x10); bw.FillInt32("Section11Offset", (int)bw.Position); int section11Count = 0; for (int i = 0; i < section3s.Count; i++) { section3s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section6s.Count; i++) { section6s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section7s.Count; i++) { section7s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section8s.Count; i++) { section8s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section9s.Count; i++) { section9s[i].WriteSection11s(bw, i, ref section11Count); } for (int i = 0; i < section10s.Count; i++) { section10s[i].WriteSection11s(bw, i, ref section11Count); } bw.FillInt32("Section11Count", section11Count); bw.Pad(0x10); if (Version == FXRVersion.Sekiro) { bw.FillInt32("Section12Offset", (int)bw.Position); bw.WriteInt32s(Section12s); bw.Pad(0x10); bw.FillInt32("Section13Offset", (int)bw.Position); bw.WriteInt32s(Section13s); bw.Pad(0x10); bw.FillInt32("Section14Offset", (int)bw.Position); } }
internal override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteInt32(0); bw.ReserveInt32("FileSize"); int fileStart = (int)bw.Position; bw.WriteInt32(0); bw.WriteInt32(3); WriteMarker(bw, 0x01); bw.WriteInt32(0); bw.WriteInt32(0x1C); bw.WriteInt32(1); bw.WriteInt32(2); WriteMarker(bw, 0xB0); bw.WriteInt32(4); bw.WriteASCII("MTD "); WriteMarker(bw, 0x34); bw.WriteInt32(0x3E8); WriteMarker(bw, 0x01); bw.WriteInt32(0); bw.ReserveInt32("DataSize"); bw.WriteInt32(2); bw.WriteInt32(4); int dataStart = (int)bw.Position; WriteMarker(bw, 0xA3); bw.WriteShiftJISLengthPrefixed(ShaderPath, 0xA3); bw.WriteShiftJISLengthPrefixed(Description, 0x03); bw.WriteInt32(1); bw.WriteInt32(0); bw.ReserveInt32("ParamSize"); bw.WriteInt32(3); bw.WriteInt32(4); WriteMarker(bw, 0xA3); bw.WriteInt32(0); int paramStart = (int)bw.Position; WriteMarker(bw, 0x03); bw.WriteInt32(Params.Count); foreach (Param internalEntry in Params) { internalEntry.Write(bw); } WriteMarker(bw, 0x03); bw.WriteInt32(Textures.Count); foreach (Texture externalEntry in Textures) { externalEntry.Write(bw); } WriteMarker(bw, 0x04); bw.WriteInt32(0); WriteMarker(bw, 0x04); bw.WriteInt32(0); WriteMarker(bw, 0x04); bw.WriteInt32(0); int position = (int)bw.Position; bw.FillInt32("FileSize", position - fileStart); bw.FillInt32("DataSize", position - dataStart); bw.FillInt32("ParamSize", position - paramStart); }
internal void Write(BinaryWriterEx bw, int entryIndex, int memberIndex, List <int> offsetIndex) { offsetIndex.Add((int)bw.Position); bw.ReserveInt32($"MemberTextOffset{entryIndex}:{memberIndex}"); bw.WriteInt32(Unk04); }
internal void Write(BinaryWriterEx bw) { bw.WriteInt32(0); bw.WriteInt32(Unk04); bw.WriteInt32(4); bw.WriteInt32(4); WriteMarker(bw, 0xA3); bw.WriteShiftJISLengthPrefixed(Name, 0xA3); bw.WriteShiftJISLengthPrefixed(Type.ToString().ToLower(), 0x04); bw.WriteInt32(1); bw.WriteInt32(0); bw.ReserveInt32("ValueSize"); int valueStart = (int)bw.Position; if (Type == ParamType.Bool) { bw.WriteByte(0); } else if (Type == ParamType.Int || Type == ParamType.Int2) { bw.WriteByte(1); } else if (Type == ParamType.Float || Type == ParamType.Float2 || Type == ParamType.Float3 || Type == ParamType.Float4) { bw.WriteByte(2); } bw.WriteByte(0x10); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(1); if (Type == ParamType.Bool) { WriteMarker(bw, 0xC0); } else if (Type == ParamType.Int || Type == ParamType.Int2) { WriteMarker(bw, 0xC5); } else if (Type == ParamType.Float || Type == ParamType.Float2 || Type == ParamType.Float3 || Type == ParamType.Float4) { WriteMarker(bw, 0xCA); } if (Type == ParamType.Bool || Type == ParamType.Float || Type == ParamType.Int) { bw.WriteInt32(1); } else if (Type == ParamType.Float2 || Type == ParamType.Int2) { bw.WriteInt32(2); } else if (Type == ParamType.Float3) { bw.WriteInt32(3); } else if (Type == ParamType.Float4) { bw.WriteInt32(4); } if (Type == ParamType.Int) { bw.WriteInt32((int)Value); } else if (Type == ParamType.Int2) { bw.WriteInt32s((int[])Value); } else if (Type == ParamType.Bool) { bw.WriteBoolean((bool)Value); } else if (Type == ParamType.Float) { bw.WriteSingle((float)Value); } else if (Type == ParamType.Float2) { bw.WriteSingles((float[])Value); } else if (Type == ParamType.Float3) { bw.WriteSingles((float[])Value); } else if (Type == ParamType.Float4) { bw.WriteSingles((float[])Value); } bw.FillInt32("ValueSize", (int)bw.Position - valueStart); bw.WriteByte(4); bw.Pad(4); bw.WriteInt32(0); }
private static void CompressDCXEDGE(byte[] data, BinaryWriterEx bw) { int chunkCount = data.Length / 0x10000; if (data.Length % 0x10000 > 0) { chunkCount++; } bw.WriteASCII("DCX\0"); bw.WriteInt32(0x10000); bw.WriteInt32(0x18); bw.WriteInt32(0x24); bw.WriteInt32(0x24); bw.WriteInt32(0x50 + chunkCount * 0x10); bw.WriteASCII("DCS\0"); bw.WriteInt32(data.Length); bw.ReserveInt32("CompressedSize"); bw.WriteASCII("DCP\0"); bw.WriteASCII("EDGE"); bw.WriteInt32(0x20); bw.WriteInt32(0x9000000); bw.WriteInt32(0x10000); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0x00100100); long dcaStart = bw.Position; bw.WriteASCII("DCA\0"); bw.ReserveInt32("DCASize"); long egdtStart = bw.Position; bw.WriteASCII("EgdT"); bw.WriteInt32(0x00010100); bw.WriteInt32(0x24); bw.WriteInt32(0x10); bw.WriteInt32(0x10000); bw.WriteInt32(data.Length % 0x10000); bw.ReserveInt32("EGDTSize"); bw.WriteInt32(chunkCount); bw.WriteInt32(0x100000); for (int i = 0; i < chunkCount; i++) { bw.WriteInt32(0); bw.ReserveInt32($"ChunkOffset{i}"); bw.ReserveInt32($"ChunkSize{i}"); bw.ReserveInt32($"ChunkCompressed{i}"); } bw.FillInt32("DCASize", (int)(bw.Position - dcaStart)); bw.FillInt32("EGDTSize", (int)(bw.Position - egdtStart)); long dataStart = bw.Position; int compressedSize = 0; for (int i = 0; i < chunkCount; i++) { int chunkSize = 0x10000; if (i == chunkCount - 1) { chunkSize = data.Length % 0x10000; } byte[] chunk; using (MemoryStream cmpStream = new MemoryStream()) using (MemoryStream dcmpStream = new MemoryStream(data, i * 0x10000, chunkSize)) { DeflateStream dfltStream = new DeflateStream(cmpStream, CompressionMode.Compress); dcmpStream.CopyTo(dfltStream); dfltStream.Close(); chunk = cmpStream.ToArray(); } if (chunk.Length < chunkSize) { bw.FillInt32($"ChunkCompressed{i}", 1); } else { bw.FillInt32($"ChunkCompressed{i}", 0); chunk = data; } compressedSize += chunk.Length; bw.FillInt32($"ChunkOffset{i}", (int)(bw.Position - dataStart)); bw.FillInt32($"ChunkSize{i}", chunk.Length); bw.WriteBytes(chunk); bw.Pad(0x10); } bw.FillInt32("CompressedSize", compressedSize); }
/// <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); }
protected override void Write(BinaryWriterEx bw) { bool bigEndian = Format == Game.DarkSouls1BE; bool is64Bit = Format >= Game.Bloodborne; bool unk06 = Format >= Game.DarkSouls3; bool unk07 = Format >= Game.Sekiro; int version = Format < Game.DarkSouls3 ? 0xCC : 0xCD; var layers = new List <uint>(); foreach (Event evt in Events) { foreach (Instruction inst in evt.Instructions) { if (inst.Layer.HasValue && !layers.Contains(inst.Layer.Value)) { layers.Add(inst.Layer.Value); } } } bw.WriteASCII("EVD\0"); bw.WriteBoolean(bigEndian); bw.WriteSByte((sbyte)(is64Bit ? -1 : 0)); bw.WriteBoolean(unk06); bw.WriteSByte((sbyte)(unk07 ? -1 : 0)); bw.BigEndian = bigEndian; bw.VarintLong = is64Bit; bw.WriteInt32(version); bw.ReserveInt32("FileSize"); Offsets offsets = default; bw.WriteVarint(Events.Count); bw.ReserveVarint("EventsOffset"); bw.WriteVarint(Events.Sum(e => e.Instructions.Count)); bw.ReserveVarint("InstructionsOffset"); bw.WriteVarint(0); bw.ReserveVarint("Offset3"); bw.WriteVarint(layers.Count); bw.ReserveVarint("LayersOffset"); bw.WriteVarint(Events.Sum(e => e.Parameters.Count)); bw.ReserveVarint("ParametersOffset"); bw.WriteVarint(LinkedFileOffsets.Count); bw.ReserveVarint("LinkedFilesOffset"); bw.ReserveVarint("ArgumentsLength"); bw.ReserveVarint("ArgumentsOffset"); bw.WriteVarint(StringData.Length); bw.ReserveVarint("StringsOffset"); if (!is64Bit) { bw.WriteInt32(0); } offsets.Events = bw.Position; bw.FillVarint("EventsOffset", bw.Position); for (int i = 0; i < Events.Count; i++) { Events[i].Write(bw, Format, i); } offsets.Instructions = bw.Position; bw.FillVarint("InstructionsOffset", bw.Position); for (int i = 0; i < Events.Count; i++) { Events[i].WriteInstructions(bw, Format, offsets, i); } bw.FillVarint("Offset3", bw.Position); offsets.Layers = bw.Position; bw.FillVarint("LayersOffset", bw.Position); var layerOffsets = new Dictionary <uint, long>(layers.Count); foreach (uint layer in layers) { layerOffsets[layer] = bw.Position - offsets.Layers; Layer.Write(bw, layer); } for (int i = 0; i < Events.Count; i++) { Event evt = Events[i]; for (int j = 0; j < evt.Instructions.Count; j++) { evt.Instructions[j].FillLayerOffset(bw, Format, i, j, layerOffsets); } } offsets.Arguments = bw.Position; bw.FillVarint("ArgumentsOffset", bw.Position); for (int i = 0; i < Events.Count; i++) { Event evt = Events[i]; for (int j = 0; j < evt.Instructions.Count; j++) { evt.Instructions[j].WriteArgs(bw, Format, offsets, i, j); } } if ((bw.Position - offsets.Arguments) % 0x10 > 0) { bw.WritePattern(0x10 - (int)(bw.Position - offsets.Arguments) % 0x10, 0x00); } bw.FillVarint("ArgumentsLength", bw.Position - offsets.Arguments); offsets.Parameters = bw.Position; bw.FillVarint("ParametersOffset", bw.Position); for (int i = 0; i < Events.Count; i++) { Events[i].WriteParameters(bw, Format, offsets, i); } offsets.LinkedFiles = bw.Position; bw.FillVarint("LinkedFilesOffset", bw.Position); foreach (long offset in LinkedFileOffsets) { bw.WriteVarint((int)offset); } offsets.Strings = bw.Position; bw.FillVarint("StringsOffset", bw.Position); bw.WriteBytes(StringData); bw.FillInt32("FileSize", (int)bw.Position); }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = BigEndian; bw.WriteInt32(1); bw.WriteInt32(Vertices.Count); bw.ReserveInt32("VertexOffset"); bw.WriteInt32(Triangles.Count); bw.ReserveInt32("TriangleOffset"); bw.ReserveInt32("RootBoxOffset"); bw.WriteInt32(0); bw.WriteInt32(Entities.Count); bw.ReserveInt32("EntityOffset"); for (int i = 0; i < 23; i++) { bw.WriteInt32(0); } bw.FillInt32("VertexOffset", (int)bw.Position); foreach (Vector3 vertex in Vertices) { bw.WriteVector3(vertex); } bw.FillInt32("TriangleOffset", (int)bw.Position); foreach (Triangle triangle in Triangles) { triangle.Write(bw); } var boxTriangleIndexOffsets = new Queue <int>(); void WriteBoxTriangleIndices(Box box) { if (box == null) { return; } WriteBoxTriangleIndices(box.ChildBox1); WriteBoxTriangleIndices(box.ChildBox2); WriteBoxTriangleIndices(box.ChildBox3); WriteBoxTriangleIndices(box.ChildBox4); if (box.TriangleIndices.Count == 0) { boxTriangleIndexOffsets.Enqueue(0); } else { boxTriangleIndexOffsets.Enqueue((int)bw.Position); bw.WriteInt32s(box.TriangleIndices); } } WriteBoxTriangleIndices(RootBox); int rootBoxOffset = RootBox.Write(bw, boxTriangleIndexOffsets); bw.FillInt32("RootBoxOffset", rootBoxOffset); var entityTriangleIndexOffsets = new List <int>(); foreach (Entity entity in Entities) { entityTriangleIndexOffsets.Add((int)bw.Position); bw.WriteInt32s(entity.TriangleIndices); } bw.FillInt32("EntityOffset", (int)bw.Position); for (int i = 0; i < Entities.Count; i++) { Entities[i].Write(bw, entityTriangleIndexOffsets[i]); } }
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); }
/// <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); }