From a2efbc4bad3822fa000f7a48abf0493750e99192 Mon Sep 17 00:00:00 2001 From: taoria <445625470@qq.com> Date: Tue, 2 Aug 2022 16:17:31 +0800 Subject: [PATCH] feature:blackboard support array or list as exposed attribute --- .../Editor/Blackboard/IBlackboardView.cs | 1 + TNode/TNodeCore/Editor/DeveloperHelper.meta | 3 + .../DeveloperHelper/CleanMissingTypeHelper.cs | 66 ++++++++++ .../CleanMissingTypeHelper.cs.meta | 3 + .../EditorPersistence/GraphEditorData.cs | 6 +- TNode/TNodeCore/Editor/GraphEditor.cs | 4 + .../NodeGraphView/IBaseDataGraphView.cs | 1 + .../Serialization/BlackboardDataWrapper.cs | 1 - .../Runtime/Components/RuntimeGraph.cs | 32 +++-- TNode/TNodeCore/Runtime/DataWrapper.cs | 11 +- .../Runtime/Models/BlackboardData.cs | 2 + .../Runtime/Models/BlackboardDragNodeData.cs | 30 ++++- TNode/TNodeCore/Runtime/Models/GraphData.cs | 4 +- .../Runtime/RuntimeCache/RuntimeCache.cs | 16 +++ .../GraphBlackboard/BlackboardDataEntry.cs | 44 +++++++ .../BlackboardDataEntry.cs.meta | 3 + .../DefaultGraphBlackboardView.cs | 117 ++++++++++++++---- .../GraphBlackboard/GraphBlackboardView.cs | 11 +- .../Editor/NodeGraphView/DataGraphView.cs | 29 ++++- .../Editor/NodeViews/DragNodeView.cs | 24 +++- .../Editor/Resources/BlackboardDataEntry.uss | 12 ++ .../Resources/BlackboardDataEntry.uss.meta | 3 + .../Search/BlackboardSearchWindowProvider.cs | 32 ++++- 23 files changed, 394 insertions(+), 61 deletions(-) create mode 100644 TNode/TNodeCore/Editor/DeveloperHelper.meta create mode 100644 TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs create mode 100644 TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs.meta create mode 100644 TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs create mode 100644 TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs.meta create mode 100644 TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss create mode 100644 TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss.meta diff --git a/TNode/TNodeCore/Editor/Blackboard/IBlackboardView.cs b/TNode/TNodeCore/Editor/Blackboard/IBlackboardView.cs index 8b57506..bf6360a 100644 --- a/TNode/TNodeCore/Editor/Blackboard/IBlackboardView.cs +++ b/TNode/TNodeCore/Editor/Blackboard/IBlackboardView.cs @@ -10,6 +10,7 @@ namespace TNodeCore.Editor.Blackboard{ public void AddItem(); void Setup(IBaseDataGraphView graphView,EditorWindow ownerWindow); + void NotifyUpdate(); } public interface IBlackboardView : IBlackboardView where T : BlackboardData{ diff --git a/TNode/TNodeCore/Editor/DeveloperHelper.meta b/TNode/TNodeCore/Editor/DeveloperHelper.meta new file mode 100644 index 0000000..b45cb6a --- /dev/null +++ b/TNode/TNodeCore/Editor/DeveloperHelper.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7d20d1aa36604785a19ec27375f3becb +timeCreated: 1659420802 \ No newline at end of file diff --git a/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs b/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs new file mode 100644 index 0000000..988b39d --- /dev/null +++ b/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs @@ -0,0 +1,66 @@ +using System.Text; +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace TNodeCore.Editor.DeveloperHelper{ + public class CleanMissingTypeHelper + { + [MenuItem("TNode/CleanMissingType/CleanScriptObjects")] + public static void CleanMissingTypesOnScriptableObjects() + { + var report = new StringBuilder(); + + var guids = AssetDatabase.FindAssets("t:ScriptableObject", new[] {"Assets"}); + foreach (string guid in guids) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + Object obj = AssetDatabase.LoadMainAssetAtPath(path); + if (obj != null) + { + if (SerializationUtility.ClearAllManagedReferencesWithMissingTypes(obj)) + { + report.Append("Cleared missing types from ").Append(path).AppendLine(); + } + else + { + report.Append("No missing types to clear on ").Append(path).AppendLine(); + } + } + } + Debug.Log(report.ToString()); + } + + [MenuItem("TNode/CleanMissingType/CleanSceneGameObjects")] + public static void CleanMissingTypesOnGameObjects(){ + var report = new StringBuilder(); + + SceneManager.GetActiveScene().GetRootGameObjects(); + foreach (GameObject root in SceneManager.GetActiveScene().GetRootGameObjects()){ + foreach (var o in root.transform){ + if (SerializationUtility.ClearAllManagedReferencesWithMissingTypes(o as Object)) + { + report.Append("Cleared missing types from ").Append(root.name).AppendLine(); + } + else + { + report.Append("No missing types to clear on ").Append(root.name).AppendLine(); + } + } + + + if (SerializationUtility.ClearAllManagedReferencesWithMissingTypes(root)) + { + report.Append("Cleared missing types from ").Append(root.name).AppendLine(); + } + else + { + report.Append("No missing types to clear on ").Append(root.name).AppendLine(); + } + } + Debug.Log(report.ToString()); + + } + + } +} \ No newline at end of file diff --git a/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs.meta b/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs.meta new file mode 100644 index 0000000..c188686 --- /dev/null +++ b/TNode/TNodeCore/Editor/DeveloperHelper/CleanMissingTypeHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d24a02b78de74a29a32e095205fe977c +timeCreated: 1659420813 \ No newline at end of file diff --git a/TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs b/TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs index b5b2eb7..7d85841 100644 --- a/TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs +++ b/TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs @@ -17,8 +17,12 @@ namespace TNodeCore.Editor.EditorPersistence{ public IDataGraphView GetGraphView () where T:GraphData{ switch (graphImplType){ - case GraphImplType.GraphViewImpl: + case GraphImplType.GraphViewImpl:{ return (IDataGraphView)GraphViewImplCreator.Invoke(typeof(T)); + + } + + case GraphImplType.GraphToolsFoundationImpl: throw new NotImplementedException(); default: diff --git a/TNode/TNodeCore/Editor/GraphEditor.cs b/TNode/TNodeCore/Editor/GraphEditor.cs index 625d8d9..d035c65 100644 --- a/TNode/TNodeCore/Editor/GraphEditor.cs +++ b/TNode/TNodeCore/Editor/GraphEditor.cs @@ -81,7 +81,11 @@ namespace TNodeCore.Editor{ } private void BuildGraphView(){ GraphView = graphEditorData.GetGraphView(); + GraphView.Owner = this; + rootVisualElement.Add((VisualElement)GraphView); + + GraphView.AfterEditorLoadGraphView(); ((VisualElement)GraphView).StretchToParentSize(); } diff --git a/TNode/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs b/TNode/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs index ef4854e..67f3053 100644 --- a/TNode/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs +++ b/TNode/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs @@ -29,5 +29,6 @@ namespace TNodeCore.Editor.NodeGraphView{ void NotifyRuntimeUpdate(); public Action AfterRuntimeGraphUpdate{ get; set; } + void AfterEditorLoadGraphView(); } } \ No newline at end of file diff --git a/TNode/TNodeCore/Editor/Serialization/BlackboardDataWrapper.cs b/TNode/TNodeCore/Editor/Serialization/BlackboardDataWrapper.cs index 31602ca..38a19c0 100644 --- a/TNode/TNodeCore/Editor/Serialization/BlackboardDataWrapper.cs +++ b/TNode/TNodeCore/Editor/Serialization/BlackboardDataWrapper.cs @@ -3,6 +3,5 @@ using TNodeCore.Runtime.Models; namespace TNodeCore.Editor.Serialization{ public class BlackboardDataWrapper:DataWrapper{ - } } \ No newline at end of file diff --git a/TNode/TNodeCore/Runtime/Components/RuntimeGraph.cs b/TNode/TNodeCore/Runtime/Components/RuntimeGraph.cs index 64fc549..69735f0 100644 --- a/TNode/TNodeCore/Runtime/Components/RuntimeGraph.cs +++ b/TNode/TNodeCore/Runtime/Components/RuntimeGraph.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using TNodeCore.Runtime.Models; +using UnityEditor; using UnityEngine; namespace TNodeCore.Runtime.Components{ @@ -13,7 +14,6 @@ namespace TNodeCore.Runtime.Components{ /// /// Runtime copy of scene node data to hold references to scene objects /// - public List sceneNodes; /// /// Map of node id to runtime node @@ -264,21 +264,25 @@ namespace TNodeCore.Runtime.Components{ #region build scene node data #if UNITY_EDITOR public void BuildSceneNodePersistentData(SceneNodeData sceneNodeData){ - var tr = transform.Find("PersistentData"); - GameObject go; - if (tr == null){ - go = new GameObject("PersistentData"); - go.transform.SetParent(transform); - go.AddComponent(); - } - go = tr.gameObject; - var persistentData = go.GetComponent(); + var persistentData = transform.Find("PersistentData").GetComponent(); persistentData.SceneNodeDataDictionary.Add(sceneNodeData.id,sceneNodeData); } + public SceneDataPersistent CreateSceneNodePersistentGameObject(){ + var go = new GameObject("PersistentData"); + go.transform.SetParent(transform); + return go.AddComponent(); + } + public void BuildSceneNode(){ - var fetchedSceneNode = graphData.NodeDictionary.Values.Where(x => x is SceneNodeData and not BlackboardDragNodeData); - var scenePersistent = transform.Find("PersistentData").GetComponent(); + var fetchedSceneNode = graphData.NodeDictionary.Values.Where(x => x is SceneNodeData and not BlackboardDragNodeData).ToArray(); + if (!fetchedSceneNode.Any()) return; + var scenePersistent = transform.Find("PersistentData")?.GetComponent(); + + if(scenePersistent == null){ + scenePersistent = CreateSceneNodePersistentGameObject(); + + } foreach (var nodeData in fetchedSceneNode){ if (scenePersistent.SceneNodeDataDictionary.ContainsKey(nodeData.id)){ var sceneNodeData = scenePersistent.SceneNodeDataDictionary[nodeData.id]; @@ -396,6 +400,7 @@ namespace TNodeCore.Runtime.Components{ } public class SceneDataPersistent:MonoBehaviour,ISerializationCallbackReceiver{ + [NonSerialized] public readonly Dictionary SceneNodeDataDictionary = new(); @@ -404,6 +409,7 @@ namespace TNodeCore.Runtime.Components{ public void OnBeforeSerialize(){ + sceneNodeData.Clear(); foreach(var node in SceneNodeDataDictionary.Values){ sceneNodeData.Add(node); @@ -416,7 +422,7 @@ namespace TNodeCore.Runtime.Components{ } } } - + public enum ProcessingStrategy{ BreadthFirst, DepthFirst diff --git a/TNode/TNodeCore/Runtime/DataWrapper.cs b/TNode/TNodeCore/Runtime/DataWrapper.cs index bcdadc3..6243362 100644 --- a/TNode/TNodeCore/Runtime/DataWrapper.cs +++ b/TNode/TNodeCore/Runtime/DataWrapper.cs @@ -36,10 +36,19 @@ namespace TNodeCore.Runtime{ var fieldInfo = data.GetType().GetField(path); return fieldInfo.GetValue(data); } - + + public KeyValuePair[] GetAllFieldValue(){ + var fieldInfos = data.GetType().GetFields(); + var list = new List>(); + foreach (var fieldInfo in fieldInfos){ + list.Add(new KeyValuePair(fieldInfo.Name,fieldInfo.GetValue(data))); + } + return list.ToArray(); + } public virtual TData GetData(){ return data; } + public static implicit operator TData(DataWrapper wrapper){ if (wrapper == null) return default(TData); diff --git a/TNode/TNodeCore/Runtime/Models/BlackboardData.cs b/TNode/TNodeCore/Runtime/Models/BlackboardData.cs index fec0ccb..a5d95a9 100644 --- a/TNode/TNodeCore/Runtime/Models/BlackboardData.cs +++ b/TNode/TNodeCore/Runtime/Models/BlackboardData.cs @@ -10,5 +10,7 @@ namespace TNodeCore.Runtime.Models{ public object Clone(){ return this.MemberwiseClone(); } + + } } \ No newline at end of file diff --git a/TNode/TNodeCore/Runtime/Models/BlackboardDragNodeData.cs b/TNode/TNodeCore/Runtime/Models/BlackboardDragNodeData.cs index 5b7ed72..08b21bb 100644 --- a/TNode/TNodeCore/Runtime/Models/BlackboardDragNodeData.cs +++ b/TNode/TNodeCore/Runtime/Models/BlackboardDragNodeData.cs @@ -2,19 +2,45 @@ using TNodeCore.Runtime.Attributes; using TNodeCore.Runtime.Attributes.Ports; using TNodeCore.Runtime.RuntimeCache; +using UnityEngine; namespace TNodeCore.Runtime.Models{ [Serializable] [InternalUsage] public class BlackboardDragNodeData:SceneNodeData{ + public string BlackDragData{ + get => blackDragData; + set{ + blackDragData = value; + if (blackDragData.Contains('.')){ + isListElement = true; + } + } + } + public string blackDragData; /// /// it's very hacky way to get blackboard data ,even when the value is null,type info is not null! /// /// TODO : The type handling in a safer way in the future [Output("",PortNameHandling.MemberType,TypeHandling.Implemented)] - public object Value => BlackboardData.GetValue(blackDragData); - + public object Value{ + get{ + if (!isListElement){ + return BlackboardData.GetValue(BlackDragData); + } + else{ + var split = BlackDragData.Split('.'); + Debug.Log(blackDragData); + var index = int.Parse(split[1]); + + return BlackboardData.GetListValue(split[0],index); + } + + } + } + + public bool isListElement=false; public BlackboardDragNodeData(){ } diff --git a/TNode/TNodeCore/Runtime/Models/GraphData.cs b/TNode/TNodeCore/Runtime/Models/GraphData.cs index 3e2b596..a5c4eff 100644 --- a/TNode/TNodeCore/Runtime/Models/GraphData.cs +++ b/TNode/TNodeCore/Runtime/Models/GraphData.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using UnityEditor; using UnityEngine; namespace TNodeCore.Runtime.Models{ [Serializable] public class GraphData:ScriptableObject,ISerializationCallbackReceiver{ + [NonSerialized] public Dictionary NodeDictionary = new Dictionary(); [SerializeReference] @@ -28,8 +30,6 @@ namespace TNodeCore.Runtime.Models{ public void OnBeforeSerialize(){ - - nodeList.Clear(); foreach(var node in NodeDictionary.Values){ nodeList.Add(node); diff --git a/TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs b/TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs index 046bdf3..16636a7 100644 --- a/TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs +++ b/TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -269,6 +270,21 @@ namespace TNodeCore.Runtime.RuntimeCache{ var method = dic.ContainsKey(path) ? dic[path] : null; return method?.Invoke(data); } + public static object GetListValue(this IModel data,string path,int index,Type type=null){ + if(!RuntimeCache.Instance.CachedDelegatesForGettingValue.ContainsKey(type??data.GetType())){ + return null; + } + var dic = RuntimeCache.Instance.CachedDelegatesForGettingValue[type ?? data.GetType()]; + var method = dic.ContainsKey(path) ? dic[path] : null; + if(method == null){ + return null; + } + var list = method.Invoke(data) as IList; + if(list == null){ + return null; + } + return list[index]; + } public static void SetValue(this IModel data,string path,T value,Type type=null){ var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path]; diff --git a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs new file mode 100644 index 0000000..b94a32f --- /dev/null +++ b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections; +using UnityEditor.Experimental.GraphView; +using UnityEngine; +using UnityEngine.UIElements; + +namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{ + public class BlackboardDataEntry:GraphElement{ + public Type propertyType; + public string propertyPath; + public BlackboardDataEntry(Type type){ + propertyType = type; + if (typeof(Component).IsAssignableFrom(propertyType)){ + this.AddToClassList("typeComponent"); + } + if (typeof(GameObject).IsAssignableFrom(propertyType)){ + this.AddToClassList("gameObject"); + } + if (typeof(Vector2).IsAssignableFrom(propertyType)){ + this.AddToClassList("vector"); + } + if (typeof(Vector2Int).IsAssignableFrom(propertyType)){ + this.AddToClassList("vector"); + } + if (typeof(IList).IsAssignableFrom(propertyType)){ + this.AddToClassList("list"); + } + this.capabilities |= Capabilities.Selectable | Capabilities.Deletable | Capabilities.Droppable | Capabilities.Renamable; + this.AddManipulator(new SelectionDropper()); + var styleSheet = Resources.Load("BlackboardDataEntry"); + this.styleSheets.Add(styleSheet); + + this.RegisterCallback((evt) => { + style.borderBottomColor=style.borderRightColor=style.borderLeftColor=style.borderTopColor=new Color(1,1,1,1); + }); + this.RegisterCallback((evt) => { + style.borderBottomColor = style.borderRightColor = + style.borderLeftColor = style.borderTopColor = StyleKeyword.Null; + + }); + + } + } +} \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs.meta b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs.meta new file mode 100644 index 0000000..0ac714c --- /dev/null +++ b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1c0d8e24a45b4ed78454d17047f6cf7e +timeCreated: 1659416220 \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs index 4c6d2ad..36bd89c 100644 --- a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs +++ b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.Reflection; using TNode.TNodeGraphViewImpl.Editor.Search; using TNodeCore.Editor.NodeGraphView; @@ -14,6 +15,7 @@ using UnityEngine.UIElements; namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{ [ViewComponent] public class DefaultGraphBlackboardView:GraphBlackboardView{ + public DefaultGraphBlackboardView():base(){ //the label and the field gap smaller styleSheets.Add( Resources.Load("GraphViewPropertyField")); @@ -21,44 +23,113 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{ } protected override void UpdateBlackboard(BlackboardData data){ if (data == null) return; + this.Clear(); var serializedObject = new SerializedObject((BlackboardDataWrapper)data); var currentGraphView = graphView as IBaseDataGraphView; var isRuntimeGraph = currentGraphView?.IsRuntimeGraph ?? false; + var blackboardGlobalSection = new BlackboardSection{ + title = "Global Data" + }; + Add(blackboardGlobalSection); foreach (var field in data.GetType() .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)){ //if the field is MonoBehaviour,add a property field for blackboard //skip if the field is a list or Ilist - if (!typeof(IList).IsAssignableFrom(field.FieldType)){ - VisualElement visualElement = new VisualElement(); - var propertyField = new BlackboardField(new BlackboardProperty.BlackboardProperty(field.Name,field.FieldType)); - var foldoutData = new Foldout{ - text = ObjectNames.NicifyVariableName(field.Name) - }; - var drawer = new GraphBlackboardPropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name),isRuntimeGraph); - drawer.Bind(serializedObject); - foldoutData.Add(drawer); - visualElement.Add(propertyField); - visualElement.Add(foldoutData); - Add(visualElement); + if (!typeof(IList).IsAssignableFrom(field.FieldType)&&!field.FieldType.IsArray){ + CreateBlackboardDataEntry(field, serializedObject, isRuntimeGraph, blackboardGlobalSection); } else{ var blackboardList = new BlackboardSection{ title = field.Name }; - this.Add(blackboardList); + var foldout = new Foldout{ + text = field.Name, + }; + blackboardList.Add(foldout); + + Add(blackboardList); + if (field.GetValue(data) is IList list){ + for (var i = 0; i < list.Count; i++){ + CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i); + } + } + + if (field.GetValue(data).GetType().IsArray){ + var array = (Array)field.GetValue(data); + for (var i = 0; i < array.Length; i++){ + CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i); + } + } } } - addItemRequested = (sender) => { - var res = ScriptableObject.CreateInstance(); + addItemRequested += (sender) => { + var res = ScriptableObject.CreateInstance(); - //Get right top corner of the blackboard - var blackboardPos = GetPosition().position+OwnerWindow.position.position; - var searchWindowContext = new SearchWindowContext(blackboardPos,200,200); - //Call search window - res.Setup(Owner.GetGraphData().GetType(),Owner,OwnerWindow); - SearchWindow.Open(searchWindowContext, res); + + //Get right top corner of the blackboard + + var blackboardPos = GetPosition().position+OwnerWindow.position.position; + + var searchWindowContext = new SearchWindowContext(blackboardPos,200,200); + + + //Call search window + res.Setup(Owner.GetGraphData().GetType(),Owner,OwnerWindow,this); + + SearchWindow.Open(searchWindowContext, res); + + + }; + } + + private static void CreateBlackboardDataEntryForListItem(FieldInfo field, SerializedObject serializedObject, + bool isRuntimeGraph, + BlackboardSection blackboardSection, int index){ + var property =serializedObject.FindProperty("data").FindPropertyRelative(field.Name).GetArrayElementAtIndex(index); + + BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){ + propertyPath = field.Name+"."+index, + }; + var drawer = + new GraphBlackboardPropertyField(property, + isRuntimeGraph); + drawer.Bind(serializedObject); + entry.Add(drawer); + var container = blackboardSection.Q(); + container.Add(entry); + + } + + private static void CreateBlackboardDataEntry(FieldInfo field, SerializedObject serializedObject, bool isRuntimeGraph, + BlackboardSection blackboardSection){ + BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){ + propertyPath = field.Name + }; + //var propertyField = new BlackboardField(new BlackboardProperty.BlackboardProperty(field.Name,field.FieldType)); + var foldoutData = new Foldout{ + }; + var drawer = + new GraphBlackboardPropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name), + isRuntimeGraph); + drawer.Bind(serializedObject); + foldoutData.Add(drawer); + entry.Add(foldoutData); + blackboardSection.Add(entry); + Label visualElementOverlapFoldoutLabel = new Label(ObjectNames.NicifyVariableName(field.Name)){ + style ={ + //put the label in the position that overlaps the foldout's right side to prevent click + position = Position.Absolute, + left = 20, + alignContent = new StyleEnum(Align.Center), + justifyContent = new StyleEnum(Justify.Center), + unityTextAlign = new StyleEnum(TextAnchor.UpperCenter), + marginTop = 0, + paddingTop = 0 + + } }; + entry.Add(visualElementOverlapFoldoutLabel); + visualElementOverlapFoldoutLabel.BringToFront(); } - } } \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/GraphBlackboardView.cs b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/GraphBlackboardView.cs index b248d9d..7ba13c5 100644 --- a/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/GraphBlackboardView.cs +++ b/TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/GraphBlackboardView.cs @@ -14,11 +14,18 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{ protected EditorWindow OwnerWindow; private T _data; + public void AddItem(){ + + } + public void Setup(IBaseDataGraphView graphView,EditorWindow ownerWindow){ Owner = graphView; OwnerWindow = ownerWindow; } + public void NotifyUpdate(){ + UpdateBlackboard(GetBlackboardData()); + } public new void SetPosition(Rect rect){ @@ -44,8 +51,6 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{ Data = (T) data; } - public void AddItem(){ - - } + } } \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs b/TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs index 7aabeb9..7cf100a 100644 --- a/TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs +++ b/TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using TNode.TNodeGraphViewImpl.Editor.Cache; +using TNode.TNodeGraphViewImpl.Editor.GraphBlackboard; using TNode.TNodeGraphViewImpl.Editor.Inspector; using TNode.TNodeGraphViewImpl.Editor.NodeViews; using TNode.TNodeGraphViewImpl.Editor.Search; @@ -34,6 +35,8 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ private IBlackboardView _blackboard; private bool _runtimeGraphUpdate; + + public T Data{ get{ return _data; } set{ @@ -195,8 +198,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ private void OnInit(){ ConstructDefaultBehaviour(); - OnGraphViewCreate(); + CheckDataAfterInit(); + + OnGraphViewCreate(); + } + + public virtual void AfterEditorLoadGraphView(){ + } protected void CreateMenu(){ @@ -247,11 +256,22 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ //Make a constructor of BlackboardDragNodeData by reflection var dragNodeData = NodeCreator.InstantiateNodeData(); dragNodeData.BlackboardData = GetBlackboardData(); - dragNodeData.blackDragData = field.BlackboardProperty.PropertyName; + dragNodeData.BlackDragData = field.BlackboardProperty.PropertyName; AddTNode(dragNodeData,new Rect(evt.mousePosition,new Vector2(200,200))); } } - + + var blackboardEntries = data.OfType(); + foreach (var selectable in blackboardEntries){ + if(selectable is { } entry) { + //Make a constructor of BlackboardDragNodeData by reflection + var dragNodeData = NodeCreator.InstantiateNodeData(); + dragNodeData.BlackboardData = GetBlackboardData(); + dragNodeData.BlackDragData = entry.propertyPath; + AddTNode(dragNodeData,new Rect(evt.mousePosition,new Vector2(200,200))); + } + } + } } @@ -261,6 +281,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ DragAndDrop.visualMode = DragAndDropVisualMode.Move; //high light the } + } #endregion @@ -523,7 +544,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ public void CreateBlackboard(){ _blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T)); _blackboard.Setup(this,Owner); - + Debug.Log(Owner); var castedBlackboard = _blackboard as Blackboard; Add(castedBlackboard); Rect blackboardPos = new Rect(0,0,300,700); diff --git a/TNode/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs b/TNode/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs index 576d87d..f95f424 100644 --- a/TNode/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs +++ b/TNode/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs @@ -21,13 +21,25 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{ var blackboard = obj.BlackboardData; BlackboardDataWrapper blackboardWrapper = (BlackboardDataWrapper)blackboard; var serializedData = new SerializedObject(blackboardWrapper); - var serializedProperty = serializedData.FindProperty("data").FindPropertyRelative(obj.blackDragData); - - label.text = ObjectNames.NicifyVariableName(obj.blackDragData); - + var arrayElement = obj.isListElement; + SerializedProperty serializedProperty = null; + if (arrayElement){ + var part = obj.BlackDragData.Split('.'); + serializedProperty = serializedData.FindProperty("data").FindPropertyRelative(part[0]).GetArrayElementAtIndex(int.Parse(part[1])); + } + else{ + serializedProperty = serializedData.FindProperty("data").FindPropertyRelative(obj.BlackDragData); + } + label.text = ObjectNames.NicifyVariableName(obj.BlackDragData); //Get serialized property's icon - var icon = AssetPreview.GetMiniThumbnail(serializedProperty.boxedValue as UnityEngine.Object); - + Texture2D icon = null; + if (serializedProperty.boxedValue is Object value){ + icon = AssetPreview.GetMiniThumbnail(value); + } + else{ + icon = AssetPreview.GetMiniTypeThumbnail(serializedProperty.boxedValue.GetType()); + } + label.parent.Add(new Image(){ image = icon }); diff --git a/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss b/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss new file mode 100644 index 0000000..e0ad638 --- /dev/null +++ b/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss @@ -0,0 +1,12 @@ +BlackboardDataEntry{ + border-width: 1px; + border-color: aqua; +} +.typeComponent{ + border-width: 1px; + border-color: rgba(201, 249, 116, 255); +} +.vector{ + border-width: 1px; + border-color: rgba(0.788, 0.969, 0.455, 1.000); +} \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss.meta b/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss.meta new file mode 100644 index 0000000..ea8a49c --- /dev/null +++ b/TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e945d200b8b4056bcf0adeb55f52cc8 +timeCreated: 1659416935 \ No newline at end of file diff --git a/TNode/TNodeGraphViewImpl/Editor/Search/BlackboardSearchWindowProvider.cs b/TNode/TNodeGraphViewImpl/Editor/Search/BlackboardSearchWindowProvider.cs index 2b8e789..fe01ff4 100644 --- a/TNode/TNodeGraphViewImpl/Editor/Search/BlackboardSearchWindowProvider.cs +++ b/TNode/TNodeGraphViewImpl/Editor/Search/BlackboardSearchWindowProvider.cs @@ -1,16 +1,20 @@ using System; using System.Collections; using System.Collections.Generic; +using TNode.TNodeGraphViewImpl.Editor.GraphBlackboard; +using TNodeCore.Editor.Blackboard; using TNodeCore.Editor.NodeGraphView; using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEngine; +using Object = UnityEngine.Object; namespace TNode.TNodeGraphViewImpl.Editor.Search{ public class BlackboardSearchWindowProvider:ScriptableObject,ISearchWindowProvider{ private Type _graphType; private IBaseDataGraphView _graphView; private EditorWindow _editor; + private IBlackboardView _blackboard; private struct InternalSearchTreeUserData{ public IList List; @@ -38,31 +42,49 @@ namespace TNode.TNodeGraphViewImpl.Editor.Search{ List = field.GetValue(blackboardData) as IList, Type = field.FieldType.GetGenericArguments()[0] } - }); } } + + if (field.FieldType.IsArray){ + list.Add(new SearchTreeEntry(new GUIContent(field.Name,icon)){ + level = 1, + userData = new InternalSearchTreeUserData(){ + List = field.GetValue(blackboardData) as Array, + Type = field.FieldType.GetElementType() + } + }); + } } - Debug.Log($"{list.Count}"); return list; } public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context){ var userData = SearchTreeEntry.userData; + if (userData is InternalSearchTreeUserData){ var list = ((InternalSearchTreeUserData) userData).List; + Debug.Log(list); var type = ((InternalSearchTreeUserData) userData).Type; - var newItem = Activator.CreateInstance(type); - list?.Add(newItem); + if (!typeof(Object).IsAssignableFrom(type)){ + var newItem = Activator.CreateInstance(type); + list?.Add(newItem); + } + else{ + var newItem = EditorUtility.InstanceIDToObject(EditorGUIUtility.GetObjectPickerControlID()); + list?.Add(newItem); + } + _blackboard.NotifyUpdate(); return true; } return false; } - public void Setup(Type graph,IBaseDataGraphView graphView,EditorWindow editor){ + public void Setup(Type graph,IBaseDataGraphView graphView,EditorWindow editor,IBlackboardView blackboard){ _graphType = graph; _graphView = graphView; _editor = editor; + _blackboard = blackboard; } }