TOS code refactor

This commit is contained in:
Jeremy Pritts 2023-06-03 16:06:22 -04:00
parent bf5b077086
commit 6cb2f5d6fd
10 changed files with 237 additions and 222 deletions

View File

@ -0,0 +1,44 @@
using AssetRipper.Assets;
using AssetRipper.Assets.Bundles;
using AssetRipper.SourceGenerated.Classes.ClassID_111;
using AssetRipper.SourceGenerated.Classes.ClassID_90;
using AssetRipper.SourceGenerated.Classes.ClassID_95;
namespace AssetRipper.Processing.AnimationClips;
public sealed class AnimationCache
{
public IReadOnlyList<IAvatar> CachedAvatars { get; }
public IReadOnlyList<IAnimator> CachedAnimators { get; }
public IReadOnlyList<IAnimation> CachedAnimations { get; }
private AnimationCache(Bundle bundle)
{
List<IAvatar> cachedAvatars = new();
List<IAnimator> cachedAnimators = new();
List<IAnimation> cachedAnimations = new();
foreach (IUnityObjectBase asset in bundle.FetchAssetsInHierarchy())
{
switch (asset)
{
case IAvatar avatar:
cachedAvatars.Add(avatar);
break;
case IAnimator animator:
cachedAnimators.Add(animator);
break;
case IAnimation animation:
cachedAnimations.Add(animation);
break;
}
}
CachedAvatars = cachedAvatars;
CachedAnimators = cachedAnimators;
CachedAnimations = cachedAnimations;
}
public static AnimationCache CreateCache(Bundle bundle)
{
return new AnimationCache(bundle);
}
}

View File

