internal void Write(BinaryWriterEx bw, List <BinderFile> files) { bw.BigEndian = BigEndian; bw.WriteASCII("BHF4"); bw.WriteBoolean(Flag1); bw.WriteBoolean(Flag2); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(0x10000); bw.WriteInt32(files.Count); bw.WriteInt64(0x40); bw.WriteFixStr(Timestamp, 8); bw.WriteInt64(Binder.FileHeaderSize(Format)); bw.WriteInt64(0); bw.WriteBoolean(Unicode); bw.WriteByte((byte)Format); bw.WriteByte(Extended); bw.WriteByte(0); bw.WriteInt32(0); if (Extended == 4) { bw.ReserveInt64("HashGroups"); } else { bw.WriteInt64(0); } for (int i = 0; i < files.Count; i++) { FileHeader.Write(bw, files[i], i, Format); } for (int i = 0; i < files.Count; i++) { BinderFile file = files[i]; bw.FillUInt32($"FileName{i}", (uint)bw.Position); if (Unicode) { bw.WriteUTF16(file.Name, true); } else { bw.WriteShiftJIS(file.Name, true); } } if (Extended == 4) { uint groupCount = 0; for (uint p = (uint)files.Count / 7; p <= 100000; p++) { if (SFUtil.IsPrime(p)) { groupCount = p; break; } } if (groupCount == 0) { throw new InvalidOperationException("Hash group count not determined in BXF4."); } var hashLists = new List <PathHash> [groupCount]; for (int i = 0; i < groupCount; i++) { hashLists[i] = new List <PathHash>(); } for (int i = 0; i < files.Count; i++) { var pathHash = new PathHash(i, files[i].Name); uint group = pathHash.Hash % groupCount; hashLists[group].Add(pathHash); } for (int i = 0; i < groupCount; i++) { hashLists[i].Sort((ph1, ph2) => ph1.Hash.CompareTo(ph2.Hash)); } var hashGroups = new List <HashGroup>(); var pathHashes = new List <PathHash>(); int count = 0; foreach (List <PathHash> hashList in hashLists) { int index = count; foreach (PathHash pathHash in hashList) { pathHashes.Add(pathHash); count++; } hashGroups.Add(new HashGroup(index, count - index)); } bw.Pad(0x8); bw.FillInt64("HashGroups", bw.Position); bw.ReserveInt64("PathHashes"); bw.WriteUInt32(groupCount); bw.WriteInt32(0x00080810); foreach (HashGroup hashGroup in hashGroups) { hashGroup.Write(bw); } // No padding after section 1 bw.FillInt64("PathHashes", bw.Position); foreach (PathHash pathHash in pathHashes) { pathHash.Write(bw); } } }
protected override void Write(BinaryWriterEx bw) { bw.WriteASCII("TAE "); bw.BigEndian = BigEndian; bw.WriteBoolean(BigEndian); bw.WriteByte(0); bw.WriteByte(0); if (Format == TAEFormat.DS1) { bw.VarintLong = false; bw.WriteByte(0); } else { bw.VarintLong = true; bw.WriteByte(0xFF); } if (Format == TAEFormat.DS1) { bw.WriteInt32(0x1000B); } else if (Format == TAEFormat.DS3 || Format == TAEFormat.SOTFS) { bw.WriteInt32(0x1000C); } else if (Format == TAEFormat.SDT) { bw.WriteInt32(0x1000D); } bw.ReserveInt32("FileSize"); bw.WriteVarint(0x40); bw.WriteVarint(1); bw.WriteVarint(0x50); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x70 : 0x80); if (Format == TAEFormat.DS1) { bw.WriteInt16(2); bw.WriteInt16(1); } else { bw.WriteVarint(EventBank); } bw.WriteVarint(0); //DeS also if (Format == TAEFormat.DS1) { bw.WriteInt64(0); bw.WriteInt64(0); bw.WriteInt64(0); } bw.WriteBytes(Flags); if (Format == TAEFormat.SOTFS) { bw.WriteByte(0); bw.WriteByte(1); } else { bw.WriteByte(1); bw.WriteByte(0); } for (int i = 0; i < 6; i++) { bw.WriteByte(0); } bw.WriteInt32(ID); bw.WriteInt32(Animations.Count); bw.ReserveVarint("AnimsOffset"); bw.ReserveVarint("AnimGroupsOffset"); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x90 : 0xA0); bw.WriteVarint(Animations.Count); bw.ReserveVarint("FirstAnimOffset"); if (Format == TAEFormat.DS1) { bw.WriteInt32(0); } bw.WriteVarint(1); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x80 : 0x90); if (Format == TAEFormat.DS1) { bw.WriteInt64(0); } bw.WriteInt32(ID); bw.WriteInt32(ID); bw.WriteVarint(0x50); bw.WriteInt64(0); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x98 : 0xB0); bw.ReserveVarint("SkeletonName"); bw.ReserveVarint("SibName"); if (Format != TAEFormat.SOTFS) { bw.WriteVarint(0); bw.WriteVarint(0); } bw.FillVarint("SkeletonName", bw.Position); if (!string.IsNullOrEmpty(SkeletonName)) { bw.WriteUTF16(SkeletonName, true); if (Format != TAEFormat.DS1) { bw.Pad(0x10); } } bw.FillVarint("SibName", bw.Position); if (!string.IsNullOrEmpty(SibName)) { bw.WriteUTF16(SibName, true); if (Format != TAEFormat.DS1) { bw.Pad(0x10); } } Animations.Sort((a1, a2) => a1.ID.CompareTo(a2.ID)); var animOffsets = new List <long>(Animations.Count); if (Animations.Count == 0) { bw.FillVarint("AnimsOffset", 0); } else { bw.FillVarint("AnimsOffset", bw.Position); for (int i = 0; i < Animations.Count; i++) { animOffsets.Add(bw.Position); Animations[i].WriteHeader(bw, i); } } bw.FillVarint("AnimGroupsOffset", bw.Position); bw.ReserveVarint("AnimGroupsCount"); bw.ReserveVarint("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.WriteVarint(animOffsets[firstIndex]); groupCount++; } bw.FillVarint("AnimGroupsCount", groupCount); if (groupCount == 0) { bw.FillVarint("AnimGroupsOffset", 0); } else { bw.FillVarint("AnimGroupsOffset", groupStart); } if (Animations.Count == 0) { bw.FillVarint("FirstAnimOffset", 0); } else { bw.FillVarint("FirstAnimOffset", bw.Position); for (int i = 0; i < Animations.Count; i++) { Animations[i].WriteBody(bw, i, Format); } } for (int i = 0; i < Animations.Count; i++) { Animation anim = Animations[i]; anim.WriteAnimFile(bw, i, Format); Dictionary <float, long> timeOffsets = anim.WriteTimes(bw, i, Format); List <long> eventHeaderOffsets = anim.WriteEventHeaders(bw, i, timeOffsets); anim.WriteEventData(bw, i, Format); anim.WriteEventGroupHeaders(bw, i, Format); anim.WriteEventGroupData(bw, i, eventHeaderOffsets, Format); } bw.FillInt32("FileSize", (int)bw.Position); }
public void Write(BinaryWriterEx bw) { bw.WriteUInt32(Signature); bw.WriteByte(0x09); bw.WriteASCII(ClassName, true); }
protected override void Write(BinaryWriterEx bw) { bw.WriteASCII("FXR\0"); bw.WriteInt16((short)0); bw.WriteUInt16((ushort)this.Version); bw.WriteInt32(1); bw.WriteInt32(this.Id); bw.ReserveInt32("Section1Offset"); bw.WriteInt32(1); bw.ReserveInt32("Section2Offset"); bw.WriteInt32(this.RootStateMachine.States.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 (this.Version == Fxr3.FxrVersion.Sekiro) { bw.ReserveInt32("Section12Offset"); bw.WriteInt32(this.Section12S.Count); bw.ReserveInt32("Section13Offset"); bw.WriteInt32(this.Section13S.Count); bw.ReserveInt32("Section14Offset"); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); } bw.FillInt32("Section1Offset", (int)bw.Position); this.RootStateMachine.Write(bw); bw.Pad(16); bw.FillInt32("Section2Offset", (int)bw.Position); this.RootStateMachine.WriteSection2S(bw); bw.Pad(16); bw.FillInt32("Section3Offset", (int)bw.Position); List <Fxr3.FfxState> states = this.RootStateMachine.States; List <Fxr3.FfxTransition> section3S = new List <Fxr3.FfxTransition>(); for (int index = 0; index < states.Count; ++index) { states[index].WriteSection3S(bw, index, section3S); } bw.FillInt32("Section3Count", section3S.Count); bw.Pad(16); bw.FillInt32("Section4Offset", (int)bw.Position); List <Fxr3.FfxEffectCallA> section4S = new List <Fxr3.FfxEffectCallA>(); this.RootEffectCall.Write(bw, section4S); this.RootEffectCall.WriteSection4S(bw, section4S); bw.FillInt32("Section4Count", section4S.Count); bw.Pad(16); bw.FillInt32("Section5Offset", (int)bw.Position); int section5Count = 0; for (int index = 0; index < section4S.Count; ++index) { section4S[index].WriteSection5S(bw, index, ref section5Count); } bw.FillInt32("Section5Count", section5Count); bw.Pad(16); bw.FillInt32("Section6Offset", (int)bw.Position); section5Count = 0; List <Fxr3.FfxActionCall> section6S = new List <Fxr3.FfxActionCall>(); for (int index = 0; index < section4S.Count; ++index) { section4S[index].WriteSection6S(bw, index, ref section5Count, section6S); } bw.FillInt32("Section6Count", section6S.Count); bw.Pad(16); bw.FillInt32("Section7Offset", (int)bw.Position); List <Fxr3.FfxProperty> section7S = new List <Fxr3.FfxProperty>(); for (int index = 0; index < section6S.Count; ++index) { section6S[index].WriteSection7S(bw, index, section7S); } bw.FillInt32("Section7Count", section7S.Count); bw.Pad(16); bw.FillInt32("Section8Offset", (int)bw.Position); List <Fxr3.Section8> section8S = new List <Fxr3.Section8>(); for (int index = 0; index < section7S.Count; ++index) { section7S[index].WriteSection8S(bw, index, section8S); } bw.FillInt32("Section8Count", section8S.Count); bw.Pad(16); bw.FillInt32("Section9Offset", (int)bw.Position); List <Fxr3.Section9> section9S = new List <Fxr3.Section9>(); for (int index = 0; index < section8S.Count; ++index) { section8S[index].WriteSection9S(bw, index, section9S); } bw.FillInt32("Section9Count", section9S.Count); bw.Pad(16); bw.FillInt32("Section10Offset", (int)bw.Position); List <Fxr3.Section10> section10S = new List <Fxr3.Section10>(); for (int index = 0; index < section6S.Count; ++index) { section6S[index].WriteSection10S(bw, index, section10S); } bw.FillInt32("Section10Count", section10S.Count); bw.Pad(16); bw.FillInt32("Section11Offset", (int)bw.Position); int section11Count = 0; for (int index = 0; index < section3S.Count; ++index) { section3S[index].WriteSection11S(bw, index, ref section11Count); } for (int index = 0; index < section6S.Count; ++index) { section6S[index].WriteSection11S(bw, index, ref section11Count); } for (int index = 0; index < section7S.Count; ++index) { section7S[index].WriteSection11S(bw, index, ref section11Count); } for (int index = 0; index < section8S.Count; ++index) { section8S[index].WriteSection11S(bw, index, ref section11Count); } for (int index = 0; index < section9S.Count; ++index) { section9S[index].WriteSection11S(bw, index, ref section11Count); } for (int index = 0; index < section10S.Count; ++index) { section10S[index].WriteSection11S(bw, index, ref section11Count); } bw.FillInt32("Section11Count", section11Count); bw.Pad(16); if (this.Version != Fxr3.FxrVersion.Sekiro) { return; } bw.FillInt32("Section12Offset", (int)bw.Position); bw.WriteInt32s((IList <int>) this.Section12S); bw.Pad(16); bw.FillInt32("Section13Offset", (int)bw.Position); bw.WriteInt32s((IList <int>) this.Section13S); bw.Pad(16); bw.FillInt32("Section14Offset", (int)bw.Position); }
public void WriteWithContext(BinaryWriterEx bw, EzSembleContext context) { bw.WriteASCII(ESDMagicByFormat[FormatType]); bw.BigEndian = (FormatType == ESDFormatType.BigEndian32Bit || FormatType == ESDFormatType.BigEndian64Bit); context.IsBigEndian = bw.BigEndian; 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(Unk6C); 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(context, 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]; cond.MetaRefID = conditionOffsets[cond] = bw.Position - dataStart; cond.WriteHeader(context, 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(context, bw, LongFormat, groupID, stateID, dataStart, commands); } for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteCommandCalls(context, 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(context, 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(context, bw, LongFormat, groupID, i, dataStart); } } for (int i = 0; i < commands.Count; i++) { commands[i].WriteBytecode(context, 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); } LastSavedHash = bw.GetMD5HashOfStream(); Metadata = ESDMetadata.Generate(this); }