private AnimationRef LoadAnimationFromOffset(DSBinaryReader bin, int offset, int id, Dictionary <int, List <int> > debugUnkTypesReport) { int oldOffset = (int)bin.BaseStream.Position; bin.BaseStream.Seek(offset, SeekOrigin.Begin); var anim = new AnimationRef(); anim.ID = id; try { Dictionary <int, TimeActEventBase> eventOffsetLookupForEventGroup = new Dictionary <int, TimeActEventBase>(); int eventCount = bin.ReadInt32(); int eventHeadersOffset = bin.ReadInt32(); int eventGroupCount = bin.ReadInt32(); int eventGroupOffset = bin.ReadInt32(); var timeConstantsCount = bin.ReadInt32(); var timeConstantsOffset = bin.ReadInt32(); int animFileOffset = bin.ReadInt32(); if (Header.IsBigEndian) { bin.AssertInt32(0); bin.AssertInt32(0); bin.AssertInt32(0); bin.AssertInt32(0); bin.AssertInt32(0); } if (eventCount > 0) { for (int i = 0; i < eventCount; i++) { var thisEventOffset = eventHeadersOffset + (EventHeaderSize * i); //lazily seek to the start of each event manually. bin.BaseStream.Seek(thisEventOffset, SeekOrigin.Begin); int startTimeOffset = bin.ReadInt32(); int endTimeOffset = bin.ReadInt32(); int eventBodyOffset = bin.ReadInt32(); //if (EventHeaderSize >= 0x10) //{ // int unk = bin.ReadInt32(); // throw new Exception(); //} float startTime = -1; float endTime = -1; bin.StepIn(startTimeOffset); { startTime = bin.ReadSingle(); } bin.StepOut(); bin.StepIn(endTimeOffset); { endTime = bin.ReadSingle(); } bin.StepOut(); bin.StepIn(eventBodyOffset); { int eventTypeInt = bin.ReadInt32(); TimeActEventType eventType = (TimeActEventType)eventTypeInt; int eventParamOffset = bin.ReadInt32(); if (eventParamOffset <= 0) { var newEvent = TimeActEventBase.GetNewEvent(eventType, startTime, endTime); newEvent.Index = anim.EventList.Count; anim.EventList.Add(newEvent); eventOffsetLookupForEventGroup.Add(thisEventOffset, newEvent); } else { bin.StepIn(eventParamOffset); { var newEvent = TimeActEventBase.GetNewEvent(eventType, startTime, endTime); if (newEvent == null) { if (!debugUnkTypesReport.ContainsKey(eventTypeInt)) { debugUnkTypesReport.Add(eventTypeInt, new List <int>()); } if (i < eventCount - 1) { bin.StepIn(eventHeadersOffset + (EventHeaderSize * (i + 1))); { bin.ReadInt32(); //startTimeOffset bin.ReadInt32(); //endTimeOffset var nextEventBodyOffset = bin.ReadInt32(); int thisUnkParamByteCount = nextEventBodyOffset - eventParamOffset; if (!debugUnkTypesReport[eventTypeInt].Contains(thisUnkParamByteCount)) { debugUnkTypesReport[eventTypeInt].Add(thisUnkParamByteCount); } //bin.StepIn(nextEventBodyOffset); //{ // bin.ReadInt32();//eventType // var nextEventParamOffset = bin.ReadInt32(); // int thisUnkParamByteCount = nextEventParamOffset - eventParamOffset; // debugUnkTypesReport[eventTypeInt].Add(thisUnkParamByteCount); //} //bin.StepOut(); } bin.StepOut(); } else { //debugUnkTypesReport[eventTypeInt].Add(-1); } } else { newEvent.ReadParameters(bin); newEvent.Index = anim.EventList.Count; anim.EventList.Add(newEvent); eventOffsetLookupForEventGroup.Add(thisEventOffset, newEvent); } } bin.StepOut(); } } bin.StepOut(); } } if (eventGroupCount > 0 && eventGroupOffset > 0) { bin.StepIn(eventGroupOffset); { for (int i = 0; i < eventGroupCount; i++) { var group = new TimeActEventGroup(); int groupEntryCount = bin.ReadInt32(); int groupPointerOffset = bin.ReadInt32(); int groupTypeOffset = bin.ReadInt32(); bin.StepIn(groupPointerOffset); { for (int j = 0; j < groupEntryCount; j++) { var groupEventOffset = bin.ReadInt32(); if (eventOffsetLookupForEventGroup.ContainsKey(groupEventOffset)) { var thisGroupEvent = eventOffsetLookupForEventGroup[groupEventOffset]; group.Events.Add(thisGroupEvent); } } } bin.StepOut(); bin.StepIn(groupTypeOffset); { group.GeneralType = (TimeActEventType)bin.ReadInt32(); } bin.StepOut(); anim.EventGroupList.Add(group); } } bin.StepOut(); } bin.BaseStream.Seek(animFileOffset, SeekOrigin.Begin); int fileType = bin.ReadInt32(); if (fileType == 0) { anim.IsReference = false; int dataOffset = bin.ReadInt32(); //bin.BaseStream.Seek(dataOffset, SeekOrigin.Begin); int nameOffset = -1; if (Header.IsBigEndian) { anim.OriginalAnimID = bin.ReadInt32(); bin.AssertByte(0); anim.TAEDataOnly = bin.ReadBoolean(); anim.UseHKXOnly = bin.ReadBoolean(); anim.IsLoopingObjAnim = bin.ReadBoolean(); nameOffset = bin.ReadInt32(); var secondaryNameOffset = bin.ReadInt32(); } else { nameOffset = bin.ReadInt32(); anim.IsLoopingObjAnim = bin.ReadBoolean(); anim.UseHKXOnly = bin.ReadBoolean(); anim.TAEDataOnly = bin.ReadBoolean(); bin.AssertByte(0); anim.OriginalAnimID = bin.ReadInt32(); bin.AssertInt32(0); } if (nameOffset <= 0) { //throw new Exception("Anim file type was that of a named one but the name pointer was NULL."); } else { bin.BaseStream.Seek(nameOffset, SeekOrigin.Begin); anim.FileName = ReadUnicodeString(bin); } } else if (fileType == 1) { anim.IsReference = true; anim.FileName = null; if (Header.IsBigEndian) { var nullA = bin.ReadInt32(); var nullB = bin.ReadInt32(); var offsetPointingToNextDword = bin.ReadInt32(); var offsetPointingToStartOfNextAnimFileStruct = bin.ReadInt32(); anim.RefAnimID = bin.ReadInt32(); var nullC = bin.ReadInt32(); } else { var offsetPointingToNextDword = bin.ReadInt32(); var offsetPointingToStartOfNextAnimFileStruct = bin.ReadInt32(); anim.RefAnimID = bin.ReadInt32(); var nullA = bin.ReadInt32(); var nullB = bin.ReadInt32(); var nullC = bin.ReadInt32(); } } else { throw new Exception($"Unknown anim file type code: {fileType}"); } return(anim); } catch (EndOfStreamException) { MiscUtil.PrintlnDX($"Warning: reached end of file while parsing animation {id}; data may not be complete.", ConsoleColor.Yellow); //if (!MiscUtil.ConsolePrompYesNo("Would you like to continue loading the file and run the risk of " + // "accidentally outputting a file that might be missing some of its original data?")) //{ // throw new LoadAbortedException(); //} //else //{ // return a; //} return(anim); } finally { bin.BaseStream.Seek(oldOffset, SeekOrigin.Begin); } }