@ -0,0 +1,174 @@
using AssetRipper.Assets.Generics;
using AssetRipper.Assets.Metadata;
using AssetRipper.Assets.Utils;
using AssetRipper.SourceGenerated.Classes.ClassID_1;
using AssetRipper.SourceGenerated.Classes.ClassID_111;
using AssetRipper.SourceGenerated.Classes.ClassID_4;
using AssetRipper.SourceGenerated.Classes.ClassID_74;
using AssetRipper.SourceGenerated.Classes.ClassID_90;
using AssetRipper.SourceGenerated.Classes.ClassID_95;
using AssetRipper.SourceGenerated.Extensions;
using AssetRipper.SourceGenerated.Subclasses.GenericBinding;
using AssetRipper.SourceGenerated.Subclasses.Utf8String;
namespace AssetRipper.Processing.AnimationClips;
/// <summary>
/// A CRC32 lookup generator.
/// </summary>
/// <remarks>
/// TOS comes from <see cref="IAvatar.TOS_C90"/>. It presumably means "Table of Strings," but there doesn't seem to be any documentation on it.
/// </remarks>
internal static class TosBuilder
{
private static IReadOnlyDictionary<uint, string> BuildTOS(this IAnimator animator)
{
if (animator.Has_HasTransformHierarchy_C95() && !animator.HasTransformHierarchy_C95)
{
return MakeNewDictionary();
}
return animator.GameObject_C95.GetAsset(animator.Collection).BuildTOS();
}
public static IReadOnlyDictionary<uint, string> FindTOS(this IAnimationClip clip, AnimationCache cache)
{
Dictionary<uint, string> tos = MakeNewDictionary();
foreach (IAvatar avatar in cache.CachedAvatars)
{
if (clip.AddAvatarTOS(avatar, tos))
{
return tos;
}
}
foreach (IAnimator animator in cache.CachedAnimators)
{
if (animator.ContainsAnimationClip(clip) && clip.AddAnimatorTOS(animator, tos))
{
return tos;
}
}
foreach (IAnimation animation in cache.CachedAnimations)
{
if (animation.ContainsAnimationClip(clip) && clip.AddAnimationTOS(animation, tos))
{
return tos;
}
}
return tos;
}
private static Dictionary<uint, string> MakeNewDictionary()
{
return new() { { 0, string.Empty } };
}
private static bool AddAvatarTOS(this IAnimationClip clip, IAvatar avatar, Dictionary<uint, string> tos)
{
return clip.AddTOS(avatar.TOS_C90, tos);
}
private static bool AddAnimatorTOS(this IAnimationClip clip, IAnimator animator, Dictionary<uint, string> tos)
{
IAvatar? avatar = animator.Avatar_C95P;
if (avatar != null && clip.AddAvatarTOS(avatar, tos))
{
return true;
}
IReadOnlyDictionary<uint, string> animatorTOS = animator.BuildTOS();
return clip.AddTOS(animatorTOS, tos);
}
private static bool AddAnimationTOS(this IAnimationClip clip, IAnimation animation, Dictionary<uint, string> tos)
{
IGameObject go = animation.GameObject_C8.GetAsset(animation.Collection);
IReadOnlyDictionary<uint, string> animationTOS = go.BuildTOS();
return clip.AddTOS(animationTOS, tos);
}
private static bool AddTOS(this IAnimationClip clip, IReadOnlyDictionary<uint, string> src, Dictionary<uint, string> dest)
{
if (!clip.Has_ClipBindingConstant_C74())
{
return false;
}
AccessListBase<IGenericBinding> bindings = clip.ClipBindingConstant_C74.GenericBindings;
bool allFound = true;
for (int i = 0; i < bindings.Count; i++)
{
uint bindingPath = bindings[i].Path;
if (src.TryGetValue(bindingPath, out string? path))
{
dest[bindingPath] = path;
}
else if (bindingPath != 0)
{
allFound = false;
}
}
return allFound;
}
private static bool AddTOS(this IAnimationClip clip, AssetDictionary<uint, Utf8String> src, Dictionary<uint, string> dest)
{
if (!clip.Has_ClipBindingConstant_C74())
{
return false;
}
AccessListBase<IGenericBinding> bindings = clip.ClipBindingConstant_C74.GenericBindings;
bool allFound = true;
for (int i = 0; i < bindings.Count; i++)
{
uint bindingPath = bindings[i].Path;
if (src.TryGetValue(bindingPath, out Utf8String? path))
{
dest[bindingPath] = path.String;
}
else if (bindingPath != 0)
{
allFound = false;
}
}
return allFound;
}
private static IReadOnlyDictionary<uint, string> BuildTOS(this IGameObject gameObject)
{
Dictionary<uint, string> tos = MakeNewDictionary();
gameObject.BuildTOS(gameObject, string.Empty, tos);
return tos;
}
private static void BuildTOS(this IGameObject gameObject, IGameObject parent, string parentPath, Dictionary<uint, string> tos)
{
ITransform transform = parent.GetTransform();
foreach (ITransform? childTransform in transform.Children_C4P)
{
IGameObject child = childTransform?.GameObject_C4P ?? throw new NullReferenceException();
string path = string.IsNullOrEmpty(parentPath)
? child.NameString
: $"{parentPath}/{child.NameString}";
uint pathHash = CrcUtils.CalculateDigestUTF8(path);
tos[pathHash] = path;
gameObject.BuildTOS(child, path, tos);
}
}
}

View File

@ -1,41 +0,0 @@
using AssetRipper.Assets;
using AssetRipper.Assets.Bundles;
using AssetRipper.SourceGenerated.Classes.ClassID_111;
using AssetRipper.SourceGenerated.Classes.ClassID_90;
using AssetRipper.SourceGenerated.Classes.ClassID_95;
namespace AssetRipper.SourceGenerated.Extensions
{
public class AnimationCache
{
public List<IAvatar> CachedAvatars = new();
public List<IAnimator> CachedAnimators = new();
public List<IAnimation> CachedAnimations = new();
private void CacheAssets(Bundle bundle)
{
foreach (IUnityObjectBase asset in bundle.FetchAssetsInHierarchy())
{
switch (asset)
{
case IAvatar avatar:
CachedAvatars.Add(avatar);
break;
case IAnimator animator:
CachedAnimators.Add(animator);
break;
case IAnimation animation:
CachedAnimations.Add(animation);
break;
}
}
}
public static AnimationCache CreateCache(Bundle bundle)
{
AnimationCache cache = new();
cache.CacheAssets(bundle);
return cache;
}
}
}

View File

