internal void WriteData(BinaryWriterEx bw, int animIndex, int eventIndex, TAEFormat format) { CopyParametersToBytes(bw.BigEndian); bw.FillVarint($"EventDataOffset{animIndex}:{eventIndex}", bw.Position); bw.WriteInt32(Type); if (format != TAEFormat.DS1) { bw.WriteInt32(Unk04); } if (format == TAEFormat.SDT && Type == 943) { bw.WriteVarint(0); } else { bw.WriteVarint(bw.Position + (bw.VarintLong ? 8 : 4)); } bw.WriteBytes(ParameterBytes); if (format != TAEFormat.DS1) { bw.Pad(0x10); } }
internal Dictionary <float, long> WriteTimes(BinaryWriterEx bw, int animIndex, TAEFormat format) { var times = new SortedSet <float>(); foreach (Event evt in Events) { times.Add(evt.StartTime); times.Add(evt.EndTime); } bw.FillInt32($"TimesCount{animIndex}", times.Count); if (times.Count == 0) { bw.FillVarint($"TimesOffset{animIndex}", 0); } else { bw.FillVarint($"TimesOffset{animIndex}", bw.Position); } var timeOffsets = new Dictionary <float, long>(); foreach (float time in times) { timeOffsets[time] = bw.Position; bw.WriteSingle(time); } if (format != TAEFormat.DS1) { bw.Pad(0x10); } return(timeOffsets); }
internal void WriteEventGroupData(BinaryWriterEx bw, int i, List <long> eventHeaderOffsets, TAEFormat format) { for (int j = 0; j < EventGroups.Count; j++) { EventGroups[j].WriteData(bw, i, j, eventHeaderOffsets, format); } }
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(); }
internal List <long> WriteEventHeaders(BinaryWriterEx bw, int animIndex, Dictionary <float, long> timeOffsets, TAEFormat format) { var eventHeaderOffsets = new List <long>(Events.Count); if (Events.Count > 0) { bw.FillVarint($"EventHeadersOffset{animIndex}", bw.Position); for (int i = 0; i < Events.Count; i++) { eventHeaderOffsets.Add(bw.Position); Events[i].WriteHeader(bw, animIndex, i, timeOffsets, format); } } else { bw.FillVarint($"EventHeadersOffset{animIndex}", 0); } return(eventHeaderOffsets); }
internal void WriteAnimFile(BinaryWriterEx bw, int i, TAEFormat format) { bw.FillVarint($"AnimFileOffset{i}", bw.Position); bw.WriteVarint((int)MiniHeader.Type); bw.ReserveVarint("AnimFileNameOffsetOffset"); if (format == TAEFormat.DES) { bw.Pad(0x10); } bw.FillVarint("AnimFileNameOffsetOffset", bw.Position); 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, format); if (!(format == TAEFormat.DES || 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 (!string.IsNullOrWhiteSpace(AnimFileName)) { bw.WriteUTF16(AnimFileName, true); if (format != TAEFormat.DS1) { bw.Pad(0x10); } } }
internal abstract void WriteInner(BinaryWriterEx bw, TAEFormat format);
internal abstract void ReadInner(BinaryReaderEx br, TAEFormat format);