339 lines
13 KiB
C#
339 lines
13 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Collections.Generic;
|
|
using SevenZip;
|
|
using System;
|
|
|
|
namespace AssetStudio
|
|
{
|
|
public static class AnimationClipExtensions
|
|
{
|
|
public static float DefaultFloatWeight => 1.0f / 3.0f;
|
|
public static Vector3 DefaultVector3Weight => new Vector3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
|
public static Quaternion DefaultQuaternionWeight => new Quaternion(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
|
|
|
|
#region AnimationClip
|
|
public static IEnumerable<GameObject> FindRoots(this AnimationClip clip)
|
|
{
|
|
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects))
|
|
{
|
|
switch (asset.type)
|
|
{
|
|
case ClassIDType.Animator:
|
|
Animator animator = (Animator)asset;
|
|
if (clip.IsAnimatorContainsClip(animator))
|
|
{
|
|
if (animator.m_GameObject.TryGet(out var go))
|
|
{
|
|
yield return go;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ClassIDType.Animation:
|
|
Animation animation = (Animation)asset;
|
|
if (clip.IsAnimationContainsClip(animation))
|
|
{
|
|
if (animation.m_GameObject.TryGet(out var go))
|
|
{
|
|
yield return go;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
yield break;
|
|
}
|
|
public static Dictionary<uint, string> FindTOS(this AnimationClip clip)
|
|
{
|
|
var tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
|
foreach (var asset in clip.assetsFile.assetsManager.assetsFileList.SelectMany(x => x.Objects).OrderBy(x => x.type).ToArray())
|
|
{
|
|
switch (asset.type)
|
|
{
|
|
case ClassIDType.Avatar:
|
|
var avatar = asset as Avatar;
|
|
if (clip.AddAvatarTOS(avatar, tos))
|
|
{
|
|
return tos;
|
|
}
|
|
break;
|
|
case ClassIDType.Animator:
|
|
var animator = asset as Animator;
|
|
if (clip.IsAnimatorContainsClip(animator))
|
|
{
|
|
if (clip.AddAnimatorTOS(animator, tos))
|
|
{
|
|
return tos;
|
|
}
|
|
}
|
|
break;
|
|
case ClassIDType.Animation:
|
|
var animation = asset as Animation;
|
|
if (clip.IsAnimationContainsClip(animation))
|
|
{
|
|
if (clip.AddAnimationTOS(animation, tos))
|
|
{
|
|
return tos;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return tos;
|
|
}
|
|
private static bool AddAvatarTOS(this AnimationClip clip, Avatar avatar, Dictionary<uint, string> tos)
|
|
{
|
|
return clip.AddTOS(avatar.m_TOS.ToDictionary(x => x.Key, x => x.Value), tos);
|
|
}
|
|
private static bool AddAnimatorTOS(this AnimationClip clip, Animator animator, Dictionary<uint, string> tos)
|
|
{
|
|
if (animator.m_Avatar.TryGet(out var avatar))
|
|
{
|
|
if (clip.AddAvatarTOS(avatar, tos))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Dictionary<uint, string> animatorTOS = animator.BuildTOS();
|
|
return clip.AddTOS(animatorTOS, tos);
|
|
}
|
|
private static bool AddAnimationTOS(this AnimationClip clip, Animation animation, Dictionary<uint, string> tos)
|
|
{
|
|
if (animation.m_GameObject.TryGet(out var go))
|
|
{
|
|
Dictionary<uint, string> animationTOS = go.BuildTOS();
|
|
return clip.AddTOS(animationTOS, tos);
|
|
}
|
|
return false;
|
|
}
|
|
private static bool AddTOS(this AnimationClip clip, Dictionary<uint, string> src, Dictionary<uint, string> dest)
|
|
{
|
|
int tosCount = clip.m_ClipBindingConstant.genericBindings.Length;
|
|
for (int i = 0; i < tosCount; i++)
|
|
{
|
|
ref GenericBinding binding = ref clip.m_ClipBindingConstant.genericBindings[i];
|
|
if (src.TryGetValue(binding.path, out string path))
|
|
{
|
|
dest[binding.path] = path;
|
|
if (dest.Count == tosCount)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
private static bool IsAnimationContainsClip(this AnimationClip clip, Animation animation)
|
|
{
|
|
return animation.IsContainsAnimationClip(clip);
|
|
}
|
|
private static bool IsAnimatorContainsClip(this AnimationClip clip, Animator animator)
|
|
{
|
|
if (animator.m_Controller.TryGet(out var runtime))
|
|
{
|
|
return runtime.IsContainsAnimationClip(clip);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
public static string Convert(this AnimationClip clip)
|
|
{
|
|
if (!clip.m_Legacy || clip.m_MuscleClip != null)
|
|
{
|
|
var converter = AnimationClipConverter.Process(clip);
|
|
clip.m_RotationCurves = converter.Rotations.Union(clip.m_RotationCurves).ToArray();
|
|
clip.m_EulerCurves = converter.Eulers.Union(clip.m_EulerCurves).ToArray();
|
|
clip.m_PositionCurves = converter.Translations.Union(clip.m_PositionCurves).ToArray();
|
|
clip.m_ScaleCurves = converter.Scales.Union(clip.m_ScaleCurves).ToArray();
|
|
clip.m_FloatCurves = converter.Floats.Union(clip.m_FloatCurves).ToArray();
|
|
clip.m_PPtrCurves = converter.PPtrs.Union(clip.m_PPtrCurves).ToArray();
|
|
}
|
|
return ConvertSerializedAnimationClip(clip);
|
|
}
|
|
public static string ConvertSerializedAnimationClip(AnimationClip animationClip)
|
|
{
|
|
var sb = new StringBuilder();
|
|
using (var stringWriter = new StringWriter(sb))
|
|
{
|
|
YAMLWriter writer = new YAMLWriter();
|
|
YAMLDocument doc = ExportYAMLDocument(animationClip);
|
|
writer.AddDocument(doc);
|
|
writer.Write(stringWriter);
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
|
|
public static YAMLDocument ExportYAMLDocument(AnimationClip animationClip)
|
|
{
|
|
var document = new YAMLDocument();
|
|
var root = document.CreateMappingRoot();
|
|
root.Tag = ((int)ClassIDType.AnimationClip).ToString();
|
|
root.Anchor = ((int)ClassIDType.AnimationClip * 100000).ToString();
|
|
var node = animationClip.ExportYAML(animationClip.version);
|
|
root.Add(ClassIDType.AnimationClip.ToString(), node);
|
|
return document;
|
|
}
|
|
public static YAMLMappingNode ExportYAML(this AnimationClip clip, int[] version)
|
|
{
|
|
var node = new YAMLMappingNode();
|
|
node.Add(nameof(clip.m_Name), clip.m_Name);
|
|
node.AddSerializedVersion(ToSerializedVersion(version));
|
|
node.Add(nameof(clip.m_Legacy), clip.m_Legacy);
|
|
node.Add(nameof(clip.m_Compressed), clip.m_Compressed);
|
|
node.Add(nameof(clip.m_UseHighQualityCurve), clip.m_UseHighQualityCurve);
|
|
node.Add(nameof(clip.m_RotationCurves), clip.m_RotationCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_CompressedRotationCurves), clip.m_CompressedRotationCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_EulerCurves), clip.m_EulerCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_PositionCurves), clip.m_PositionCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_ScaleCurves), clip.m_ScaleCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_FloatCurves), clip.m_FloatCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_PPtrCurves), clip.m_PPtrCurves.ExportYAML(version));
|
|
node.Add(nameof(clip.m_SampleRate), clip.m_SampleRate);
|
|
node.Add(nameof(clip.m_WrapMode), clip.m_WrapMode);
|
|
node.Add(nameof(clip.m_Bounds), clip.m_Bounds.ExportYAML(version));
|
|
node.Add(nameof(clip.m_ClipBindingConstant), clip.m_ClipBindingConstant.ExportYAML(version));
|
|
node.Add("m_AnimationClipSettings", clip.m_MuscleClip != null ? clip.m_MuscleClip.ExportYAML(version) : new YAMLMappingNode());
|
|
node.Add(nameof(clip.m_Events), clip.m_Events.ExportYAML(version));
|
|
return node;
|
|
}
|
|
|
|
public static int ToSerializedVersion(int[] version)
|
|
{
|
|
if (version[0] >= 5)
|
|
{
|
|
return 6;
|
|
}
|
|
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))
|
|
{
|
|
return 4;
|
|
}
|
|
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6))
|
|
{
|
|
return 3;
|
|
}
|
|
return 2;
|
|
}
|
|
#endregion
|
|
|
|
#region Others
|
|
private static bool IsContainsAnimationClip(this Animation animation, AnimationClip clip)
|
|
{
|
|
foreach (PPtr<AnimationClip> ptr in animation.m_Animations)
|
|
{
|
|
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static Dictionary<uint, string> BuildTOS(this Animator animator)
|
|
{
|
|
if (animator.version[0] > 4 || (animator.version[0] == 4 && animator.version[1] >= 3))
|
|
{
|
|
if (animator.m_HasTransformHierarchy)
|
|
{
|
|
if (animator.m_GameObject.TryGet(out var go))
|
|
{
|
|
return go.BuildTOS();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return new Dictionary<uint, string>() { { 0, string.Empty } };
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (animator.m_GameObject.TryGet(out var go))
|
|
{
|
|
return go.BuildTOS();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
private static Dictionary<uint, string> BuildTOS(this GameObject gameObject)
|
|
{
|
|
Dictionary<uint, string> tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
|
gameObject.BuildTOS(string.Empty, tos);
|
|
return tos;
|
|
}
|
|
private static void BuildTOS(this GameObject parent, string parentPath, Dictionary<uint, string> tos)
|
|
{
|
|
Transform transform = parent.m_Transform;
|
|
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
|
{
|
|
if (childPtr.TryGet(out var childTransform))
|
|
{
|
|
if (childTransform.m_GameObject.TryGet(out var child))
|
|
{
|
|
string path = parentPath != string.Empty ? parentPath + '/' + child.m_Name : child.m_Name;
|
|
var pathHash = CRC.CalculateDigestUTF8(path);
|
|
tos[pathHash] = path;
|
|
BuildTOS(child, path, tos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private static bool IsContainsAnimationClip(this RuntimeAnimatorController runtimeAnimatorController, AnimationClip clip)
|
|
{
|
|
if (runtimeAnimatorController is AnimatorController animatorController)
|
|
{
|
|
foreach (PPtr<AnimationClip> ptr in animatorController.m_AnimationClips)
|
|
{
|
|
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
public static int GetDimension(this GenericBinding binding)
|
|
{
|
|
return binding.attribute == 2 ? 4 : 3;
|
|
}
|
|
|
|
public static HumanoidMuscleType GetHumanoidMuscle(this GenericBinding binding)
|
|
{
|
|
return ((HumanoidMuscleType)binding.attribute).Update(binding.version);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
public enum BindingCustomType : byte
|
|
{
|
|
None = 0,
|
|
Transform = 4,
|
|
AnimatorMuscle = 8,
|
|
|
|
BlendShape = 20,
|
|
Renderer = 21,
|
|
RendererMaterial = 22,
|
|
SpriteRenderer = 23,
|
|
MonoBehaviour = 24,
|
|
Light = 25,
|
|
RendererShadows = 26,
|
|
ParticleSystem = 27,
|
|
RectTransform = 28,
|
|
LineRenderer = 29,
|
|
TrailRenderer = 30,
|
|
PositionConstraint = 31,
|
|
RotationConstraint = 32,
|
|
ScaleConstraint = 33,
|
|
AimConstraint = 34,
|
|
ParentConstraint = 35,
|
|
LookAtConstraint = 36,
|
|
Camera = 37,
|
|
}
|
|
}
|