うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】PresetEditor を拡張する

Unity2020 から Preset に更新しないような設定をすることが可能になった

更新しない値には左側に赤い色がつく

f:id:hacchi_man:20211225010100p:plain:w300

これを全部更新しないようにしたり、更新するようにしたい場合は Menu からやるんですが

この一手間が面倒だったのでボタンにしてみました

f:id:hacchi_man:20211225005959p:plain:w300

PresetEditor

拡張するために、クラスを探していたところ見つかりましたが internal クラスのため通常の拡張ができません

https://github.com/Unity-Technologies/UnityCsReference/blob/e740821767d2290238ea7954457333f06e952bad/Modules/PresetsUIEditor/PresetEditor.cs

そのため Reflection を利用して無理やり描画させます

    // 型を探し出して Editor を作成
    private void OnEnable()
    {
        Type = typeof(EditorApplication).Assembly.GetType("UnityEditor.Presets.PresetEditor");
        _editor = CreateEditor(targets, Type);
    }

    private void OnDisable()
    {
        DestroyImmediate(_editor);
    }
        
    public override void OnInspectorGUI()
    {
        _editor.OnInspectorGUI();
    }

また Menu の Exclude と Include は CONTEXT より参照を得ているため、こちらも無理やり呼び出してあげる必要があります

スクリプト

そうして出来上がったスクリプトが以下になります

これを利用すると下図のようにボタンが追加で表示されます

f:id:hacchi_man:20211225010500p:plain:w300

using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.Presets;
using UnityEngine;
 
[CustomEditor(typeof(Preset))]
public class PresetEditorExtension : Editor
{
    private Editor _editor;
    private Type Type;
         
    private void OnEnable()
    {
        Type = typeof(EditorApplication).Assembly.GetType("UnityEditor.Presets.PresetEditor");
        _editor = CreateEditor(targets, Type);
    }
     
    public override void OnInspectorGUI()
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            if (GUILayout.Button("Exclude All Properties"))
            {
                InvokePresetEditorMenu("ExcludeAll");
            }
            if (GUILayout.Button("Include All Properties"))
            {
                InvokePresetEditorMenu("IncludeAll");
            }                
        }
        _editor.OnInspectorGUI();
    }
 
    protected override void OnHeaderGUI()
    {
        Type.InvokeMember(nameof(OnHeaderGUI), 
            BindingFlags.NonPublic | BindingFlags.Instance |
            BindingFlags.InvokeMethod,
            null,
            _editor,
            null);
    }
 
    private void InvokePresetEditorMenu(string name)
    {
        Type.InvokeMember(
            name,
            BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, 
            null,
            null, 
            new object[]{new MenuCommand(target)}
        );
    }
}