Merge pull request #16 from taoria/working-in-process

Working in process
main
taoria 3 years ago committed by GitHub
commit 93e540bcc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      TNode/Attribute/BlackboardSection.cs
  2. 3
      TNode/Attribute/BlackboardSection.cs.meta
  3. 2
      TNode/Attribute/Ports/InputAttribute.cs
  4. 4
      TNode/Attribute/Ports/OutputAttribute.cs
  5. 13
      TNode/Attribute/Ports/PortAttribute.cs
  6. 3
      TNode/Editor/Blackboard.meta
  7. 19
      TNode/Editor/Blackboard/IBlackboardView.cs
  8. 3
      TNode/Editor/Blackboard/IBlackboardView.cs.meta
  9. 5
      TNode/Editor/EditorPersistence/GraphEditorData.cs
  10. 4
      TNode/Editor/EditorPersistence/GraphElementEditorData.cs
  11. 6
      TNode/Editor/NodeGraphView/IBaseDataGraphView.cs
  12. 2
      TNode/Editor/NodeGraphView/IDataGraphView.cs
  13. 3
      TNode/Editor/Serialization.meta
  14. 10
      TNode/Editor/Serialization/BlackboardDataWrapper.cs
  15. 3
      TNode/Editor/Serialization/BlackboardDataWrapper.cs.meta
  16. 53
      TNode/Editor/Serialization/DataWrapper.cs
  17. 3
      TNode/Editor/Serialization/DataWrapper.cs.meta
  18. 110
      TNode/Editor/Serialization/NodeDataWrapper.cs
  19. 0
      TNode/Editor/Serialization/NodeDataWrapper.cs.meta
  20. 2
      TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs
  21. 7
      TNode/Editor/Tools/GraphEditorCreator/SourceGeneratorForGraphEditor.cs
  22. 3
      TNode/JsonSerialize.meta
  23. 36
      TNode/JsonSerialize/JsonSerializeTool.cs
  24. 3
      TNode/JsonSerialize/JsonSerializeTool.cs.meta
  25. 42
      TNode/JsonSerialize/NodeDataConverter.cs
  26. 3
      TNode/JsonSerialize/NodeDataConverter.cs.meta
  27. 28
      TNode/JsonSerialize/Vector3Converter.cs
  28. 3
      TNode/JsonSerialize/Vector3Converter.cs.meta
  29. 4
      TNode/Models/BlackboardData.cs
  30. 15
      TNode/Models/BlackboardDragNodeData.cs
  31. 51
      TNode/Models/GraphData.cs
  32. 5
      TNode/RuntimeCache/RuntimeCache.cs
  33. 3
      TNode/Tools.meta
  34. 90
      TNode/Tools/NodeDataWrapper.cs
  35. 0
      TNodeGraphViewImpl/Editor/Cache.meta
  36. 17
      TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs
  37. 0
      TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs.meta
  38. 61
      TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs
  39. 45
      TNodeGraphViewImpl/Editor/GraphBlackboard/GraphBlackboardView.cs
  40. 4
      TNodeGraphViewImpl/Editor/GraphEditor.cs
  41. 0
      TNodeGraphViewImpl/Editor/GraphEditor.cs.meta
  42. 1
      TNodeGraphViewImpl/Editor/Inspector/NodeInspector.cs
  43. 7
      TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
  44. 97
      TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
  45. 1
      TNodeGraphViewImpl/Editor/NodeViews/DefaultNodeView.cs
  46. 7
      TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs
  47. 23
      TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
  48. 3
      TNodeGraphViewImpl/Editor/Resources.meta
  49. 5
      TNodeGraphViewImpl/Editor/Resources/GraphViewPropertyField.uss
  50. 3
      TNodeGraphViewImpl/Editor/Resources/GraphViewPropertyField.uss.meta
  51. 2
      TNodeGraphViewImpl/Editor/Search/NodeSearchWindowProvider.cs

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace TNode.Attribute{
/// <summary>
/// Use this attribute to declare a blackboard section ,a blackboard section is a group of variables with same types
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
[BaseTypeRequired(typeof(List<>))]
public class BlackboardSection:System.Attribute{
}
}

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 773d073006dc4dd488e18b38165efd5a
timeCreated: 1656942977

@ -5,7 +5,7 @@ namespace TNode.Attribute.Ports{
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class InputAttribute : PortAttribute{
public InputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto) : base(name, nameHandling){
public InputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared) : base(name, nameHandling,typeHandling){
}
}
}

@ -1,6 +1,8 @@
namespace TNode.Attribute.Ports{
public class OutputAttribute:PortAttribute{
public OutputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto) : base(name, nameHandling){
public OutputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling = TypeHandling.Declared) : base(name, nameHandling,typeHandling){
}
}
}

