Unity Animation Hierarchy Fixer

0 0 February 14, 2015

While working on a project at home I made a change to the hierarchy of a group that I had previously animated. Whoops! Yellow, broken animations all over the place. I searched around for an easy solution, finding not a whole lot. Luckily one “S-M-K” over at GitHub had created just such a tool. I took a quick look at how he was doing and thought it was a pretty nifty idea. I, however, am never one to take the easy route and I prefer to really understand how something is done rather than just use it. To that end I decided to try re-creating the tool from scratch. I’m happy with what I ended up with:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class AnimHierarchyEditor : EditorWindow
{
	private GameObject obj;
	private List animations = new List();
	private Hashtable animTable = new Hashtable();
	private Dictionary objectByPath = new Dictionary();
	private Dictionary pathByObject = new Dictionary();
	private Vector2 scrollPos;


	[MenuItem("Window/Anim Hierarchy Editor")]
	public static void Init()
	{
		AnimHierarchyEditor window = EditorWindow.CreateInstance();
		window.position = new Rect(Screen.width * 0.3f, Screen.height * 0.3f, 800.0f, 400.0f);
		window.name = window.title = "Anim Hierarchy Editor";

		window.OnSelectionChange();

		window.ShowUtility();
	}

	private void OnHierarchyChange()
	{
		if(obj != null)
		{
			objectByPath.Clear();
			pathByObject.Clear();
			GetChildPaths(obj.transform);
			this.Repaint();
		}
	}

	private void OnSelectionChange()
	{
		this.Repaint();
		if(Selection.activeGameObject == null)
		{
			return;
		}

		Animator animator = Selection.activeGameObject.GetComponent();
		if(animator == null)
		{
			return;
		}
		
		obj = Selection.activeGameObject;
		RuntimeAnimatorController controller = animator.runtimeAnimatorController;
		animations.Clear();
		animTable.Clear();
		
		string[] dependents = AssetDatabase.GetDependencies(new string[]{AssetDatabase.GetAssetPath(controller)});
		foreach(string s in dependents)
		{
			if(s.EndsWith(".anim"))
			{
				AnimationClip anim = (AnimationClip)AssetDatabase.LoadAssetAtPath(s, typeof(AnimationClip));
				if(anim != null)
				{
					animations.Add (anim);
					List animPaths = new List();

					EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(anim);
					foreach(EditorCurveBinding binding in bindings)
					{
						if(!animPaths.Contains(binding.path))
						{
							animPaths.Add(binding.path);
						}
					}

					animTable.Add(anim, animPaths);
				}
			}
		}

		objectByPath.Clear();
		pathByObject.Clear();

		GetChildPaths(obj.transform);
	}

	private void GetChildPaths(Transform trans, string mPath = "")
	{
		if(!string.IsNullOrEmpty(mPath))
		{
			mPath += "/";
		}
		for(int i=0; i animPaths = (List)animTable[anim];
					foreach(string path in animPaths)
					{
						EditorGUILayout.BeginHorizontal();
						{
							GameObject childObj = null;
							bool bContains = objectByPath.TryGetValue(path, out childObj);
							if(!bContains)
							{
								GUI.color = Color.red;
							}
							EditorGUILayout.LabelField(path);

							GUI.color = Color.white;
							GameObject fixObj = (GameObject)EditorGUILayout.ObjectField(childObj, typeof(GameObject), true);

							if(fixObj != childObj)
							{
								string newPath;
								if(pathByObject.TryGetValue(fixObj, out newPath))
								{
									FixAnimationPaths(anim, path, newPath);
									return;
								}
							}
						}
						EditorGUILayout.EndHorizontal();
					}
				}
				EditorGUI.indentLevel--;

				EditorGUILayout.Space();
			}
			EditorGUI.indentLevel--;
		}
		EditorGUILayout.EndScrollView();
	}

	private void FixAnimationPaths(AnimationClip clip, string badPath, string newPath)
	{
		Undo.RecordObject(clip, "Animation Hierarchy Change");

		EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip);
		for(int i=0; i

0 Comments

Leave a Reply