From a8b5020e69e57ee7a7813f3584284a11ed8b0064 Mon Sep 17 00:00:00 2001 From: taoria <445625470@qq.com> Date: Tue, 28 Jun 2022 16:02:40 +0800 Subject: [PATCH 1/3] 1.now graph can create node automatically --- Sample/Editor/HelloGraphView.cs | 6 +- Sample/{Editor => }/HelloGraph.cs | 0 Sample/{Editor => }/HelloGraph.cs.meta | 0 Sample/HelloNode.cs | 10 + Sample/HelloNode.cs.meta | 3 + Scenes/SampleScene.unity | 337 ++++++++++++++++++ .../Attribute/AssetMenuCreateAsGraphEditor.cs | 12 - .../AssetMenuCreateAsGraphEditor.cs.meta | 3 - TNode/Attribute/GraphUsageAttribute.cs | 26 ++ TNode/Attribute/GraphUsageAttribute.cs.meta | 3 + .../Editor/BaseViews/SimpleGraphSubWindow.cs | 1 + TNode/Editor/Cache/NodeEditorExtensions.cs | 98 ++++- TNode/Editor/DefaultNodeView.cs | 8 + TNode/Editor/DefaultNodeView.cs.meta | 3 + TNode/Editor/GraphEditor.cs | 7 +- .../Inspector/DefaultInspectorItemFactory.cs | 2 +- TNode/Editor/Inspector/NodeInspector.cs | 2 + ...{NodeInsepctor.uxml => NodeInspector.uxml} | 0 ...ctor.uxml.meta => NodeInspector.uxml.meta} | 0 TNode/Editor/SearchWindowProvider.cs | 42 ++- TNode/TNodeSample.meta | 3 - TNode/TNodeSample/GraphViewTest.cs | 8 - TNode/TNodeSample/GraphViewTest.cs.meta | 3 - TNode/TNodeSample/NodeDataTest.cs | 15 - TNode/TNodeSample/NodeDataTest.cs.meta | 3 - 25 files changed, 527 insertions(+), 68 deletions(-) rename Sample/{Editor => }/HelloGraph.cs (100%) rename Sample/{Editor => }/HelloGraph.cs.meta (100%) create mode 100644 Sample/HelloNode.cs create mode 100644 Sample/HelloNode.cs.meta delete mode 100644 TNode/Attribute/AssetMenuCreateAsGraphEditor.cs delete mode 100644 TNode/Attribute/AssetMenuCreateAsGraphEditor.cs.meta create mode 100644 TNode/Attribute/GraphUsageAttribute.cs create mode 100644 TNode/Attribute/GraphUsageAttribute.cs.meta create mode 100644 TNode/Editor/DefaultNodeView.cs create mode 100644 TNode/Editor/DefaultNodeView.cs.meta rename TNode/Editor/Resources/{NodeInsepctor.uxml => NodeInspector.uxml} (100%) rename TNode/Editor/Resources/{NodeInsepctor.uxml.meta => NodeInspector.uxml.meta} (100%) delete mode 100644 TNode/TNodeSample.meta delete mode 100644 TNode/TNodeSample/GraphViewTest.cs delete mode 100644 TNode/TNodeSample/GraphViewTest.cs.meta delete mode 100644 TNode/TNodeSample/NodeDataTest.cs delete mode 100644 TNode/TNodeSample/NodeDataTest.cs.meta diff --git a/Sample/Editor/HelloGraphView.cs b/Sample/Editor/HelloGraphView.cs index 819917f..9d2de3e 100644 --- a/Sample/Editor/HelloGraphView.cs +++ b/Sample/Editor/HelloGraphView.cs @@ -1,9 +1,13 @@ using TNode.Attribute; using TNode.Editor.BaseViews; +using TNode.Editor.Inspector; namespace Sample.Editor{ [NodeComponent] public class HelloGraphView : DataGraphView{ - + public override void OnGraphViewCreate(){ + NodeInspector inspector = new NodeInspector(); + this.Add(inspector); + } } } \ No newline at end of file diff --git a/Sample/Editor/HelloGraph.cs b/Sample/HelloGraph.cs similarity index 100% rename from Sample/Editor/HelloGraph.cs rename to Sample/HelloGraph.cs diff --git a/Sample/Editor/HelloGraph.cs.meta b/Sample/HelloGraph.cs.meta similarity index 100% rename from Sample/Editor/HelloGraph.cs.meta rename to Sample/HelloGraph.cs.meta diff --git a/Sample/HelloNode.cs b/Sample/HelloNode.cs new file mode 100644 index 0000000..b8dd3d0 --- /dev/null +++ b/Sample/HelloNode.cs @@ -0,0 +1,10 @@ +using Sample.Editor; +using TNode.Attribute; +using TNode.Models; + +namespace Sample{ + [GraphUsage(typeof(HelloGraph))] + public class HelloNode:NodeData{ + + } +} \ No newline at end of file diff --git a/Sample/HelloNode.cs.meta b/Sample/HelloNode.cs.meta new file mode 100644 index 0000000..0b740d3 --- /dev/null +++ b/Sample/HelloNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 928bb3292c464ae0b811455e9f4e8667 +timeCreated: 1656391464 \ No newline at end of file diff --git a/Scenes/SampleScene.unity b/Scenes/SampleScene.unity index 9421266..2be4338 100644 --- a/Scenes/SampleScene.unity +++ b/Scenes/SampleScene.unity @@ -123,6 +123,107 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &507038906 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 507038910} + - component: {fileID: 507038909} + - component: {fileID: 507038908} + - component: {fileID: 507038907} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &507038907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507038906} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &507038908 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507038906} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &507038909 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507038906} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &507038910 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507038906} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} --- !u!1 &519420028 GameObject: m_ObjectHideFlags: 0 @@ -202,7 +303,243 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &691266389 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 691266390} + - component: {fileID: 691266391} + m_Layer: 0 + m_Name: Circle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &691266390 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691266389} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.79506373, y: 0.7908081, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1608359614} + m_RootOrder: -1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!331 &691266391 +SpriteMask: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691266389} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10758, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: -2413806693520163455, guid: a86470a33a6bf42c4b3595704624658b, type: 3} + m_MaskAlphaCutoff: 0.2 + m_FrontSortingLayerID: 0 + m_BackSortingLayerID: 0 + m_FrontSortingLayer: 0 + m_BackSortingLayer: 0 + m_FrontSortingOrder: 0 + m_BackSortingOrder: 0 + m_IsCustomRangeActive: 0 + m_SpriteSortPoint: 0 +--- !u!1 &1608359612 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1608359614} + - component: {fileID: 1608359613} + m_Layer: 0 + m_Name: Circle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!212 &1608359613 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1608359612} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Sprite: {fileID: -2413806693520163455, guid: a86470a33a6bf42c4b3595704624658b, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 1, y: 1} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 2 + m_SpriteSortPoint: 0 +--- !u!4 &1608359614 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1608359612} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 16.183, y: 14.154, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 691266390} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1701140682 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1701140685} + - component: {fileID: 1701140684} + - component: {fileID: 1701140683} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1701140683 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1701140682} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1701140684 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1701140682} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1701140685 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1701140682} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs b/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs deleted file mode 100644 index 38af2b1..0000000 --- a/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using JetBrains.Annotations; -using UnityEngine; - -namespace TNode.Attribute{ - [MeansImplicitUse] - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - [BaseTypeRequired(typeof(ScriptableObject))] - public class AssetMenuCreateAsGraphEditorAttribute:System.Attribute{ - - } -} \ No newline at end of file diff --git a/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs.meta b/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs.meta deleted file mode 100644 index e908835..0000000 --- a/TNode/Attribute/AssetMenuCreateAsGraphEditor.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 536eae3bd21b49609d88e3bd24b4d7d0 -timeCreated: 1656038984 \ No newline at end of file diff --git a/TNode/Attribute/GraphUsageAttribute.cs b/TNode/Attribute/GraphUsageAttribute.cs new file mode 100644 index 0000000..4cc6b1f --- /dev/null +++ b/TNode/Attribute/GraphUsageAttribute.cs @@ -0,0 +1,26 @@ +using System; +using JetBrains.Annotations; +using TNode.Models; +using Unity.VisualScripting; + +namespace TNode.Attribute{ + /// + /// Use this attribute to claim the usage of a type of node on the derived NodeData class. + /// it can be applied to the same node multiple times. + /// + /// [GraphUsage(DialogueGraph)] + /// + /// + [AttributeUsage(AttributeTargets.Class)] + [BaseTypeRequired(typeof(NodeData))] + public class GraphUsageAttribute:System.Attribute{ + public Type GraphDataType; + public GraphUsageAttribute(Type t){ + //check if the type t is graph + if(!typeof(GraphData).IsAssignableFrom(t)){ + throw new Exception("The type must be a graph"); + } + GraphDataType = t; + } + } +} \ No newline at end of file diff --git a/TNode/Attribute/GraphUsageAttribute.cs.meta b/TNode/Attribute/GraphUsageAttribute.cs.meta new file mode 100644 index 0000000..bc8dab3 --- /dev/null +++ b/TNode/Attribute/GraphUsageAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 25593dbfe27b42809a2a38eae3458521 +timeCreated: 1656389642 \ No newline at end of file diff --git a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs index b81282b..26be881 100644 --- a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs +++ b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs @@ -7,6 +7,7 @@ namespace TNode.BaseViews{ private readonly Dragger _dragger = new Dragger(); protected void ConstructWindowBasicSetting(){ + style.position = new StyleEnum(Position.Absolute); RegisterCallback(evt => { evt.StopPropagation(); }); focusable = false; capabilities |= Capabilities.Movable | Capabilities.Resizable; diff --git a/TNode/Editor/Cache/NodeEditorExtensions.cs b/TNode/Editor/Cache/NodeEditorExtensions.cs index 4d8f57b..22909e1 100644 --- a/TNode/Editor/Cache/NodeEditorExtensions.cs +++ b/TNode/Editor/Cache/NodeEditorExtensions.cs @@ -1,38 +1,80 @@ using System; using System.Collections.Generic; +using System.Linq; using TNode.Attribute; using TNode.BaseViews; +using TNode.Editor; using TNode.Editor.BaseViews; +using TNode.Models; +using UnityEditor.Experimental.GraphView; using UnityEngine; namespace TNode.Cache{ + /// + /// Internal singleton class for caching TNode reflection Data. + /// internal class NodeEditorSingleton{ private static NodeEditorSingleton _instance; public readonly Dictionary FromGenericToSpecific = new Dictionary(); + public readonly Dictionary> GraphDataUsage = new Dictionary>(); public static NodeEditorSingleton Instance{ get{ return _instance ??= new NodeEditorSingleton(); } } + + private static readonly string[] ExcludedAssemblies = new string[]{"Microsoft", "UnityEngine","UnityEditor","mscorlib","System"}; + private NodeEditorSingleton(){ - foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies()){ + //exclude unity ,system ,and microsoft types + var assemblies = AppDomain. + CurrentDomain.GetAssemblies() + .Where(x=>ExcludedAssemblies.All(y=>!x.GetName().Name.Split(".")[0].Equals(y))); + + foreach(var assembly in assemblies){ foreach(var type in assembly.GetTypes()){ if(type.IsClass && !type.IsAbstract){ - foreach(var attribute in type.GetCustomAttributes(typeof(NodeComponentAttribute), false)){ - //fetch this type 's parent class - var parent = type.BaseType; - //Check if this type is a generic type and is a generic type of NodeView or DataGraphView - if(parent is{IsGenericType: true} && (parent.GetGenericTypeDefinition() == typeof(NodeView<>) || parent.GetGenericTypeDefinition() == typeof(DataGraphView<>))){ - //Get the generic type of this type - //Add this type to the dictionary - Debug.Log($"Find a component named {type} and its parent is {parent}" ); - FromGenericToSpecific.Add(parent, type); - } - + //Register Node View And Graph View via its parent class + SetNodeComponentAttribute(type); + //Register Node Data by GraphUsageAttribute. + SetGraphUsageAttribute(type); + } + } + } + } + + private void SetGraphUsageAttribute(Type type){ + foreach (var attribute in type.GetCustomAttributes(typeof(GraphUsageAttribute), true)){ + var parent = type.BaseType; + if (typeof(NodeData).IsAssignableFrom(type.BaseType)){ + //Check if GraphDataUsage dictionary has GraphDataType of attribute + if (attribute is GraphUsageAttribute attributeCasted){ + if (GraphDataUsage.ContainsKey(attributeCasted.GraphDataType)){ + GraphDataUsage[attributeCasted.GraphDataType].Add(type); + } + else{ + GraphDataUsage.Add(attributeCasted.GraphDataType, new List{type}); } } } } } + + private void SetNodeComponentAttribute(Type type){ + foreach (var attribute in type.GetCustomAttributes(typeof(NodeComponentAttribute), false)){ + //fetch this type 's parent class + var parent = type.BaseType; + //Check if this type is a generic type and is a generic type of NodeView or DataGraphView + if (parent is{IsGenericType: true} && (parent.GetGenericTypeDefinition() == typeof(NodeView<>) || + parent.GetGenericTypeDefinition() == typeof(DataGraphView<>))){ + //Get the generic type of this type + //Add this type to the dictionary + Debug.Log($"Find a component named {type} and its parent is {parent}"); + FromGenericToSpecific.Add(parent, type); + } + //TODO Note that a node component only applied to a specific type of editor,so ,same GraphView could behave differently in different editor.it's a todo feature. + } + } } + //Outer wrapper for the singleton class public static class NodeEditorExtensions{ public static T CreateInstance(){ Debug.Log($"Create A instance of {typeof(T)}"); @@ -50,5 +92,37 @@ namespace TNode.Cache{ var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)] as T; return (T)implementedType!=null; } + public static List GetGraphDataUsage(Type t){ + if (NodeEditorSingleton.Instance.GraphDataUsage.ContainsKey(t)){ + return NodeEditorSingleton.Instance.GraphDataUsage[t]; + } + return new List(); + } + public static object CreateNodeViewFromNodeType() where T:NodeData,new(){ + //Check specific derived type exists or not. + var type = typeof(NodeView); + if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(type)){ + var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[type]; + var instance = (NodeView)Activator.CreateInstance(implementedType); + return instance; + } + else{ + return new DefaultNodeView(); + } + + } + public static object CreateNodeViewFromNodeType(Type t){ + //Check the generic type of NodeView by t + var type = typeof(NodeView<>).MakeGenericType(t); + if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(type)){ + var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[type]; + var instance = Activator.CreateInstance(implementedType); + return instance; + } + else{ + return new DefaultNodeView(); + } + + } } } \ No newline at end of file diff --git a/TNode/Editor/DefaultNodeView.cs b/TNode/Editor/DefaultNodeView.cs new file mode 100644 index 0000000..999938a --- /dev/null +++ b/TNode/Editor/DefaultNodeView.cs @@ -0,0 +1,8 @@ +using TNode.BaseViews; +using TNode.Models; + +namespace TNode.Editor{ + public class DefaultNodeView:NodeView{ + + } +} \ No newline at end of file diff --git a/TNode/Editor/DefaultNodeView.cs.meta b/TNode/Editor/DefaultNodeView.cs.meta new file mode 100644 index 0000000..6de0d0a --- /dev/null +++ b/TNode/Editor/DefaultNodeView.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 30bf0ad9c92f4bebae1a838bafd71c06 +timeCreated: 1656401737 \ No newline at end of file diff --git a/TNode/Editor/GraphEditor.cs b/TNode/Editor/GraphEditor.cs index 24b0f55..645bab9 100644 --- a/TNode/Editor/GraphEditor.cs +++ b/TNode/Editor/GraphEditor.cs @@ -52,7 +52,10 @@ namespace TNode.Editor{ evt.menu.AppendAction("Create Node", dma => { var dmaPos = dma.eventInfo.mousePosition+editorPosition; SearchWindowContext searchWindowContext = new SearchWindowContext(dmaPos,200,200); - SearchWindow.Open(searchWindowContext, ScriptableObject.CreateInstance()); + var searchWindow = CreateInstance(); + searchWindow.Setup(typeof(T),_graphView); + Debug.Log(searchWindow); + SearchWindow.Open(searchWindowContext, searchWindow); }); }); } @@ -78,7 +81,7 @@ namespace TNode.Editor{ { string path = EditorUtility.SaveFilePanel("Save Graph", "", "", "asset"); if (path.Length != 0){ - //Create a new asset file with type of T + //Create a new asset file with type of GraphDataType T asset = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(asset, path); } diff --git a/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs index 0bc873e..0f90d97 100644 --- a/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs +++ b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs @@ -8,7 +8,7 @@ namespace TNode.Editor.Inspector{ public class DefaultInspectorItemFactory{ public InspectorItem Create(){ - //Check type of T + //Check type of GraphDataType var hasSpecificType = NodeEditorExtensions.HasSpecificType>(); if (hasSpecificType){ return NodeEditorExtensions.CreateInstance>(); diff --git a/TNode/Editor/Inspector/NodeInspector.cs b/TNode/Editor/Inspector/NodeInspector.cs index a15dabb..48accc7 100644 --- a/TNode/Editor/Inspector/NodeInspector.cs +++ b/TNode/Editor/Inspector/NodeInspector.cs @@ -23,6 +23,8 @@ namespace TNode.Editor.Inspector{ } public NodeInspector(){ var visualTreeAsset = Resources.Load("NodeInspector"); + + Debug.Log(visualTreeAsset); ConstructWindowBasicSetting(); BuildWindow(visualTreeAsset); } diff --git a/TNode/Editor/Resources/NodeInsepctor.uxml b/TNode/Editor/Resources/NodeInspector.uxml similarity index 100% rename from TNode/Editor/Resources/NodeInsepctor.uxml rename to TNode/Editor/Resources/NodeInspector.uxml diff --git a/TNode/Editor/Resources/NodeInsepctor.uxml.meta b/TNode/Editor/Resources/NodeInspector.uxml.meta similarity index 100% rename from TNode/Editor/Resources/NodeInsepctor.uxml.meta rename to TNode/Editor/Resources/NodeInspector.uxml.meta diff --git a/TNode/Editor/SearchWindowProvider.cs b/TNode/Editor/SearchWindowProvider.cs index 3073585..c0bf4c8 100644 --- a/TNode/Editor/SearchWindowProvider.cs +++ b/TNode/Editor/SearchWindowProvider.cs @@ -1,18 +1,50 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using TNode.BaseViews; +using TNode.Cache; +using TNode.Models; using UnityEditor.Experimental.GraphView; using UnityEngine; +using UnityEngine.UIElements; namespace TNode.Editor{ public class SearchWindowProvider:ScriptableObject,ISearchWindowProvider{ + private Type _graphType; + private GraphView _graphView; + public void Setup(Type graph,GraphView graphView){ + _graphType = graph; + _graphView = graphView; + } public List CreateSearchTree(SearchWindowContext context){ - var list = new List(); - list.Add(new SearchTreeGroupEntry(new GUIContent("Add New Node"), 0)); - list.Add(new SearchTreeGroupEntry(new GUIContent("Add Placemat"), 0)); + var nodeDataTypes = NodeEditorExtensions.GetGraphDataUsage(_graphType); + + var list = new List{ + new SearchTreeGroupEntry(new GUIContent("Add New Node"), 0), + }; + //TODO a node icon shall be given by some way + Texture2D icon = new Texture2D(2,2); + foreach (var nodeDataType in nodeDataTypes){ + Debug.Log(nodeDataType.Name); + + + list.Add(new SearchTreeEntry(new GUIContent($" {nodeDataType.Name} ",icon)){ + level = 1, + userData = nodeDataType, + }); + } return list; } - public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context){ + var userData = SearchTreeEntry.userData; + if (userData is Type type){ + var nodeView = NodeEditorExtensions.CreateNodeViewFromNodeType(type) as GraphElement; + _graphView.AddElement(nodeView); + return true; + } return false; } + + public SearchWindowProvider(){ + } } } \ No newline at end of file diff --git a/TNode/TNodeSample.meta b/TNode/TNodeSample.meta deleted file mode 100644 index 8fedb61..0000000 --- a/TNode/TNodeSample.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: ab3bb3578bf34dafad6ff9fb71f040e1 -timeCreated: 1655794910 \ No newline at end of file diff --git a/TNode/TNodeSample/GraphViewTest.cs b/TNode/TNodeSample/GraphViewTest.cs deleted file mode 100644 index ce772a5..0000000 --- a/TNode/TNodeSample/GraphViewTest.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Dialogue; -using TNode.Attribute; - - -namespace TNode.TNodeSample{ - - -} \ No newline at end of file diff --git a/TNode/TNodeSample/GraphViewTest.cs.meta b/TNode/TNodeSample/GraphViewTest.cs.meta deleted file mode 100644 index 8769352..0000000 --- a/TNode/TNodeSample/GraphViewTest.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: a7d4101454c84539b936140f3b54a3a6 -timeCreated: 1655794926 \ No newline at end of file diff --git a/TNode/TNodeSample/NodeDataTest.cs b/TNode/TNodeSample/NodeDataTest.cs deleted file mode 100644 index 9e10c6c..0000000 --- a/TNode/TNodeSample/NodeDataTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Dialogue; -using TNode.Attribute; -using TNode.Models; -using UnityEditor.Experimental.GraphView; - -namespace TNode.TNodeSample{ - public class NodeDataTest:NodeData{ - [InputPort(typeof(NodeLink),Port.Capacity.Multi)] - private float _floatInput; - public NodeDataTest(string name):base(){ - - } - - } -} \ No newline at end of file diff --git a/TNode/TNodeSample/NodeDataTest.cs.meta b/TNode/TNodeSample/NodeDataTest.cs.meta deleted file mode 100644 index 7fc5fff..0000000 --- a/TNode/TNodeSample/NodeDataTest.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 2d66df6e04694c51818042134869583f -timeCreated: 1655794954 \ No newline at end of file From 03193fc2f6fbe8b12d63967e5822605bbd2aa811 Mon Sep 17 00:00:00 2001 From: taoria <445625470@qq.com> Date: Tue, 28 Jun 2022 16:14:51 +0800 Subject: [PATCH 2/3] 1.Create node view to corresponding region --- TNode/Editor/GraphEditor.cs | 2 +- TNode/Editor/SearchWindowProvider.cs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/TNode/Editor/GraphEditor.cs b/TNode/Editor/GraphEditor.cs index 645bab9..f80078d 100644 --- a/TNode/Editor/GraphEditor.cs +++ b/TNode/Editor/GraphEditor.cs @@ -53,7 +53,7 @@ namespace TNode.Editor{ var dmaPos = dma.eventInfo.mousePosition+editorPosition; SearchWindowContext searchWindowContext = new SearchWindowContext(dmaPos,200,200); var searchWindow = CreateInstance(); - searchWindow.Setup(typeof(T),_graphView); + searchWindow.Setup(typeof(T),_graphView,this); Debug.Log(searchWindow); SearchWindow.Open(searchWindowContext, searchWindow); }); diff --git a/TNode/Editor/SearchWindowProvider.cs b/TNode/Editor/SearchWindowProvider.cs index c0bf4c8..61cd6a5 100644 --- a/TNode/Editor/SearchWindowProvider.cs +++ b/TNode/Editor/SearchWindowProvider.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Drawing; using TNode.BaseViews; using TNode.Cache; using TNode.Models; +using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; @@ -11,9 +13,11 @@ namespace TNode.Editor{ public class SearchWindowProvider:ScriptableObject,ISearchWindowProvider{ private Type _graphType; private GraphView _graphView; - public void Setup(Type graph,GraphView graphView){ + private EditorWindow _editor; + public void Setup(Type graph,GraphView graphView,EditorWindow editor){ _graphType = graph; _graphView = graphView; + _editor = editor; } public List CreateSearchTree(SearchWindowContext context){ var nodeDataTypes = NodeEditorExtensions.GetGraphDataUsage(_graphType); @@ -36,9 +40,14 @@ namespace TNode.Editor{ } public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context){ var userData = SearchTreeEntry.userData; + var relativePos = context.screenMousePosition - _editor.position.position; + var localPos = _graphView.WorldToLocal(relativePos); if (userData is Type type){ - var nodeView = NodeEditorExtensions.CreateNodeViewFromNodeType(type) as GraphElement; - _graphView.AddElement(nodeView); + if (NodeEditorExtensions.CreateNodeViewFromNodeType(type) is GraphElement nodeView){ + nodeView.SetPosition( + new Rect(localPos.x, localPos.y, nodeView.layout.width, nodeView.layout.height)); + _graphView.AddElement(nodeView); + } return true; } return false; From 9544ad81b6dba457d151f6fab1908827c3ffdfbb Mon Sep 17 00:00:00 2001 From: taoria <445625470@qq.com> Date: Tue, 28 Jun 2022 17:00:15 +0800 Subject: [PATCH 3/3] 1.finally an inspector can inspect nodes --- Sample/Editor/HelloGraphView.cs | 4 +- TNode/Editor/BaseViews/DataGraphView.cs | 47 ++++++++++++++----- .../Editor/BaseViews/SimpleGraphSubWindow.cs | 4 +- TNode/Editor/Cache/NodeEditorExtensions.cs | 4 +- TNode/Editor/Inspector/NodeInspector.cs | 10 ++-- TNode/Editor/SearchWindowProvider.cs | 12 +++-- 6 files changed, 58 insertions(+), 23 deletions(-) diff --git a/Sample/Editor/HelloGraphView.cs b/Sample/Editor/HelloGraphView.cs index 9d2de3e..7bb5ef4 100644 --- a/Sample/Editor/HelloGraphView.cs +++ b/Sample/Editor/HelloGraphView.cs @@ -1,13 +1,13 @@ using TNode.Attribute; using TNode.Editor.BaseViews; using TNode.Editor.Inspector; +using UnityEngine; namespace Sample.Editor{ [NodeComponent] public class HelloGraphView : DataGraphView{ public override void OnGraphViewCreate(){ - NodeInspector inspector = new NodeInspector(); - this.Add(inspector); + CreateInspector(); } } } \ No newline at end of file diff --git a/TNode/Editor/BaseViews/DataGraphView.cs b/TNode/Editor/BaseViews/DataGraphView.cs index b0e3493..4ff7ffa 100644 --- a/TNode/Editor/BaseViews/DataGraphView.cs +++ b/TNode/Editor/BaseViews/DataGraphView.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using TNode.BaseViews; using TNode.Cache; +using TNode.Editor.Inspector; using TNode.Models; using UnityEditor; using UnityEditor.Experimental.GraphView; @@ -102,9 +103,11 @@ namespace TNode.Editor.BaseViews{ } } */ - public abstract class DataGraphView:GraphView where T:GraphData{ + public abstract class DataGraphView:GraphView,IDataGraphView where T:GraphData{ private T _data; private SearchWindowProvider _searchWindowProvider; + private bool _isInspectorOn; + private NodeInspector _nodeInspector; public T Data{ get{ return _data; } set{ @@ -172,8 +175,16 @@ namespace TNode.Editor.BaseViews{ ConstructDefaultBehaviour(); OnGraphViewCreate(); } - - + + public virtual void CreateInspector(){ + NodeInspector nodeInspector = new NodeInspector(); + nodeInspector.SetPosition(new Rect(200,200,200,600)); + this.Add(nodeInspector); + _nodeInspector = nodeInspector; + _isInspectorOn = true; + } + + public virtual void OnGraphViewCreate(){ @@ -184,14 +195,28 @@ namespace TNode.Editor.BaseViews{ ~DataGraphView(){ OnGraphViewDestroy(); } - //rewrite function of the derived class in the comment on the top of this script file in this class - // public abstract override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter); - // - // public void AddNode(NodeData nodeData){ - // - // } - - + + public void AddTNode(NodeData nodeData, Rect rect){ + if (NodeEditorExtensions.CreateNodeViewFromNodeType(nodeData.GetType()) is GraphElement nodeView){ + nodeView.SetPosition(rect); + AddElement(nodeView); + //Add a select callback to the nodeView + nodeView.RegisterCallback(evt => { + Debug.Log("NodeView Selected"); + if (evt.clickCount == 1){ + if (_isInspectorOn){ + _nodeInspector.Data = nodeData; + } + } + }); + + } + } + + } + + public interface IDataGraphView{ + public void AddTNode(NodeData nodeData, Rect rect); } public class DataChangedEventArgs{ diff --git a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs index 26be881..4376929 100644 --- a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs +++ b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs @@ -7,7 +7,7 @@ namespace TNode.BaseViews{ private readonly Dragger _dragger = new Dragger(); protected void ConstructWindowBasicSetting(){ - style.position = new StyleEnum(Position.Absolute); + RegisterCallback(evt => { evt.StopPropagation(); }); focusable = false; capabilities |= Capabilities.Movable | Capabilities.Resizable; @@ -20,6 +20,7 @@ namespace TNode.BaseViews{ } public SimpleGraphSubWindow(string defaultUxml=null){ + style.position = new StyleEnum(Position.Absolute); ConstructWindowBasicSetting(); if (defaultUxml != null){ var uxml = AssetDatabase.LoadAssetAtPath(defaultUxml); @@ -27,6 +28,7 @@ namespace TNode.BaseViews{ } } public SimpleGraphSubWindow(VisualTreeAsset visualTreeAsset){ + style.position = new StyleEnum(Position.Absolute); ConstructWindowBasicSetting(); BuildWindow(visualTreeAsset); } diff --git a/TNode/Editor/Cache/NodeEditorExtensions.cs b/TNode/Editor/Cache/NodeEditorExtensions.cs index 22909e1..9df7c55 100644 --- a/TNode/Editor/Cache/NodeEditorExtensions.cs +++ b/TNode/Editor/Cache/NodeEditorExtensions.cs @@ -89,8 +89,8 @@ namespace TNode.Cache{ return instance; } public static bool HasSpecificType() where T : class{ - var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)] as T; - return (T)implementedType!=null; + + return NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(typeof(T)); } public static List GetGraphDataUsage(Type t){ if (NodeEditorSingleton.Instance.GraphDataUsage.ContainsKey(t)){ diff --git a/TNode/Editor/Inspector/NodeInspector.cs b/TNode/Editor/Inspector/NodeInspector.cs index 48accc7..902d761 100644 --- a/TNode/Editor/Inspector/NodeInspector.cs +++ b/TNode/Editor/Inspector/NodeInspector.cs @@ -13,17 +13,19 @@ namespace TNode.Editor.Inspector{ set{ _data = value; UpdateData(); + } } private void UpdateData(){ + Debug.Log(_data); if (_data != null){ RefreshInspector(); } } public NodeInspector(){ + style.position = new StyleEnum(Position.Absolute); var visualTreeAsset = Resources.Load("NodeInspector"); - Debug.Log(visualTreeAsset); ConstructWindowBasicSetting(); BuildWindow(visualTreeAsset); @@ -31,8 +33,10 @@ namespace TNode.Editor.Inspector{ private void RefreshInspector(){ //iterate field of data and get name of every fields,create a new inspector item of appropriate type and add it to the inspector for each field - foreach (var field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)){ + this.Q("InspectorBody").Clear(); + foreach (var field in _data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)){ var bindingPath = field.Name; + var type = field.FieldType; DefaultInspectorItemFactory defaultInspectorItemFactory = new DefaultInspectorItemFactory(); //Invoke generic function Create<> of default inspector item factory to create an inspector item of appropriate type by reflection @@ -40,7 +44,7 @@ namespace TNode.Editor.Inspector{ if (methodInfo != null){ var genericMethod = methodInfo.MakeGenericMethod(type); var createdInspector = genericMethod.Invoke(defaultInspectorItemFactory,null) as VisualElement; - Add(createdInspector); + this.Q("InspectorBody").Add(createdInspector); if (createdInspector is INodeDataBindingBase castedInspector){ castedInspector.BindingNodeData = _data; castedInspector.BindingPath = bindingPath; diff --git a/TNode/Editor/SearchWindowProvider.cs b/TNode/Editor/SearchWindowProvider.cs index 61cd6a5..8278c97 100644 --- a/TNode/Editor/SearchWindowProvider.cs +++ b/TNode/Editor/SearchWindowProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Drawing; using TNode.BaseViews; using TNode.Cache; +using TNode.Editor.BaseViews; using TNode.Models; using UnityEditor; using UnityEditor.Experimental.GraphView; @@ -43,11 +44,14 @@ namespace TNode.Editor{ var relativePos = context.screenMousePosition - _editor.position.position; var localPos = _graphView.WorldToLocal(relativePos); if (userData is Type type){ - if (NodeEditorExtensions.CreateNodeViewFromNodeType(type) is GraphElement nodeView){ - nodeView.SetPosition( - new Rect(localPos.x, localPos.y, nodeView.layout.width, nodeView.layout.height)); - _graphView.AddElement(nodeView); + //Check if type is derived from NodeData + if (typeof(NodeData).IsAssignableFrom(type)){ + //Make an instance of the type + var nodeData = (NodeData) Activator.CreateInstance(type); + nodeData.nodeName = "New Node"; + ((IDataGraphView)_graphView).AddTNode(nodeData,new Rect(localPos.x,localPos.y,100,100)); } + return true; } return false;