///Refletion nodes on a type public static UnityEditor.GenericMenu AppendTypeReflectionNodesMenu(this FlowGraph graph, UnityEditor.GenericMenu menu, System.Type type, string baseCategory, Vector2 pos, Port sourcePort, object dropInstance) { if (!string.IsNullOrEmpty(baseCategory)) { baseCategory += "/"; } var typeCategory = baseCategory + type.FriendlyName(); var icon = UserTypePrefs.GetTypeIcon(type); if (type.IsValueType && !type.IsPrimitive) { if (sourcePort == null || (sourcePort is ValueOutput && type.IsAssignableFrom(sourcePort.type))) { var extractName = string.Format("Extract {0}", type.FriendlyName()); menu.AddItem(new GUIContent(typeCategory + "/" + extractName, icon, null), false, () => { graph.AddReflectedExtractorNode(type, pos, sourcePort, dropInstance); }); } } if (sourcePort is ValueInput) { if (sourcePort.type == type) { var portValue = (sourcePort as ValueInput).serializedValue; menu.AddItem(new GUIContent("Make Constant Variable", icon, null), false, (o) => { graph.AddVariableGet((System.Type)o, null, pos, sourcePort, portValue); }, type); menu.AddItem(new GUIContent("Make Linked Variable", icon, null), false, (o) => { var bbVar = graph.blackboard.AddVariable(sourcePort.name, sourcePort.type); graph.AddVariableGet((System.Type)o, bbVar.name, pos, sourcePort, portValue); }, type); menu.AddSeparator("/"); } } //Constructors if (!type.IsAbstract && !type.IsInterface && !type.IsPrimitive && type != typeof(string)) { foreach (var _c in type.RTGetConstructors()) { var c = _c; if (!c.IsPublic || c.IsObsolete()) { continue; } if (sourcePort is FlowInput || sourcePort is FlowOutput) { continue; } var parameters = c.GetParameters(); if (sourcePort is ValueOutput) { if (!parameters.Any(p => p.ParameterType.IsAssignableFrom(sourcePort.type))) { continue; } } if (sourcePort is ValueInput) { if (!sourcePort.type.IsAssignableFrom(type)) { continue; } } var categoryName = typeCategory + "/" + "Constructors/"; var name = categoryName + c.SignatureName(); if (typeof(Component).IsAssignableFrom(type)) { if (type == typeof(Transform)) { continue; } var stubType = typeof(AddComponent <>).MakeGenericType(type); menu.AddItem(new GUIContent(name, icon, null), false, () => { graph.AddSimplexNode(stubType, pos, sourcePort, dropInstance); }); continue; } if (typeof(ScriptableObject).IsAssignableFrom(type)) { var stubType = typeof(NewScriptableObject <>).MakeGenericType(type); menu.AddItem(new GUIContent(name, icon, null), false, () => { graph.AddSimplexNode(stubType, pos, sourcePort, dropInstance); }); continue; } //exclude types like Mathf, Random, Time etc (they are not static) if (!UserTypePrefs.functionalTypesBlacklist.Contains(type)) { menu.AddItem(new GUIContent(name, icon, null), false, (o) => { graph.AddContructorNode((ConstructorInfo)o, pos, sourcePort, dropInstance); }, c); } } } //Methods var methods = type.RTGetMethods().ToList(); methods.AddRange(type.GetExtensionMethods()); foreach (var _m in methods.OrderBy(_m => !_m.IsStatic).OrderBy(_m => _m.GetMethodSpecialType()).OrderBy(_m => _m.DeclaringType != type)) { var m = _m; if (!m.IsPublic || m.IsObsolete()) { continue; } //convertions are handled automatically at a connection level if (m.Name == "op_Implicit" || m.Name == "op_Explicit") { continue; } var isGeneric = m.IsGenericMethod && m.GetGenericArguments().Length == 1; if (isGeneric) { if (sourcePort != null && sourcePort.IsValuePort()) { if (m.CanBeMadeGenericWith(sourcePort.type)) { m = m.MakeGenericMethod(sourcePort.type); } else { continue; } } } var parameters = m.GetParameters(); if (sourcePort is ValueOutput) { if (type != sourcePort.type || m.IsStatic) { if (!parameters.Any(p => p.ParameterType.IsAssignableFrom(sourcePort.type))) { continue; } } } if (sourcePort is ValueInput) { if (!sourcePort.type.IsAssignableFrom(m.ReturnType) && !parameters.Any(p => p.IsOut && sourcePort.type.IsAssignableFrom(p.ParameterType))) { continue; } } if (sourcePort is FlowInput || sourcePort is FlowOutput) { if (m.ReturnType != typeof(void)) { continue; } } var categoryName = typeCategory; var signatureName = m.SignatureName(); var specialType = m.GetMethodSpecialType(); if (specialType == ReflectionTools.MethodType.Normal) { categoryName += "/Methods/"; } if (specialType == ReflectionTools.MethodType.PropertyAccessor) { categoryName += "/Properties/"; } if (specialType == ReflectionTools.MethodType.Operator) { categoryName += "/Operators/"; } if (specialType == ReflectionTools.MethodType.Event) { categoryName += "/Events/"; } //Unity Event special case if (typeof(UnityEventBase).IsAssignableFrom(m.ReturnType) && specialType == ReflectionTools.MethodType.PropertyAccessor) { categoryName = typeCategory + "/Events/"; } var isExtension = m.IsExtensionMethod(); if (m.DeclaringType != type) { categoryName += isExtension? "Extensions/" : "Inherited/"; } var name = categoryName + signatureName; menu.AddItem(new GUIContent(name, icon, null), false, (o) => { graph.AddMethodNode((MethodInfo)o, pos, sourcePort, dropInstance); }, m); } //Fields foreach (var _f in type.RTGetFields()) { var f = _f; if (!f.IsPublic || f.IsObsolete()) { continue; } var isReadOnly = f.IsReadOnly(); var isConstant = f.IsConstant(); if (sourcePort is ValueOutput) { if (type != sourcePort.type || isConstant) { if (isReadOnly || !f.FieldType.IsAssignableFrom(sourcePort.type)) { continue; } } } if (sourcePort is ValueInput) { if (!sourcePort.type.IsAssignableFrom(f.FieldType)) { continue; } } var isUnityEvent = typeof(UnityEventBase).IsAssignableFrom(f.FieldType); var categoryName = typeCategory + (isUnityEvent? "/Events/" : "/Fields/"); if (f.DeclaringType != type) { categoryName += "Inherited/"; } //Unity Event if (isUnityEvent) { menu.AddItem(new GUIContent(categoryName + f.Name + " (Auto Subscribe)", icon, null), false, (o) => { graph.AddUnityEventAutoCallbackNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f); menu.AddItem(new GUIContent(categoryName + f.Name + " (Get Reference)", icon, null), false, (o) => { graph.AddFieldGetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f); continue; } var nameForGet = categoryName + (isConstant? "constant " + f.Name : "Get " + f.Name); menu.AddItem(new GUIContent(nameForGet, icon, null), false, (o) => { graph.AddFieldGetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f); if (!isReadOnly) { var nameForSet = categoryName + "Set " + f.Name; menu.AddItem(new GUIContent(nameForSet, icon, null), false, (o) => { graph.AddFieldSetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f); } } //C# Events foreach (var _info in type.RTGetEvents()) { var info = _info; var categoryName = typeCategory + "/Events/"; menu.AddItem(new GUIContent(categoryName + info.Name + " (Auto Subscribe)", icon), false, (o) => { graph.AddCSharpEventAutoCallbackNode((EventInfo)o, pos, sourcePort, dropInstance); }, info); menu.AddItem(new GUIContent(categoryName + info.Name + " (Get Reference)", icon), false, (o) => { graph.AddCSharpGetNode((EventInfo)o, pos, sourcePort, dropInstance); }, info); } return(menu); }
///Simplex Nodes public static UnityEditor.GenericMenu AppendSimplexNodesMenu(this FlowGraph graph, UnityEditor.GenericMenu menu, string baseCategory, Vector2 pos, Port sourcePort, object dropInstance) { var infos = EditorUtils.GetScriptInfosOfType(typeof(SimplexNode)); var generalized = new List <System.Type>(); foreach (var _info in infos) { var info = _info; if (sourcePort != null) { if (generalized.Contains(info.originalType)) { continue; } if (sourcePort.IsValuePort()) { if (info.originalType.IsGenericTypeDefinition) { var genericInfo = info.MakeGenericInfo(sourcePort.type); if (genericInfo != null) { info = genericInfo; generalized.Add(info.originalType); } } } var outProperties = info.type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); //SL------------- bool isCallableFunction = info.type.RTIsSubclassOf(typeof(CallableFunctionNodeBase)); var method = info.type.GetMethod("Invoke"); if (method != null) { if (sourcePort is ValueOutput) { var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); if (parameterTypes.Length == 0 || !parameterTypes.Any(t => t.IsAssignableFrom(sourcePort.type))) { continue; } } if (sourcePort is ValueInput) { if (!sourcePort.type.IsAssignableFrom(method.ReturnType) && !outProperties.Any(p => sourcePort.type.IsAssignableFrom(p.PropertyType))) { continue; } } if (sourcePort is FlowOutput || sourcePort is FlowInput) { //SL-------------- if (!isCallableFunction && method.ReturnType != typeof(void) && method.ReturnType != typeof(System.Collections.IEnumerator)) { continue; } if (info.type.IsSubclassOf(typeof(ExtractorNode))) { continue; } } } } var category = string.Join("/", new string[] { !info.category.Contains("UnityEngine/") ? baseCategory : "", info.category, info.name }).TrimStart('/'); menu.AddItem(new GUIContent(category, info.icon, info.description), false, () => { graph.AddSimplexNode(info.type, pos, sourcePort, dropInstance); }); } return(menu); }