@ -1,13 +1,9 @@
using AssetRipper.Assets; using AssetRipper.Assets;
using AssetRipper.Assets.Generics;
using AssetRipper.Assets.Metadata; using AssetRipper.Assets.Metadata;
using AssetRipper.SourceGenerated.Classes.ClassID_1; using AssetRipper.SourceGenerated.Classes.ClassID_1;
using AssetRipper.SourceGenerated.Classes.ClassID_111; using AssetRipper.SourceGenerated.Classes.ClassID_111;
using AssetRipper.SourceGenerated.Classes.ClassID_74; using AssetRipper.SourceGenerated.Classes.ClassID_74;
using AssetRipper.SourceGenerated.Classes.ClassID_90;
using AssetRipper.SourceGenerated.Classes.ClassID_95; using AssetRipper.SourceGenerated.Classes.ClassID_95;
using AssetRipper.SourceGenerated.Subclasses.GenericBinding;
using AssetRipper.SourceGenerated.Subclasses.Utf8String;
namespace AssetRipper.SourceGenerated.Extensions namespace AssetRipper.SourceGenerated.Extensions
{ {
@ -36,14 +32,14 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
if (asset is IAnimator animator) if (asset is IAnimator animator)
{ {
if (clip.IsAnimatorContainsClip(animator)) if (animator.ContainsAnimationClip(clip))
{ {
yield return animator.GameObject_C8.GetAsset(animator.Collection); yield return animator.GameObject_C8.GetAsset(animator.Collection);
} }
} }
else if (asset is IAnimation animation) else if (asset is IAnimation animation)
{ {
if (clip.IsAnimationContainsClip(animation)) if (animation.ContainsAnimationClip(clip))
{ {
yield return animation.GameObject_C8.GetAsset(animation.Collection); yield return animation.GameObject_C8.GetAsset(animation.Collection);
} }
@ -52,125 +48,5 @@ namespace AssetRipper.SourceGenerated.Extensions
yield break; yield break;
} }
private static bool IsAnimatorContainsClip(this IAnimationClip clip, IAnimator animator)
{
return animator.IsContainsAnimationClip(clip);
}
private static bool IsAnimationContainsClip(this IAnimationClip clip, IAnimation animation)
{
return animation.IsContainsAnimationClip(clip);
}
public static IReadOnlyDictionary<uint, string> FindTOS(this IAnimationClip clip, AnimationCache cache)
{
Dictionary<uint, string> tos = new() { { 0, string.Empty } };
foreach (IAvatar avatar in cache.CachedAvatars)
{
if (clip.AddAvatarTOS(avatar, tos))
{
return tos;
}
}
foreach (IAnimator animator in cache.CachedAnimators)
{
if (clip.IsAnimatorContainsClip(animator) && clip.AddAnimatorTOS(animator, tos))
{
return tos;
}
}
foreach (IAnimation animation in cache.CachedAnimations)
{
if (clip.IsAnimationContainsClip(animation) && clip.AddAnimationTOS(animation, tos))
{
return tos;
}
}
return tos;
}
private static bool AddAvatarTOS(this IAnimationClip clip, IAvatar avatar, Dictionary<uint, string> tos)
{
return clip.AddTOS(avatar.TOS_C90, tos);
}
private static bool AddAnimatorTOS(this IAnimationClip clip, IAnimator animator, Dictionary<uint, string> tos)
{
IAvatar? avatar = animator.Avatar_C95P;
if (avatar != null && clip.AddAvatarTOS(avatar, tos))
{
return true;
}
IReadOnlyDictionary<uint, string> animatorTOS = animator.BuildTOS();
return clip.AddTOS(animatorTOS, tos);
}
private static bool AddAnimationTOS(this IAnimationClip clip, IAnimation animation, Dictionary<uint, string> tos)
{
IGameObject go = animation.GameObject_C8.GetAsset(animation.Collection);
IReadOnlyDictionary<uint, string> animationTOS = go.BuildTOS();
return clip.AddTOS(animationTOS, tos);
}
private static bool AddTOS(this IAnimationClip clip, IReadOnlyDictionary<uint, string> src, Dictionary<uint, string> dest)
{
if (!clip.Has_ClipBindingConstant_C74())
{
return false;
}
AccessListBase<IGenericBinding> bindings = clip.ClipBindingConstant_C74.GenericBindings;
bool allFound = true;
for (int i = 0; i < bindings.Count; i++)
{
uint bindingPath = bindings[i].Path;
if (src.TryGetValue(bindingPath, out string? path))
{
dest[bindingPath] = path;
}
else if (bindingPath != 0)
{
allFound = false;
}
}
return allFound;
}
private static bool AddTOS(this IAnimationClip clip, AssetDictionary<uint, Utf8String> src, Dictionary<uint, string> dest)
{
if (!clip.Has_ClipBindingConstant_C74())
{
return false;
}
AccessListBase<IGenericBinding> bindings = clip.ClipBindingConstant_C74.GenericBindings;
bool allFound = true;
for (int i = 0; i < bindings.Count; i++)
{
uint bindingPath = bindings[i].Path;
if (src.TryGetValue(bindingPath, out Utf8String? path))
{
dest[bindingPath] = path.String;
}
else if (bindingPath != 0)
{
allFound = false;
}
}
return allFound;
}
} }
} }

