BehaviorTree / Editor / EditorWindows / BlackboardEditor.cs
BlackboardEditor.cs
Raw
using AI.BT;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.Graphs;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

public class BlackboardEditor : EditorWindow
{
    [SerializeField]
    private SerializedObject m_BlackboardObject = null;

    [SerializeField]
    private Blackboard m_Blackboard = null;

    [SerializeField]
    private ListView m_KeyList = null;

    [SerializeField]
    private PropertyField m_SelectedKeyPropertyField = null;

    [SerializeField]
    private ToolbarMenu m_AddKeyMenu = null;

    [MenuItem("Window/UI Toolkit/BlackboardEditor")]
    public static void Open()
    {
        BlackboardEditor wnd = GetWindow<BlackboardEditor>();
        wnd.titleContent = new GUIContent("BlackboardEditor");
    }

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

        var visualTreeAsset = BehaviorTreeSettings.GetOrCreateSettings().BlackboardEditorUxml;
        // Instantiate UXML
        visualTreeAsset.CloneTree(root);
    }

    public static void Open(Blackboard tree)
    {
        BlackboardEditor wnd = CreateWindow<BlackboardEditor>();
        wnd.titleContent = new GUIContent("BehaviorTreeEditor");
        wnd.Initialize(tree);
    }

    [OnOpenAsset()]
    public static bool OpenBehaviorTreeAsset(int instanceID, int line)
    {
        var asset_path = AssetDatabase.GetAssetPath(instanceID);
        if (asset_path != null)
        {
            var asset = AssetDatabase.LoadAssetAtPath<Blackboard>(asset_path);
            if (asset != null)
            {
                BlackboardEditor.Open(asset);
                return true;
            }
        }

        return false;
    }

    public void Initialize(Blackboard blackboard)
    {
        if (!blackboard) return;

        m_BlackboardObject = new SerializedObject(blackboard);
        m_Blackboard = blackboard;
        m_Blackboard.OnKeyAdded = OnKeyAdded;
        m_Blackboard.OnKeyRemoved = OnKeyRemoved;

        rootVisualElement.RegisterCallback<KeyDownEvent>(OnKeyDown);

        InitKeyMenu();
        InitKeyList();
        InitSelectedPropertyField();
    }

    private void OnKeyDown(KeyDownEvent evt)
    {
        if(evt.keyCode == KeyCode.Delete)
        {
            m_Blackboard.Remove(m_KeyList.selectedItem as string);
            m_SelectedKeyPropertyField.Unbind();
            m_KeyList.SetSelection(m_KeyList.itemsSource.Count - 1);
            evt.StopImmediatePropagation();
        }
    }

    private void OnKeyRemoved(string obj)
    {
        m_KeyList.itemsSource = m_Blackboard.Keys.Keys.ToList();
        m_KeyList.RefreshItems();
    }

    private void OnKeyAdded(string obj)
    {
        m_KeyList.itemsSource = m_Blackboard.Keys.Keys.ToList();
        m_KeyList.RefreshItems();
    }

    private void InitKeyMenu()
    {
        m_AddKeyMenu = rootVisualElement.Q<ToolbarMenu>("AddKeyMenu");
        m_AddKeyMenu.menu.AppendAction("New Key", action => { m_Blackboard.Add("New Key"); });
    }

    private void InitKeyList()
    {
        m_KeyList = rootVisualElement.Q<ListView>("KeyList");
        m_KeyList.itemsSource = m_Blackboard.Keys.Keys.ToList();
        m_KeyList.makeItem = MakeListItem;
        m_KeyList.bindItem = BindListItem;
        m_KeyList.unbindItem = UnBindItem;
        m_KeyList.selectedIndicesChanged += OnSelectedIndicesChanged;
        
    }

    private void UnBindItem(VisualElement element, int arg2)
    {
        var label = ((BlackboardKeyElement)element).m_Label;

        label.Unbind();
    }

    private void OnSelectedIndicesChanged(IEnumerable<int> enumerable)
    {
        if (enumerable.Count() == 0) return;

        var index = enumerable.First();
 
        if(m_BlackboardObject.FindProperty("_Values").GetArrayElementAtIndex(index) is SerializedProperty property)
            m_SelectedKeyPropertyField.BindProperty(property);
        
    }

    private void BindListItem(VisualElement element, int index)
    {
        var label = ((BlackboardKeyElement)element).m_Label;

        var key_property = m_BlackboardObject.FindProperty("_Keys");

        if (key_property.arraySize == index) return;

        if (key_property.GetArrayElementAtIndex(index) is SerializedProperty property)
        {
            label.BindProperty(property);
        }

    }

    private VisualElement MakeListItem()
    {
        return new BlackboardKeyElement();
    }

    private void InitSelectedPropertyField()
    {
        m_SelectedKeyPropertyField = rootVisualElement.Q<PropertyField>("SelectedKeyField");
    }

    private void OnSelectionChange()
    {
        Blackboard blackboard = Selection.activeObject as Blackboard;
        if (!blackboard)
        {
            return;
        }

        if (blackboard && AssetDatabase.CanOpenAssetInEditor(blackboard.GetInstanceID()))
        {
            Initialize(blackboard);
        }
    }
}