@ -9,17 +9,26 @@ namespace TNode.Attribute.Ports{
Manual,
Format,
MemberType
}
public enum TypeHandling{
Declared,
Implemented,
Specified
}
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class PortAttribute:System.Attribute{
public readonly string Name;
public readonly PortNameHandling NameHandling;
public PortAttribute(string name,PortNameHandling nameHandling=PortNameHandling.Auto){
public Type HandledType;
public TypeHandling TypeHandling{ get; set; }
public PortAttribute(string name,PortNameHandling nameHandling=PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared){
this.Name = name;
this.NameHandling = nameHandling;
this.TypeHandling = typeHandling;
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bf3b6f6e73b647e2a5421f482a0b0e8f
timeCreated: 1657686050

@ -0,0 +1,19 @@
using TNode.Editor.NodeGraphView;
using TNode.Models;
using UnityEditor;
using UnityEngine;
namespace TNode.Editor.Blackboard{
public interface IBlackboardView{
public BlackboardData GetBlackboardData();
public void SetBlackboardData(BlackboardData data);
public void AddItem();
void Setup(IBaseDataGraphView graphView,EditorWindow ownerWindow);
}
public interface IBlackboardView<T> : IBlackboardView where T : BlackboardData{
public T Data{ get; set; }
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9c618ca8a5b0444284489b8a1942af91
timeCreated: 1657686059

@ -1,10 +1,7 @@
using System.Collections.Generic;
using TNode.Editor.EditorPersistence;
using TNode.Editor.Model;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNode.Editor{
namespace TNode.Editor.EditorPersistence{
[CreateAssetMenu(fileName = "Graph Editor Data", menuName = "TNode/Graph Editor Data")]
public class GraphEditorData:ScriptableObject{

@ -1,9 +1,7 @@
using System;
using TNode.Models;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNode.Editor.Model{
namespace TNode.Editor.EditorPersistence{
[Serializable]
public class GraphElementEditorData{

@ -5,7 +5,11 @@ namespace TNode.Editor.NodeGraphView{
public interface IBaseDataGraphView{
public void AddTNode(NodeData nodeData, Rect rect);
public void RemoveTNode(NodeData nodeData);
public void CreateBlackboard();
public GraphData GetGraphData();
public BlackboardData GetBlackboardData();
}
}

@ -2,6 +2,6 @@
namespace TNode.Editor.NodeGraphView{
public interface IDataGraphView<T> : IBaseDataGraphView where T:GraphData{
public T Data{ get; set; }
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c1e0017367a4d448a68ed34b7540782
timeCreated: 1657690936

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using TNode.Models;
using UnityEngine;
namespace TNode.Editor.Serialization{
public class BlackboardDataWrapper:DataWrapper<BlackboardDataWrapper,BlackboardData>{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac3fada821244e69b6b9a27a7b94eeee
timeCreated: 1657691334

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using TNode.Models;
using UnityEngine;
namespace TNode.Editor.Serialization{
[Serializable]
public class DataWrapper<TWrapper,TData>:ScriptableObject where TWrapper:DataWrapper<TWrapper,TData> where TData:IModel,new(){
[SerializeReference]
public TData data;
private static readonly Dictionary<TData,TWrapper> Cache = new ();
public static TWrapper Get(TData data){
if (data.GetType().IsGenericType){
return CreateInstance<TWrapper>();
}
if(Cache.ContainsKey(data)){
return Cache[data];
}
var wrapper = CreateInstance<TWrapper>();
wrapper.data = data;
Cache.Add(data,wrapper);
return wrapper;
}
public event Action<DataWrapper<TWrapper,TData>> OnValueChanged;
public void SetValue(string path, object value){
var fieldInfo = data.GetType().GetField(path);
fieldInfo.SetValue(data,value);
OnValueChanged?.Invoke(this);
}
public object GetValue(string path){
var fieldInfo = data.GetType().GetField(path);
return fieldInfo.GetValue(data);
}
public static implicit operator TData(DataWrapper<TWrapper,TData> wrapper){
if (wrapper == null)
return default(TData);
return wrapper.data;
}
/// <summary>
/// Use this to get the wrapped data directly.
/// </summary>
/// <param name="unWrapper"></param>
/// <returns></returns>
public static implicit operator DataWrapper<TWrapper,TData>(TData unWrapper){
if (unWrapper == null)
return null;
return Get(unWrapper);
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3b4407f1670d4359b807377900c83583
timeCreated: 1657693507

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using TNode.Models;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNode.Editor.Serialization{
[Obsolete]
public class NodeDataWrapper<T> : ScriptableObject where T : NodeData{
public T Data;
private static readonly Dictionary<T,NodeDataWrapper<T>> Cache = new ();
public event Action<NodeDataWrapper<T>> OnValueChanged;
public static NodeDataWrapper<T> Get(T data){
if(Cache.ContainsKey(data)){
return Cache[data];
}
var wrapper = ScriptableObject.CreateInstance<NodeDataWrapper<T>>();
Cache.Add(data,wrapper);
return wrapper;
}
public NodeDataWrapper(T data){
this.Data = data;
}
public void SetValue(string path, object value){
var fieldInfo = Data.GetType().GetField(path);
fieldInfo.SetValue(Data,value);
OnValueChanged?.Invoke(this);
}
public object GetValue(string path){
var fieldInfo = Data.GetType().GetField(path);
return fieldInfo.GetValue(Data);
}
public static implicit operator T(NodeDataWrapper<T> wrapper){
if (wrapper == null)
return null;
return wrapper.Data;
}
public static implicit operator NodeDataWrapper<T>(T unWrapper){
if (unWrapper == null)
return null;
return Get(unWrapper);
}
}
public class NodeDataWrapper:DataWrapper<NodeDataWrapper,NodeData>{
}
/// <summary>
/// Scriptable object wrapper enable property drawer for t-node
/// instance create automatically when using get function,generic node data is not support yet because of unity serialization system.
/// TODO : support generic node data
/// </summary>
// public class NodeDataWrapper:ScriptableObject{
// [SerializeReference]
// public NodeData data;
// private static readonly Dictionary<NodeData,NodeDataWrapper> Cache = new ();
// public event Action<NodeDataWrapper> OnValueChanged;
// /// <summary>
// /// Create a new wrapper or get a cached wrapper for the given data
// /// </summary>
// /// <param name="data">node data,an implemented type is acceptable</param>
// /// <returns></returns>
// public static NodeDataWrapper Get(NodeData data){
// if (data.GetType().IsGenericType){
// return CreateInstance<NodeDataWrapper>();
// }
// if(Cache.ContainsKey(data)){
// return Cache[data];
// }
// var wrapper = CreateInstance<NodeDataWrapper>();
// wrapper.data = data;
// Cache.Add(data,wrapper);
// return wrapper;
// }
//
//
// public void SetValue(string path, object value){
// var fieldInfo = data.GetType().GetField(path);
// fieldInfo.SetValue(data,value);
// OnValueChanged?.Invoke(this);
// }
//
// public object GetValue(string path){
// var fieldInfo = data.GetType().GetField(path);
// return fieldInfo.GetValue(data);
// }
// public static implicit operator NodeData(NodeDataWrapper wrapper){
// if (wrapper == null)
// return null;
// return wrapper.data;
//
// }
// /// <summary>
// /// Use this to get the wrapped data directly.
// /// </summary>
// /// <param name="unWrapper"></param>
// /// <returns></returns>
// public static implicit operator NodeDataWrapper(NodeData unWrapper){
// if (unWrapper == null)
// return null;
// return Get(unWrapper);
// }
// }
}

@ -1,6 +1,6 @@
using System.IO;
using System.Text.RegularExpressions;
using TNode.Editor.Model;
using TNode.Editor.EditorPersistence;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using System.Text.RegularExpressions;
using UnityEngine;
namespace TNode.Editor.Tools.GraphEditorCreator{

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ec6119d082a947f58ed6402290b65596
timeCreated: 1656817965

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace TNode.JsonSerialize{
public static class JsonSerializeTool{
class WritablePropertiesOnlyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
return props.Where(p => p.Writable).ToList();
}
}
public static JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings(){
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
DateFormatString = "yyyy-MM-dd HH:mm:ss",
Converters = new List<JsonConverter> { new Vector3Converter() },
TypeNameHandling = TypeNameHandling.Auto,
ContractResolver = new WritablePropertiesOnlyResolver(),
Formatting = Formatting.Indented
};
public static JsonSerializerSettings InternalJsonSerializerSettings = new JsonSerializerSettings(){
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented
};
}
}

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 14067671fe28434e9ae2e67a34074c52
timeCreated: 1656819161

@ -1,42 +0,0 @@
using System;
using Newtonsoft.Json;
using TNode.Models;
using UnityEngine;
namespace TNode.JsonSerialize{
public class NodeDataConverter:JsonConverter<NodeData>{
public override void WriteJson(JsonWriter writer, NodeData value, JsonSerializer serializer){
//Write node data with type information
writer.WriteStartObject();
writer.WritePropertyName("type");
Debug.Log(value.GetType().ToString());
writer.WriteValue(value.GetType().Name);
writer.WritePropertyName("data");
serializer.Serialize(writer, value, value.GetType());
writer.WriteEndObject();
}
public override NodeData ReadJson(JsonReader reader, Type objectType, NodeData existingValue, bool hasExistingValue,
JsonSerializer serializer){
//Load type info
reader.Read();
if (reader.Value != null){
var type = reader.Value.ToString();
if (type.Trim().Length==0){
Debug.LogError(type);
throw new JsonSerializationException("Type name is empty");
}
reader.Read();
//Load data
var data = serializer.Deserialize(reader, Type.GetType(type));
return (NodeData) data;
}
return null;
}
}
}

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6f960539f2744729b35ff3011677d8ba
timeCreated: 1656857829

@ -1,28 +0,0 @@
using System;
using System.Numerics;
using Newtonsoft.Json;
namespace TNode.JsonSerialize{
public class Vector3Converter:JsonConverter<Vector3>{
public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer){
writer.WriteStartArray();
writer.WriteValue(value.X);
writer.WriteValue(value.Y);
writer.WriteValue(value.Z);
writer.WriteEndArray();
}
public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer){
if (reader.TokenType == JsonToken.Null){
return default(Vector3);
}
else{
var array = serializer.Deserialize<float[]>(reader);
if (array != null) return new Vector3(array[0], array[1], array[2]);
}
return default(Vector3);
}
}
}

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: fecb77054ad348239341a58c50549879
timeCreated: 1656817975

@ -1,5 +1,7 @@
namespace TNode.Models{
using System;
namespace TNode.Models{
[Serializable]
public class BlackboardData:IModel{
}

@ -4,15 +4,18 @@ using Newtonsoft.Json;
using TNode.Attribute;
using TNode.Attribute.Ports;
using TNode.RuntimeCache;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNode.Models{
public class BlackboardDragNodeData<T>:NodeData{
private string _blackDragData;
[JsonIgnore]
private BlackboardData _blackboardData;
[Serializable]
public class BlackboardDragNodeData:NodeData{
public string blackDragData;
[SerializeReference]
public BlackboardData blackboardData;
[Output("",PortNameHandling.MemberType)]
public T Value => _blackboardData.GetValue<T>(_blackDragData);
[Output("",PortNameHandling.MemberType,TypeHandling.Implemented)]
public object Value => blackboardData.GetValue(blackDragData);
public BlackboardDragNodeData(){

@ -1,38 +1,45 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using TNode.Editor;
using TNode.JsonSerialize;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNode.Models{
[Serializable]
public class GraphData:ScriptableObject,ISerializationCallbackReceiver{
[SerializeField]
public Dictionary<string,NodeData> NodeDictionary = new Dictionary<string,NodeData>();
public List<NodeLink> nodeLinks = new();
public BlackboardData blackboardData = new();
[TextArea(1,10)]
[SerializeReference]
public List<NodeData> nodeList = new List<NodeData>();
[SerializeField]
//[HideInInspector]
private string jsonObject;
[TextArea(1,10)]
[SerializeField]
private string jsonBlackboard;
protected List<NodeLink> nodeLinks;
[SerializeReference]
public BlackboardData blackboardData;
public List<NodeLink> NodeLinks{
get{
return nodeLinks ??= new List<NodeLink>();
}
set => nodeLinks = value;
}
public void OnBeforeSerialize(){
jsonObject = JsonConvert.SerializeObject(NodeDictionary,JsonSerializeTool.JsonSerializerSettings);
jsonBlackboard = JsonConvert.SerializeObject(blackboardData,JsonSerializeTool.JsonSerializerSettings);
nodeList.Clear();
foreach(var node in NodeDictionary.Values){
nodeList.Add(node);
}
}
public void OnAfterDeserialize(){
//Deserialize node dictionary
var deserializedData = JsonConvert.DeserializeObject<Dictionary<string,NodeData>>(jsonObject,JsonSerializeTool.JsonSerializerSettings);
NodeDictionary = deserializedData;
//Deserialize blackboard data
var deserializedBlackboard = JsonConvert.DeserializeObject<BlackboardData>(jsonBlackboard,JsonSerializeTool.JsonSerializerSettings);
blackboardData = deserializedBlackboard;
NodeDictionary.Clear();
foreach(var node in nodeList){
NodeDictionary.Add(node.id,node);
}
}
}
}

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using EasyRandomGenerator.Blackboard;
using JetBrains.Annotations;
using TNode.Models;
using Unity.VisualScripting;
@ -21,6 +22,10 @@ namespace TNode.RuntimeCache{
new ();
private static readonly string[] ExcludedAssemblies = new string[]{"Microsoft", "UnityEngine","UnityEditor","mscorlib","System"};
public RuntimeCache(){
RegisterRuntimeBlackboard(typeof(EasyBlackboardData));
}
public void RegisterRuntimeBlackboard(Type type){
if(!CachedDelegatesForGettingValue.ContainsKey(type)){
CachedDelegatesForGettingValue.Add(type, new Dictionary<string, GetValueDelegate>());

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 206b9a7ba6b54706b02c6aa2cb9a18b0
timeCreated: 1656762017

@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using TNode.Models;
using UnityEngine;
namespace TNode.Editor{
/// <summary>
/// Scriptable object wrapper enable property drawer for t-node
/// </summary>
public class NodeDataWrapper<T> : ScriptableObject where T : NodeData{
public T Data;
private static readonly Dictionary<T,NodeDataWrapper<T>> Cache = new ();
public event Action<NodeDataWrapper<T>> OnValueChanged;
public static NodeDataWrapper<T> Get(T data){
if(Cache.ContainsKey(data)){
return Cache[data];
}
var wrapper = ScriptableObject.CreateInstance<NodeDataWrapper<T>>();
Cache.Add(data,wrapper);
return wrapper;
}
public NodeDataWrapper(T data){
this.Data = data;
}
public void SetValue(string path, object value){
var fieldInfo = Data.GetType().GetField(path);
fieldInfo.SetValue(Data,value);
OnValueChanged?.Invoke(this);
}
public object GetValue(string path){
var fieldInfo = Data.GetType().GetField(path);
return fieldInfo.GetValue(Data);
}
public static implicit operator T(NodeDataWrapper<T> wrapper){
if (wrapper == null)
return null;
return wrapper.Data;
}
public static implicit operator NodeDataWrapper<T>(T unWrapper){
if (unWrapper == null)
return null;
return Get(unWrapper);
}
}
public class NodeDataWrapper:ScriptableObject{
[SerializeReference]
public NodeData Data;
private static readonly Dictionary<NodeData,NodeDataWrapper> Cache = new ();
public event Action<NodeDataWrapper> OnValueChanged;
public static NodeDataWrapper Get(NodeData data){
if (data.GetType().IsGenericType){
return ScriptableObject.CreateInstance<NodeDataWrapper>();
}
if(Cache.ContainsKey(data)){
return Cache[data];
}
var wrapper = ScriptableObject.CreateInstance<NodeDataWrapper>();
wrapper.Data = data;
Cache.Add(data,wrapper);
return wrapper;
}
public void SetValue(string path, object value){
var fieldInfo = Data.GetType().GetField(path);
fieldInfo.SetValue(Data,value);
OnValueChanged?.Invoke(this);
}
public object GetValue(string path){
var fieldInfo = Data.GetType().GetField(path);
return fieldInfo.GetValue(Data);
}
public static implicit operator NodeData(NodeDataWrapper wrapper){
if (wrapper == null)
return null;
return wrapper.Data;
}
public static implicit operator NodeDataWrapper(NodeData unWrapper){
if (unWrapper == null)
return null;
return Get(unWrapper);
}
}
}

@ -3,16 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using TNode.Attribute;
using TNode.Editor;
using TNode.Editor.Inspector;
using TNode.Editor.Blackboard;
using TNode.Editor.NodeViews;
using TNode.Models;
using TNodeGraphViewImpl.Editor.GraphBlackboard;
using TNodeGraphViewImpl.Editor.NodeGraphView;
using TNodeGraphViewImpl.Editor.NodeViews;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.TestTools.Utils;
namespace TNode.Cache{
namespace TNodeGraphViewImpl.Editor.Cache{
/// <summary>
/// Internal singleton class for caching TNode reflection Data.
/// </summary>
@ -153,14 +153,14 @@ namespace TNode.Cache{
return null;
}
public static Blackboard CreateBlackboardDataFromBlackboardDataType(Type t){
public static IBlackboardView CreateBlackboardDataFromBlackboardDataType(Type t){
var type = typeof(GraphBlackboardView<>).MakeGenericType(t);
var res = CreateViewComponentFromBaseType(type) as Blackboard;
var res = CreateViewComponentFromBaseType(type) as IBlackboardView;
return res ?? new DefaultGraphBlackboardView();
}
public static Blackboard CreateBlackboardWithGraphData(GraphData graphData){
public static IBlackboardView CreateBlackboardWithGraphData(GraphData graphData){
var graphType = graphData.GetType();
if (NodeEditorSingleton.Instance.GraphBlackboard.ContainsKey(graphType)){
var type = NodeEditorSingleton.Instance.GraphBlackboard[graphType];
@ -169,7 +169,7 @@ namespace TNode.Cache{
}
return null;
}
public static Blackboard CreateBlackboardWithGraphData(Type graphType){
public static IBlackboardView CreateBlackboardWithGraphData(Type graphType){
if (NodeEditorSingleton.Instance.GraphBlackboard.ContainsKey(graphType)){
var type = NodeEditorSingleton.Instance.GraphBlackboard[graphType];
return CreateBlackboardDataFromBlackboardDataType(type);
@ -201,7 +201,6 @@ namespace TNode.Cache{
//Check the generic type of BaseNodeView by t
if (t.IsGenericType){
Debug.Log($"A generic type {t} is detected");
//AKA if BlackboardDragNodeData<Camera> is pulled
//Get BlackboardDragNodeData<T> as generic type
@ -210,14 +209,12 @@ namespace TNode.Cache{
//What you want is a BaseNodeView<BlackboardDragNodeData<T>> to be created
var genericViewType = typeof(BaseNodeView<>).MakeGenericType(genericTypeDefinition);
Debug.Log($"The generic view type is {genericViewType}");
//search for the specific type of genericViewType in the dictionary
if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(genericViewType)){
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[genericViewType];
//The implementedType is still a generic type ,so we make it a specific type by using MakeGenericType
Debug.Log($"{implementedType}");
//Get argument type of t
var argumentType = t.GetGenericArguments()[0];
var instance = Activator.CreateInstance(implementedType.MakeGenericType(argumentType));

@ -1,17 +1,62 @@
using TNode.Attribute;
using System.Collections;
using System.Reflection;
using TNode.Attribute;
using TNode.Editor.NodeGraphView;
using TNode.Editor.Search;
using TNode.Editor.Serialization;
using TNode.Models;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNodeGraphViewImpl.Editor.GraphBlackboard{
[ViewComponent]
public class DefaultGraphBlackboardView:GraphBlackboardView<BlackboardData>{
public DefaultGraphBlackboardView(){
public DefaultGraphBlackboardView():base(){
//the label and the field gap smaller
styleSheets.Add( Resources.Load<StyleSheet>("GraphViewPropertyField"));
}
public void ConstructView(){
}
public void AddParameter(){
protected override void UpdateBlackboard(BlackboardData data){
var serializedObject = new SerializedObject((BlackboardDataWrapper)data);
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 BlackboardPropertyField(new BlackboardProperty.BlackboardProperty(field.Name,field.FieldType));
var foldoutData = new Foldout{
text = field.Name
};
var drawer = new PropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name),field.Name);
drawer.Bind(serializedObject);
foldoutData.Add(drawer);
visualElement.Add(propertyField);
visualElement.Add(foldoutData);
this.Add(visualElement);
}
else{
var blackboardList = new BlackboardSection{
title = field.Name
};
this.Add(blackboardList);
}
}
addItemRequested = (sender) => {
var res = ScriptableObject.CreateInstance<BlackboardSearchWindowProvider>();
//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);
};
}
}
}

@ -1,15 +1,52 @@
using TNode.Models;
using TNode.Editor.Blackboard;
using TNode.Editor.NodeGraphView;
using TNode.Editor.Search;
using TNode.Models;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
namespace TNodeGraphViewImpl.Editor.GraphBlackboard{
/// <summary>
/// Implement this class to create graph black board for specified graph
/// </summary>
public class GraphBlackboardView<T>:Blackboard where T:BlackboardData{
public T BlackboardData;
public class GraphBlackboardView<T>:Blackboard,IBlackboardView<T> where T:BlackboardData{
protected IBaseDataGraphView Owner;
protected EditorWindow OwnerWindow;
private T _data;
public GraphBlackboardView() : base(){
public void Setup(IBaseDataGraphView graphView,EditorWindow ownerWindow){
Owner = graphView;
OwnerWindow = ownerWindow;
}
public new void SetPosition(Rect rect){
}
protected virtual void UpdateBlackboard(BlackboardData data){
}
public T Data{
get => (T) _data;
set{
_data = value;
UpdateBlackboard(value);
}
}
public BlackboardData GetBlackboardData(){
return _data;
}
public void SetBlackboardData(BlackboardData data){
Data = (T) data;
}
public void AddItem(){
}
}
}

@ -1,8 +1,8 @@
using Codice.CM.Common;
using TNode.Cache;
using TNode.Editor.EditorPersistence;
using TNode.Editor.Inspector;
using TNode.Editor.Model;
using TNode.Models;
using TNodeGraphViewImpl.Editor.Cache;
using TNodeGraphViewImpl.Editor.NodeGraphView;
using UnityEditor;
using UnityEditor.Experimental.GraphView;

@ -5,6 +5,7 @@ using TNode.Attribute;
using TNode.Editor.NodeViews;
using TNode.Models;
using TNodeGraphViewImpl.Editor.NodeGraphView;
using TNodeGraphViewImpl.Editor.NodeViews;
using Unity.VisualScripting;
using UnityEditor;
using UnityEditor.Experimental.GraphView;

@ -1,5 +1,6 @@
using System.Reflection;
using TNode.Attribute;
using TNode.Editor.Serialization;
using TNode.Models;
using UnityEditor;
using UnityEditor.UIElements;
@ -37,7 +38,7 @@ namespace TNode.Editor.Inspector{
private void RefreshPropertyDrawer(){
//Check if the data's type is a generic type of BlackboardDragNodeData<>
if (_data.GetType().IsSubclassOf(typeof(BlackboardDragNodeData<>))){
if (_data.GetType().IsSubclassOf(typeof(BlackboardDragNodeData))){
return;
}
var serializedObject = new SerializedObject((NodeDataWrapper)_data);
@ -47,11 +48,11 @@ namespace TNode.Editor.Inspector{
var showInNodeViewAttribute = field.GetCustomAttribute<ShowInNodeViewAttribute>() != null;
if (!showInNodeViewAttribute)
continue;
var drawer = new PropertyField(serializedObject.FindProperty("Data").FindPropertyRelative(field.Name),field.Name);
Debug.Log(serializedObject.FindProperty("Data"));
var drawer = new PropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name),field.Name);
drawer.Bind(serializedObject);
Add(drawer);
}
}
}
}

@ -3,17 +3,19 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TNode.Cache;
using TNode.Editor;
using TNode.Editor.Blackboard;
using TNode.Editor.EditorPersistence;
using TNode.Editor.Inspector;
using TNode.Editor.Model;
using TNode.Editor.NodeGraphView;
using TNode.Editor.NodeViews;
using TNode.Editor.Search;
using TNode.Editor.Tools.NodeCreator;
using TNode.Models;
using TNodeGraphViewImpl.Editor.Cache;
using TNodeGraphViewImpl.Editor.GraphBlackboard;
using TNodeGraphViewImpl.Editor.GraphBlackboard.BlackboardProperty;
using TNodeGraphViewImpl.Editor.NodeViews;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
@ -21,7 +23,7 @@ using UnityEngine.UIElements;
using Edge = UnityEditor.Experimental.GraphView.Edge;
namespace TNodeGraphViewImpl.Editor.NodeGraphView{
public abstract class BaseDataGraphView<T>:GraphView,IBaseDataGraphView where T:GraphData{
public abstract class BaseDataGraphView<T>:GraphView,IDataGraphView<T> where T:GraphData{
#region variables and properties
private T _data;
private bool _isInspectorOn;
@ -29,7 +31,7 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
private NodeInspector _nodeInspector;
public GraphEditor<T> Owner;
private Dictionary<string,Node> _nodeDict = new();
private Blackboard _blackboard;
private IBlackboardView _blackboard;
public T Data{
get{ return _data; }
set{
@ -103,11 +105,10 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
foreach (var selectable in blackboardFields){
if(selectable is { } field) {
//Make a constructor of BlackboardDragNodeData<field.PropertyType > by reflection
var specifiedType =
typeof(BlackboardDragNodeData<>).MakeGenericType(field.BlackboardProperty.PropertyType);
//Create a new instance of specified type
var dragNodeData = NodeCreator.InstantiateNodeData(specifiedType);
this.AddTNode(dragNodeData,new Rect(evt.mousePosition,new Vector2(200,200)));
var dragNodeData = NodeCreator.InstantiateNodeData<BlackboardDragNodeData>();
dragNodeData.blackboardData = _data.blackboardData;
dragNodeData.blackDragData = field.BlackboardProperty.PropertyName;
AddTNode(dragNodeData,new Rect(evt.mousePosition,new Vector2(200,200)));
}
}
@ -155,7 +156,7 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
AddTNode(dataNode,nodePos);
}
foreach (var edge in _data.nodeLinks){
foreach (var edge in _data.NodeLinks){
var inputNode = _data.NodeDictionary[edge.inPort.nodeDataId];
var outputNode = _data.NodeDictionary[edge.outPort.nodeDataId];
var inputNodeView = _nodeDict[inputNode.id];
@ -191,47 +192,15 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
miniMap.SetPosition(rect);
}
public virtual void CreateBlackboard(){
_blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T));
_blackboard.SetPosition(new Rect(0,0,200,600));
Add(_blackboard);
OnDataChanged+= (sender, e) => { BlackboardUpdate(); };
}
private void BlackboardUpdate(){
if (_data.blackboardData == null || _data.blackboardData.GetType() == typeof(BlackboardData)){
if (_data.blackboardData == null || _data.blackboardData.GetType()==(typeof(BlackboardData))){
_data.blackboardData = NodeEditorExtensions.GetAppropriateBlackboardData(_data.GetType());
if (_data.blackboardData == null) return;
}
//Iterate field of the blackboard and add a button for each field
foreach (var field in _data.blackboardData.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)){
var propertyField = new BlackboardPropertyField(new BlackboardProperty(field.Name,field.FieldType));
_blackboard.Add(propertyField);
}
}
_blackboard.addItemRequested = (sender) => {
var res = ScriptableObject.CreateInstance<BlackboardSearchWindowProvider>();
//Get right top corner of the blackboard
var blackboardPos = _blackboard.GetPosition().position;
var searchWindowContext = new SearchWindowContext(blackboardPos,200,200);
//Call search window
res.Setup(typeof(T),this,Owner);
SearchWindow.Open(searchWindowContext, res);
};
}
_blackboard.SetBlackboardData(_data.blackboardData);
}
public virtual void DestroyInspector(){
@ -304,17 +273,23 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
}
_data.nodeLinks = links;
_data.NodeLinks = links;
}
private void SaveGraphData(){
_data.NodeDictionary.Clear();
_data.nodeLinks.Clear();
_data.NodeLinks.Clear();
SaveNode();
SaveEdge();
SaveBlackboard();
EditorUtility.SetDirty(_data);
}
private void SaveBlackboard(){
if (_data.blackboardData == null){
_data.blackboardData = NodeEditorExtensions.GetAppropriateBlackboardData(_data.GetType());
}
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){
return ports.Where(x => x.portType == startPort.portType).ToList();
@ -330,10 +305,7 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
OnGraphViewDestroy();
}
public bool IsDroppable(){
return true;
}
#region implement interfaces
public void AddTNode(NodeData nodeData, Rect rect){
if (NodeEditorExtensions.CreateNodeViewFromNodeType(nodeData.GetType()) is Node nodeView){
nodeView.SetPosition(rect);
@ -381,9 +353,30 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
Owner.graphEditorData.graphElementsData.RemoveAll(x => x.guid == nodeData.id);
}
public void CreateBlackboard(){
_blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T));
_blackboard.Setup(this,Owner);
var castedBlackboard = _blackboard as Blackboard;
Add(castedBlackboard);
Rect blackboardPos = new Rect(0,0,300,700);
castedBlackboard?.SetPosition(blackboardPos);
OnDataChanged+= (sender, e) => { BlackboardUpdate(); };
}
public GraphData GetGraphData(){
return _data;
}
public BlackboardData GetBlackboardData(){
return this._data.blackboardData;
}
#endregion
}

@ -1,5 +1,6 @@
using TNode.Editor.NodeViews;
using TNode.Models;
using TNodeGraphViewImpl.Editor.NodeViews;
namespace TNode.Editor{

@ -1,13 +1,12 @@
using TNode.Attribute;
using TNode.Models;
using TNodeGraphViewImpl.Editor.NodeViews;
namespace TNode.Editor.NodeViews{
[ViewComponent]
public class DragBaseNodeView<T>:BaseNodeView<BlackboardDragNodeData<T>>{
public class DragBaseNodeView:BaseNodeView<BlackboardDragNodeData>{
public DragBaseNodeView() : base(){
//Make capsule like style
this.titleContainer.visible = false;
this.titleContainer.visible = false;
this.titleContainer.RemoveFromHierarchy();
}
}

@ -1,15 +1,15 @@
using System;
using System.Linq;
using System.Reflection;
using TNode.Attribute;
using TNode.Attribute.Ports;
using TNode.Editor.Inspector;
using TNode.Editor.Serialization;
using TNode.Models;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNode.Editor.NodeViews{
namespace TNodeGraphViewImpl.Editor.NodeViews{
public abstract class BaseNodeView<T> : Node,INodeView<T> where T:NodeData,new(){
protected T _data;
@ -28,10 +28,9 @@ namespace TNode.Editor.NodeViews{
}
}
private void OnDataValueChanged(NodeDataWrapper obj){
private void OnDataValueChanged(DataWrapper<NodeDataWrapper, NodeData> obj){
Refresh();
}
public sealed override string title{
get => base.title;
set => base.title = value;
@ -77,6 +76,18 @@ namespace TNode.Editor.NodeViews{
throw new ArgumentOutOfRangeException();
}
}
protected virtual Type BuildPortType(PortAttribute portAttribute,PropertyInfo propertyInfo){
switch (portAttribute.TypeHandling){
case TypeHandling.Declared :
return propertyInfo.PropertyType;
case TypeHandling.Implemented:
return propertyInfo.GetValue(_data)?.GetType();
case TypeHandling.Specified:
return portAttribute.HandledType??typeof(object);
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// of course you can override this method to build your own port builder
/// </summary>
@ -85,7 +96,7 @@ namespace TNode.Editor.NodeViews{
foreach (var propertyInfo in propertyInfos){
if (propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true).FirstOrDefault() is OutputAttribute attribute){
Port port = InstantiatePort(Orientation.Horizontal, Direction.Output,Port.Capacity.Multi,propertyInfo.PropertyType);
Port port = InstantiatePort(Orientation.Horizontal, Direction.Output,Port.Capacity.Multi,BuildPortType(attribute,propertyInfo));
this.outputContainer.Add(port);
var portName = BuildPortName(attribute,propertyInfo);
port.portName = portName;
@ -94,7 +105,7 @@ namespace TNode.Editor.NodeViews{
}
foreach (var propertyInfo in propertyInfos){
if(propertyInfo.GetCustomAttributes(typeof(InputAttribute),true).FirstOrDefault() is InputAttribute attribute){
Port port = InstantiatePort(Orientation.Horizontal, Direction.Input,Port.Capacity.Single,propertyInfo.PropertyType);
Port port = InstantiatePort(Orientation.Horizontal, Direction.Input,Port.Capacity.Single,BuildPortType(attribute,propertyInfo));
this.inputContainer.Add(port);
var portName = BuildPortName(attribute,propertyInfo);
port.portName = portName;

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d628735dd6d477c88ed608b684c50b4
timeCreated: 1657702172

@ -0,0 +1,5 @@
.unity-property-field__label {
width: 75px;
min-width: 100px;
max-width: 150px;
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2b84790a3a0445f894b9c496ad1e716b
timeCreated: 1657702197

@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using TNode.Cache;
using TNode.Editor.NodeGraphView;
using TNode.Editor.Tools.NodeCreator;
using TNode.Models;
using TNodeGraphViewImpl.Editor.Cache;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

Loading…
Cancel
Save