diff --git a/FinModelUtility/Fin/Fin/src/util/strings/StringUtil.cs b/FinModelUtility/Fin/Fin/src/util/strings/StringUtil.cs index e6bceda88..51c38e169 100644 --- a/FinModelUtility/Fin/Fin/src/util/strings/StringUtil.cs +++ b/FinModelUtility/Fin/Fin/src/util/strings/StringUtil.cs @@ -53,5 +53,10 @@ public static string SubstringUpTo(this string str, string substr) { var indexTo = str.IndexOf(substr); return indexTo >= 0 ? str[..indexTo] : str; } + + public static string SubstringAfter(this string str, string substr) { + var indexTo = str.IndexOf(substr); + return indexTo >= 0 ? str[(indexTo + substr.Length)..] : str; + } } } \ No newline at end of file diff --git a/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs b/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs index b71fc514d..7b48da53d 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/api/DatModelImporter.cs @@ -17,6 +17,7 @@ using fin.model.io.importers; using fin.util.enums; using fin.util.hex; +using fin.util.strings; using gx; @@ -94,9 +95,11 @@ public unsafe IModel ImportModel(DatModelFileBundle modelFileBundle) { var i = 0; foreach (var animationDatSubfile in animationDat.Subfiles) { - foreach (var figaTree in animationDatSubfile - .GetRootNodesOfType()) { + foreach (var (figaTree, figaTreeName) in animationDatSubfile + .GetRootNodesWithNamesOfType()) { var finAnimation = lazyFinAnimations[i++]; + finAnimation.Name = figaTreeName.SubstringAfter("Share_ACTION_") + .SubstringUpTo("_figatree"); finAnimation.FrameCount = (int) figaTree.FrameCount; foreach (var (jObj, trackNode) in primaryDatSubfile.JObjs.Zip( diff --git a/FinModelUtility/Formats/Dat/Dat/src/schema/DatSubfile.cs b/FinModelUtility/Formats/Dat/Dat/src/schema/DatSubfile.cs index e7ba74dca..38c61b4e8 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/schema/DatSubfile.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/schema/DatSubfile.cs @@ -1,6 +1,9 @@ -using dat.schema.animation; +using System.Linq; + +using dat.schema.animation; using fin.data.queues; +using fin.io.bundles; using fin.util.linq; using schema.binary; @@ -23,12 +26,36 @@ public class DatSubfile : IBinaryDeserializable { public uint FileSize { get; set; } - public List RootNodes { get; } = new(); + public LinkedList<(IDatNode, string)> RootNodesWithNames { get; } = new(); + + public IEnumerable RootNodes + => this.RootNodesWithNames.Select( + rootNodeAndName => rootNodeAndName.Item1); public IEnumerable GetRootNodesOfType() where TNode : IDatNode => this.RootNodes.WhereIs(); + public IEnumerable<(TNode, string)> GetRootNodesWithNamesOfType() + where TNode : IDatNode + => this.RootNodesWithNames + .SelectWhere<(IDatNode, string), (TNode, string)>(IsOfType_); + + private static bool IsOfType_( + (IDatNode, string) nodeWithName, + out (TNode, string) outNodeWithName) + where TNode : IDatNode { + var (node, name) = nodeWithName; + if (node is TNode datNode) { + outNodeWithName = (datNode, name); + return true; + } + + outNodeWithName = default; + return false; + } + + public IEnumerable RootJObjs => this.GetRootNodesOfType(); private readonly Dictionary jObjByOffset_ = new(); @@ -97,28 +124,33 @@ private void ReadRootNodeObjects_(IBinaryReader br) { var jObjQueue = new FinTuple2Queue(); - this.RootNodes.Clear(); + this.RootNodesWithNames.Clear(); foreach (var rootNode in this.rootNodes_) { var rootNodeOffset = rootNode.Data.DataOffset; br.Position = rootNodeOffset; + IDatNode? node = null; switch (rootNode.Type) { case RootNodeType.JOBJ: { var jObj = br.ReadNew(); - this.RootNodes.Add(jObj); + node = jObj; jObjQueue.Enqueue((rootNodeOffset, jObj)); break; } case RootNodeType.MATANIM_JOINT: { - this.RootNodes.Add(br.ReadNew()); + node = br.ReadNew(); break; } case RootNodeType.FIGATREE: { - this.RootNodes.Add(br.ReadNew()); + node = br.ReadNew(); break; } } + + if (node != null) { + this.RootNodesWithNames.AddLast((node, rootNode.Name)); + } } br.PopLocalSpace(); diff --git a/FinModelUtility/Formats/Dat/Dat/src/schema/animation/DatKeyframesUtil.cs b/FinModelUtility/Formats/Dat/Dat/src/schema/animation/DatKeyframesUtil.cs index 14eb86cbf..601bc8f34 100644 --- a/FinModelUtility/Formats/Dat/Dat/src/schema/animation/DatKeyframesUtil.cs +++ b/FinModelUtility/Formats/Dat/Dat/src/schema/animation/DatKeyframesUtil.cs @@ -5,6 +5,7 @@ public static class DatKeyframesUtil { /// /// Shamelessly stolen from: /// https://github.com/Ploaj/HSDLib/blob/93a906444f34951c6eed4d8c6172bba43d4ada98/HSDRaw/Tools/FOBJ_Decoder.cs#L22 + /// https://github.com/Ploaj/HSDLib/blob/93a906444f34951c6eed4d8c6172bba43d4ada98/HSDRaw/Tools/FOBJ_Player.cs#L162 /// public static void ReadKeyframes( IBinaryReader br, @@ -41,21 +42,30 @@ public static void ReadKeyframes( break; } + var previousInterpolationType = GxInterpolationType.Constant; + float value = 0; + float tangent = 0; + int time = 0; + for (int i = 0; i < numOfKey; i++) { - float value = 0; - float? tangent = null; - int time = 1; switch (interpolation) { case GxInterpolationType.Constant: value = ParseFloat_(sbr, valueFormat, valueScale); + if (previousInterpolationType != GxInterpolationType.Slp) { + tangent = 0; + } time = ReadPacked_(sbr); break; case GxInterpolationType.Linear: value = ParseFloat_(sbr, valueFormat, valueScale); + if (previousInterpolationType != GxInterpolationType.Slp) { + tangent = 0; + } time = ReadPacked_(sbr); break; case GxInterpolationType.Spl0: value = ParseFloat_(sbr, valueFormat, valueScale); + tangent = 0; time = ReadPacked_(sbr); break; case GxInterpolationType.Spl: @@ -65,9 +75,11 @@ public static void ReadKeyframes( break; case GxInterpolationType.Slp: tangent = ParseFloat_(sbr, tangentFormat, tangentScale); + time = 0; break; case GxInterpolationType.Key: value = ParseFloat_(sbr, valueFormat, valueScale); + time = 0; break; default: throw new Exception("Unknown Interpolation Type " + @@ -78,6 +90,8 @@ public static void ReadKeyframes( keyframes.AddLast((frame, value, tangent)); } frame += time; + + previousInterpolationType = interpolation; } } });