【Unity】【エディタ拡張】ProjectビューにおいてTwo Columnレイアウトの左側のパネルで選択中しているフォルダとファイルを取得する

UnityでProjectビューにおいてTwo Columnレイアウトの左側のパネルで選択中しているフォルダとファイルを取得する方法についてまとめました。

Unity2020.3.22

やりたいこと

Unityで選択中のオブジェクトを取得するにはUnityEditor.Selection.objectsを使用します。
これにより現在選択中のオブジェクト = Inspectorに表示されているオブジェクトを取得できます。

さてUnityのProjectビューをTwo Columns表示にしているときには、右側のパネルで選択したもののみがSelectionAPIの対象となります。

右側のみがSelectionに

左側のパネルでフォルダを選択してUnityEditor.Selection.objectsを呼んでもそれらを取得することはできません。

左側はSelectionで取得できない

しかしながらエディタ拡張をしていると、左側のパネルの選択状態を取得したい時があります。
本記事ではその方法についてまとめます。

左側のパネルの情報を取得する

左側のパネルの情報は ProjectBrowser クラスから取得できます。
しかしながらこのクラスはinternalなので、以下のようにリフレクションを使って取得する必要があります。

using System;
using System.Linq;
using System.Reflection;
using UnityEditor;

public static class ProjectViewUtility
{
    private const string ProjectBrowserTypeName = "UnityEditor.ProjectBrowser,UnityEditor";
    private const string LastInteractedProjectBrowserFieldName = "s_LastInteractedProjectBrowser";
    private const string LastFoldersFieldName = "m_LastFolders";

    private const string UseTreeViewSelectionInsteadOfMainSelectionFieldName =
        "m_UseTreeViewSelectionInsteadOfMainSelection";

    private static Type _projectBrowserType;

    private static Type ProjectBrowserType
    {
        get
        {
            if (_projectBrowserType == null)
            {
                _projectBrowserType = Type.GetType(ProjectBrowserTypeName);
                if (_projectBrowserType == null)
                {
                    throw new Exception($"Type: {ProjectBrowserTypeName} is not found.");
                }
            }

            return Type.GetType(ProjectBrowserTypeName);
        }
    }

    /// <summary>
    ///     プロジェクトビューで選択中のアセットのパスを取得します。
    /// </summary>
    /// <returns></returns>
    public static string[] GetSelectedAssetPaths()
    {
        if (IsTwoColumnLeftPanelSelected())
        {
            return GetLastFolders();
        }

        return Selection.objects.Select(AssetDatabase.GetAssetPath).Where(x => !string.IsNullOrEmpty(x)).ToArray();
    }

    /// <summary>
    ///     プロジェクトビューが2カラムレイアウトかつ左側のパネルが選択中だったらTrueを返します。
    /// </summary>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static bool IsTwoColumnLeftPanelSelected()
    {
        var lastProjectBrowserField = ProjectBrowserType
            .GetField(LastInteractedProjectBrowserFieldName, BindingFlags.Static | BindingFlags.Public);

        if (lastProjectBrowserField == null)
        {
            throw new Exception($"Field: {LastInteractedProjectBrowserFieldName} is not found.");
        }

        var lastProjectBrowser = lastProjectBrowserField.GetValue(null);

        if (lastProjectBrowser == null)
        {
            return false;
        }

        var useTreeViewSelectionInsteadOfMainSelectionField = ProjectBrowserType
            .GetField(UseTreeViewSelectionInsteadOfMainSelectionFieldName,
                BindingFlags.NonPublic | BindingFlags.Instance);

        if (useTreeViewSelectionInsteadOfMainSelectionField == null)
        {
            throw new Exception($"Field: {UseTreeViewSelectionInsteadOfMainSelectionFieldName} is not found.");
        }

        return (bool)useTreeViewSelectionInsteadOfMainSelectionField.GetValue(lastProjectBrowser);
    }

    private static string[] GetLastFolders()
    {
        var lastProjectBrowserField = ProjectBrowserType
            .GetField(LastInteractedProjectBrowserFieldName, BindingFlags.Static | BindingFlags.Public);

        if (lastProjectBrowserField == null)
        {
            throw new Exception($"Field: {LastInteractedProjectBrowserFieldName} is not found.");
        }

        var lastProjectBrowser = lastProjectBrowserField.GetValue(null);

        if (lastProjectBrowser == null)
        {
            return null;
        }

        var lastFoldersField =
            ProjectBrowserType.GetField(LastFoldersFieldName, BindingFlags.NonPublic | BindingFlags.Instance);

        if (lastFoldersField == null)
        {
            throw new Exception($"Field: {UseTreeViewSelectionInsteadOfMainSelectionFieldName} is not found.");
        }

        return (string[])lastFoldersField.GetValue(lastProjectBrowser);
    }
}

上記のGetSelectedAssetPaths()を使用すると、左右のパネルの両方を対象として、選択中のアセットのパスを取得することができます。

参考

github.com