You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
5.9 KiB
128 lines
5.9 KiB
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{
|
|
/// <summary>
|
|
/// Internal singleton class for caching TNode reflection Data.
|
|
/// </summary>
|
|
internal class NodeEditorSingleton{
|
|
private static NodeEditorSingleton _instance;
|
|
public readonly Dictionary<Type,Type> FromGenericToSpecific = new Dictionary<Type, Type>();
|
|
public readonly Dictionary<Type, List<Type>> GraphDataUsage = new Dictionary<Type, List<Type>>();
|
|
public static NodeEditorSingleton Instance{
|
|
get{ return _instance ??= new NodeEditorSingleton(); }
|
|
}
|
|
|
|
private static readonly string[] ExcludedAssemblies = new string[]{"Microsoft", "UnityEngine","UnityEditor","mscorlib","System"};
|
|
|
|
private NodeEditorSingleton(){
|
|
//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){
|
|
//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>{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<T>(){
|
|
Debug.Log($"Create A instance of {typeof(T)}");
|
|
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)];
|
|
var instance = (T)Activator.CreateInstance(implementedType);
|
|
return instance;
|
|
}
|
|
public static object CreateInstance(Type t){
|
|
Debug.Log($"Create A instance of {t}");
|
|
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[t];
|
|
var instance = Activator.CreateInstance(implementedType);
|
|
return instance;
|
|
}
|
|
public static bool HasSpecificType<T>() where T : class{
|
|
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)] as T;
|
|
return (T)implementedType!=null;
|
|
}
|
|
public static List<Type> GetGraphDataUsage(Type t){
|
|
if (NodeEditorSingleton.Instance.GraphDataUsage.ContainsKey(t)){
|
|
return NodeEditorSingleton.Instance.GraphDataUsage[t];
|
|
}
|
|
return new List<Type>();
|
|
}
|
|
public static object CreateNodeViewFromNodeType<T>() where T:NodeData,new(){
|
|
//Check specific derived type exists or not.
|
|
var type = typeof(NodeView<T>);
|
|
if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(type)){
|
|
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[type];
|
|
var instance = (NodeView<T>)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();
|
|
}
|
|
|
|
}
|
|
}
|
|
} |