コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】Package Manager の Install・Remove ボタンの隣にボタンを表示するサンプル

ソースコード

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEditor.PackageManager.UI;
using UnityEditorInternal;
using UnityEngine.UIElements;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;

[InitializeOnLoad]
internal sealed class Example
    : VisualElement,
      IPackageManagerExtension
{
    private bool m_isInitialized;

    static Example()
    {
        var extension = new Example();
        PackageManagerExtensions.RegisterExtension( extension );
    }

    VisualElement IPackageManagerExtension.CreateExtensionUI()
    {
        m_isInitialized = false;
        return this;
    }

    void IPackageManagerExtension.OnPackageSelectionChange( PackageInfo packageInfo )
    {
        Initialize();
    }

    private void Initialize()
    {
        if ( m_isInitialized ) return;

        VisualElement root = this;

        while ( root != null && root.parent != null )
        {
            root = root.parent;
        }

        var button = new Button { text = "ピカチュウ", };

        var removeButton = FindElement( root, x => x.name == "PackageRemoveCustomButton" );
        removeButton.parent.Add( button );

        m_isInitialized = true;
    }

    void IPackageManagerExtension.OnPackageAddedOrUpdated( PackageInfo packageInfo )
    {
    }

    void IPackageManagerExtension.OnPackageRemoved( PackageInfo packageInfo )
    {
    }

    private static VisualElement FindElement
    (
        VisualElement             element,
        Func<VisualElement, bool> predicate
    )
    {
        var selected                    = new List<VisualElement>();
        var engineAssemblyPath          = InternalEditorUtility.GetEngineAssemblyPath();
        var engineAssemblyDirectoryName = Path.GetDirectoryName( engineAssemblyPath ).Replace( "\\", "/" );
        var assembly                    = Assembly.LoadFile( $@"{engineAssemblyDirectoryName}/UnityEditor.UIBuilderModule.dll" );
        var type                        = assembly.GetType( "Unity.UI.Builder.VisualElementExtensions" );
        var findElementsRecursiveMethod = type.GetMethod( "FindElementsRecursive", BindingFlags.Static | BindingFlags.NonPublic );

        findElementsRecursiveMethod.Invoke( null, new object[] { element, predicate, selected } );

        return selected.Count == 0 ? null : selected[ 0 ];
    }
}

[