【Unity】AnimationClip を path で検索できるツール

完成イメージ

アニメーションクリップをパスで検索したいケースがあったので作成しました。
要素を ドラッグ&ドロップして Inspector などの ObjectField にアタッチすることも可能です。

ソースコード

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;

public class AnimationClipSearch : EditorWindow
{
    [System.Serializable]
    public class AssetData<T> where T : Object
    {
        [SerializeField]
        private int m_Id;

        [SerializeField]
        private string m_Path;

        [SerializeField]
        private T m_Asset;

        [SerializeField]
        private Texture2D m_Icon;

        public int Id => m_Id;
        public string Path => m_Path;
        public T Asset => m_Asset;
        public Texture2D Icon => m_Icon;

        public AssetData(int id, string path, T asset)
        {
            m_Id = id;
            m_Path = path;
            m_Asset = asset;
            m_Icon = (Texture2D)EditorGUIUtility.ObjectContent(m_Asset, m_Asset.GetType()).image;
        }
    }

    [MenuItem("EditorWindow/AnimationClipSearch")]
    private static void Init()
    {
        var window = GetWindow(typeof(AnimationClipSearch));
        window.titleContent = new GUIContent("AnimationClipSearch");
        window.Show();
        window.minSize = new Vector2(330, 400);
    }

    [SerializeField]
    private List<AssetData<AnimationClip>> m_AssetDataList;
    [SerializeField]
    private TreeViewState m_TreeViewState;

    private AssetPathListView<AnimationClip> m_AssetPathListView;
    private SearchField m_SearchField;

    private void OnGUI()
    {
        using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
        {
            if (m_AssetDataList == null || GUILayout.Button("Reload", EditorStyles.toolbarButton, GUILayout.Width(80)))
            {
                m_AssetDataList = AssetDatabase.FindAssets("t:AnimationClip", new[] { "Assets/" })
                    .Select(guid => AssetDatabase.GUIDToAssetPath(guid))
                    .Select((path, index) => new AssetData<AnimationClip>(index, path, AssetDatabase.LoadAssetAtPath<AnimationClip>(path)))
                    .ToList();

                m_TreeViewState = null;
                m_AssetPathListView = null;
            }

            if (m_TreeViewState == null)
            {
                m_TreeViewState = new TreeViewState();
            }

            if (m_AssetPathListView == null)
            {
                m_AssetPathListView = new AssetPathListView<AnimationClip>(m_TreeViewState);
                m_AssetPathListView.Setup(m_AssetDataList);
                m_SearchField = new SearchField();
                m_SearchField.downOrUpArrowKeyPressed += m_AssetPathListView.SetFocusAndEnsureSelectedItem;
            }

            GUILayout.Space(100);
            GUILayout.FlexibleSpace();

            m_AssetPathListView.searchString = m_SearchField.OnToolbarGUI(m_AssetPathListView.searchString);
        }

        var rect = EditorGUILayout.GetControlRect(false, GUILayout.ExpandHeight(true));
        m_AssetPathListView.OnGUI(rect);
    }

    public class AssetPathListView<T> : TreeView where T : Object
    {
        private List<AssetData<T>> m_AssetDataList;

        public AssetPathListView(TreeViewState treeViewState) : base(treeViewState)
        {
            showAlternatingRowBackgrounds = true;
        }

        public void Setup(List<AssetData<T>> baseElements)
        {
            m_AssetDataList = baseElements;
            Reload();
        }

        protected override TreeViewItem BuildRoot()
        {
            var root = new TreeViewItem { id = -1, depth = -1, displayName = "Root" };

            foreach (var assetData in m_AssetDataList)
            {
                var item = new TreeViewItem { id = assetData.Id, displayName = assetData.Path, icon = assetData.Icon };
                root.AddChild(item);
            }

            SetupDepthsFromParentsAndChildren(root);
            return root;
        }

        protected override bool CanStartDrag(CanStartDragArgs args)
        {
            return true;
        }

        protected override void SetupDragAndDrop(SetupDragAndDropArgs args)
        {
            DragAndDrop.PrepareStartDrag();
            var selectedItems = args.draggedItemIDs;
            var objects = m_AssetDataList
                .Where(assetData => selectedItems.Contains(assetData.Id))
                .Select(assetData => assetData.Asset)
                .ToArray();

            DragAndDrop.objectReferences = objects;
            DragAndDrop.StartDrag("AnimationClipSearch Drag");
        }
    }
}