View File

@ -8,7 +8,7 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class AnimationExtensions public static class AnimationExtensions
{ {
public static bool IsContainsAnimationClip(this IAnimation animation, IAnimationClip clip) public static bool ContainsAnimationClip(this IAnimation animation, IAnimationClip clip)
{ {
foreach (IPPtr_AnimationClip clipPtr in animation.Animations_C111) foreach (IPPtr_AnimationClip clipPtr in animation.Animations_C111)
{ {

View File

@ -31,7 +31,7 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class AnimatorControllerExtensions public static class AnimatorControllerExtensions
{ {
public static bool IsContainsAnimationClip(this IAnimatorController controller, IAnimationClip clip) public static bool ContainsAnimationClip(this IAnimatorController controller, IAnimationClip clip)
{ {
foreach (IPPtr_AnimationClip clipPtr in controller.AnimationClips_C91) foreach (IPPtr_AnimationClip clipPtr in controller.AnimationClips_C91)
{ {

View File

@ -10,22 +10,22 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class AnimatorExtensions public static class AnimatorExtensions
{ {
public static bool IsContainsAnimationClip(this IAnimator animator, IAnimationClip clip) public static bool ContainsAnimationClip(this IAnimator animator, IAnimationClip clip)
{ {
if (animator.Has_Controller_C95_PPtr_AnimatorController_4_0_0()) if (animator.Has_Controller_C95_PPtr_AnimatorController_4_0_0())
{ {
IAnimatorController? controller = animator.Controller_C95_PPtr_AnimatorController_4_0_0P; IAnimatorController? controller = animator.Controller_C95_PPtr_AnimatorController_4_0_0P;
return controller is not null && controller.IsContainsAnimationClip(clip); return controller is not null && controller.ContainsAnimationClip(clip);
} }
else if (animator.Has_Controller_C95_PPtr_RuntimeAnimatorController_4_3_0()) else if (animator.Has_Controller_C95_PPtr_RuntimeAnimatorController_4_3_0())
{ {
IRuntimeAnimatorController? controller = animator.Controller_C95_PPtr_RuntimeAnimatorController_4_3_0P; IRuntimeAnimatorController? controller = animator.Controller_C95_PPtr_RuntimeAnimatorController_4_3_0P;
return controller is not null && controller.IsContainsAnimationClip(clip); return controller is not null && controller.ContainsAnimationClip(clip);
} }
else if (animator.Has_Controller_C95_PPtr_RuntimeAnimatorController_5_0_0()) else if (animator.Has_Controller_C95_PPtr_RuntimeAnimatorController_5_0_0())
{ {
IRuntimeAnimatorController? controller = animator.Controller_C95_PPtr_RuntimeAnimatorController_5_0_0P; IRuntimeAnimatorController? controller = animator.Controller_C95_PPtr_RuntimeAnimatorController_5_0_0P;
return controller is not null && controller.IsContainsAnimationClip(clip); return controller is not null && controller.ContainsAnimationClip(clip);
} }
else else
{ {
@ -33,16 +33,6 @@ namespace AssetRipper.SourceGenerated.Extensions
} }
} }
public static IReadOnlyDictionary<uint, string> BuildTOS(this IAnimator animator)
{
if (animator.Has_HasTransformHierarchy_C95() && !animator.HasTransformHierarchy_C95)
{
return new Dictionary<uint, string>() { { 0, string.Empty } };
}
return animator.GameObject_C95.GetAsset(animator.Collection).BuildTOS();
}
public static AnimatorUpdateMode GetUpdateMode(this IAnimator animator) public static AnimatorUpdateMode GetUpdateMode(this IAnimator animator)
{ {
return animator.Has_UpdateMode_C95() ? animator.UpdateMode_C95E : AnimatorUpdateMode.Normal; return animator.Has_UpdateMode_C95() ? animator.UpdateMode_C95E : AnimatorUpdateMode.Normal;

View File

@ -8,7 +8,7 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class AnimatorOverrideControllerExtensions public static class AnimatorOverrideControllerExtensions
{ {
public static bool IsContainsAnimationClip(this IAnimatorOverrideController controller, IAnimationClip clip) public static bool ContainsAnimationClip(this IAnimatorOverrideController controller, IAnimationClip clip)
{ {
foreach (IAnimationClipOverride overClip in controller.Clips_C221) foreach (IAnimationClipOverride overClip in controller.Clips_C221)
{ {
@ -24,7 +24,7 @@ namespace AssetRipper.SourceGenerated.Extensions
IRuntimeAnimatorController? baseController = controller.Controller_C221P; IRuntimeAnimatorController? baseController = controller.Controller_C221P;
if (baseController != null) if (baseController != null)
{ {
return baseController.IsContainsAnimationClip(clip); return baseController.ContainsAnimationClip(clip);
} }
return false; return false;
} }

View File

@ -1,6 +1,5 @@
using AssetRipper.Assets.Generics; using AssetRipper.Assets.Generics;
using AssetRipper.Assets.Metadata; using AssetRipper.Assets.Metadata;
using AssetRipper.Assets.Utils;
using AssetRipper.SourceGenerated.Classes.ClassID_1; using AssetRipper.SourceGenerated.Classes.ClassID_1;
using AssetRipper.SourceGenerated.Classes.ClassID_18; using AssetRipper.SourceGenerated.Classes.ClassID_18;
using AssetRipper.SourceGenerated.Classes.ClassID_2; using AssetRipper.SourceGenerated.Classes.ClassID_2;
@ -237,32 +236,6 @@ namespace AssetRipper.SourceGenerated.Extensions
} }
} }
public static IReadOnlyDictionary<uint, string> BuildTOS(this IGameObject gameObject)
{
Dictionary<uint, string> tos = new() { { 0, string.Empty } };
gameObject.BuildTOS(gameObject, string.Empty, tos);
return tos;
}
private static void BuildTOS(this IGameObject gameObject, IGameObject parent, string parentPath, Dictionary<uint, string> tos)
{
ITransform transform = parent.GetTransform();
foreach (ITransform? childTransform in transform.Children_C4P)
{
IGameObject child = childTransform?.GameObject_C4P ?? throw new NullReferenceException();
string path = string.IsNullOrEmpty(parentPath)
? child.NameString
: $"{parentPath}/{child.NameString}";
uint pathHash = CrcUtils.CalculateDigestUTF8(path);
tos[pathHash] = path;
gameObject.BuildTOS(child, path, tos);
}
}
private sealed class ComponentPairAccessList : AccessListBase<IPPtr_Component> private sealed class ComponentPairAccessList : AccessListBase<IPPtr_Component>
{ {
private readonly AssetList<ComponentPair> referenceList; private readonly AssetList<ComponentPair> referenceList;

View File

@ -7,19 +7,18 @@ namespace AssetRipper.SourceGenerated.Extensions
{ {
public static class RuntimeAnimatorControllerExtensions public static class RuntimeAnimatorControllerExtensions
{ {
public static bool IsContainsAnimationClip(this IRuntimeAnimatorController controller, IAnimationClip clip) public static bool ContainsAnimationClip(this IRuntimeAnimatorController controller, IAnimationClip clip)
{ {
if (controller is IAnimatorController animatorController) return controller switch
{ {
return animatorController.IsContainsAnimationClip(clip); IAnimatorController animatorController => animatorController.ContainsAnimationClip(clip),
} IAnimatorOverrideController overrideController => overrideController.ContainsAnimationClip(clip),
else if (controller is IAnimatorOverrideController overrideController) _ => throw new Exception(GetExceptionMessage(controller))
};
static string GetExceptionMessage(IRuntimeAnimatorController controller)
{ {
return overrideController.IsContainsAnimationClip(clip); return $"{controller.GetType()} inherits from {nameof(IRuntimeAnimatorController)} but not {nameof(IAnimatorController)} or {nameof(IAnimatorOverrideController)}";
}
else
{
throw new Exception($"{controller.GetType()} inherits from {nameof(IRuntimeAnimatorController)} but not {nameof(IAnimatorController)} or {nameof(IAnimatorOverrideController)}");
} }
} }
} }