internal void WriteAnimFile(BinaryWriterEx bw, int i, TAEFormat format) { bw.FillVarint($"AnimFileOffset{i}", bw.Position); bw.WriteVarint((int)MiniHeader.Type); bw.WriteVarint(bw.Position + (bw.VarintLong ? 8 : 4)); bw.ReserveVarint("AnimFileNameOffset"); //if (AnimFileReference) //{ // bw.WriteInt32(ReferenceID); // bw.WriteBoolean(UnkReferenceFlag1); // bw.WriteBoolean(ReferenceIsTAEOnly); // bw.WriteBoolean(ReferenceIsHKXOnly); // bw.WriteBoolean(LoopByDefault); //} //else //{ // bw.WriteBoolean(UnkReferenceFlag1); // bw.WriteBoolean(ReferenceIsTAEOnly); // bw.WriteBoolean(ReferenceIsHKXOnly); // bw.WriteBoolean(LoopByDefault); // bw.WriteInt32(ReferenceID); //} MiniHeader.WriteInner(bw); if (format != TAEFormat.DS1) { bw.WriteVarint(0); bw.WriteVarint(0); } else { bw.WriteVarint(0); if (MiniHeader.Type == MiniHeaderType.ImportOtherAnim) { bw.WriteVarint(0); } } bw.FillVarint("AnimFileNameOffset", bw.Position); if (AnimFileName != "") { bw.WriteUTF16(AnimFileName, true); if (format != TAEFormat.DS1) { bw.Pad(0x10); } } }
internal Animation(BinaryReaderEx br, TAEFormat format, out bool lastEventNeedsParamGen, out long animFileOffset, out long lastEventParamOffset) { lastEventNeedsParamGen = false; lastEventParamOffset = 0; ID = br.ReadVarint(); long offset = br.ReadVarint(); br.StepIn(offset); { int eventCount; long eventHeadersOffset; int eventGroupCount; long eventGroupsOffset; long timesOffset; if (format == TAEFormat.DS1) { eventCount = br.ReadInt32(); eventHeadersOffset = br.ReadVarint(); eventGroupCount = br.ReadInt32(); eventGroupsOffset = br.ReadVarint(); br.ReadInt32(); // Times count timesOffset = br.ReadVarint(); // Times offset animFileOffset = br.ReadVarint(); //For DeS assert 5 int32 == 0 here } else { eventHeadersOffset = br.ReadVarint(); eventGroupsOffset = br.ReadVarint(); timesOffset = br.ReadVarint(); // Times offset animFileOffset = br.ReadVarint(); eventCount = br.ReadInt32(); eventGroupCount = br.ReadInt32(); br.ReadInt32(); // Times count br.AssertInt32(0); } var eventHeaderOffsets = new List <long>(eventCount); var eventParameterOffsets = new List <long>(eventCount); Events = new List <Event>(eventCount); br.StepIn(eventHeadersOffset); { for (int i = 0; i < eventCount; i++) { eventHeaderOffsets.Add(br.Position); Events.Add(Event.Read(br, out long pOffset, format)); eventParameterOffsets.Add(pOffset); if (i > 0) { // Go to previous event's parameters br.StepIn(eventParameterOffsets[i - 1]); { // Read the space between the previous event's parameter start and the start of this event data. long gapBetweenEventParamOffsets = eventParameterOffsets[i] - eventParameterOffsets[i - 1]; // Subtract to account for the current event's type and offset Events[i - 1].ReadParameters(br, (int)(gapBetweenEventParamOffsets - (br.VarintLong ? 16 : 8))); } br.StepOut(); } } } br.StepOut(); if (eventCount > 0) { if (eventGroupsOffset == 0) { lastEventNeedsParamGen = true; lastEventParamOffset = eventParameterOffsets[eventCount - 1]; } else { // Go to last event's parameters br.StepIn(eventParameterOffsets[eventCount - 1]); { // Read the space between the last event's parameter start and the start of the event groups. Events[eventCount - 1].ReadParameters(br, (int)(eventGroupsOffset - eventParameterOffsets[eventCount - 1])); } br.StepOut(); } } EventGroups = new List <EventGroup>(eventGroupCount); br.StepIn(eventGroupsOffset); { for (int i = 0; i < eventGroupCount; i++) { EventGroups.Add(new EventGroup(br, eventHeaderOffsets, format)); } } br.StepOut(); br.StepIn(animFileOffset); { var miniHeaderType = br.ReadEnum32 <MiniHeaderType>(); if (br.VarintLong) { br.AssertInt32(0); } br.AssertVarint(br.Position + (br.VarintLong ? 8 : 4)); long animFileNameOffset = br.ReadVarint(); //if (AnimFileReference) //{ // ReferenceID = br.ReadInt32(); // UnkReferenceFlag1 = br.ReadBoolean(); // ReferenceIsTAEOnly = br.ReadBoolean(); // ReferenceIsHKXOnly = br.ReadBoolean(); // LoopByDefault = br.ReadBoolean(); //} //else //{ // UnkReferenceFlag1 = br.ReadBoolean(); // ReferenceIsTAEOnly = br.ReadBoolean(); // ReferenceIsHKXOnly = br.ReadBoolean(); // LoopByDefault = br.ReadBoolean(); // ReferenceID = br.ReadInt32(); //} if (miniHeaderType == MiniHeaderType.Standard) { MiniHeader = new AnimMiniHeader.Standard(); } else if (miniHeaderType == MiniHeaderType.ImportOtherAnim) { MiniHeader = new AnimMiniHeader.ImportOtherAnim(); } else { throw new NotImplementedException($"{nameof(AnimMiniHeader)} type not implemented yet."); } MiniHeader.ReadInner(br); if (format != TAEFormat.DS1) { br.AssertVarint(0); br.AssertVarint(0); } else { br.AssertVarint(0); if (MiniHeader.Type == MiniHeaderType.ImportOtherAnim) { br.AssertVarint(0); } } if (animFileNameOffset < br.Length && animFileNameOffset != timesOffset) { if (br.GetInt64(animFileNameOffset) != 1) { var floatCheck = br.GetSingle(animFileNameOffset); if (!(floatCheck >= 0.016667f && floatCheck <= 100)) { AnimFileName = br.GetUTF16(animFileNameOffset); } } } AnimFileName = AnimFileName ?? ""; // When Reference is false, there's always a filename. // When true, there's usually not, but sometimes there is, and I cannot figure out why. // Thus, this stupid hack to achieve byte-perfection. //var animNameCheck = AnimFileName.ToLower(); //if (!(animNameCheck.EndsWith(".hkt") // || (format == TAEFormat.SDT && animNameCheck.EndsWith("hkt")) // || animNameCheck.EndsWith(".hkx") // || animNameCheck.EndsWith(".sib") // || animNameCheck.EndsWith(".hkxwin"))) // AnimFileName = ""; } br.StepOut(); } br.StepOut(); }