public static void FetchBehaviourNodes() { behaviourNodes = new Dictionary <Type, NodeTypeProperties>(); IEnumerable <Type> behaviourTypes = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.FullName.StartsWith("Unity") && !asm.FullName.Contains("Editor")) .Where(asm => !asm.FullName.StartsWith("BonsaiTestsAssembly")) // Ignore nodes from test suite. .SelectMany(asm => asm.GetTypes()) .Where(t => t.IsSubclassOf(typeof(BTNode)) && !t.IsAbstract); foreach (Type type in behaviourTypes) { var nodeMeta = type.GetCustomAttribute <BTNodeAttribute>(false); // Default menu path if unspecified. string menuPath = "User/"; // Service base class is abstract. For Service types, default to Service texture. string texName = typeof(BTService).IsAssignableFrom(type) ? "Service" : "Play"; if (nodeMeta != null) { if (!string.IsNullOrEmpty(nodeMeta.menuPath)) { menuPath = nodeMeta.menuPath; } // Texxture names are optional. Use only if specified. if (!string.IsNullOrEmpty(nodeMeta.texturePath)) { texName = nodeMeta.texturePath; } } // Only composites and decorators have outputs. bool hasOutput = !type.IsSubclassOf(typeof(Task)); menuPath += type.Name; var prop = new NodeTypeProperties(menuPath, texName, hasOutput); behaviourNodes.Add(type, prop); } }
public static void FetchBehaviourNodes() { _behaviourNodes = new Dictionary <Type, NodeTypeProperties>(); IEnumerable <Assembly> scriptAssemblies = AppDomain.CurrentDomain.GetAssemblies(). Where((Assembly assembly) => assembly.FullName.Contains("Assembly") && !assembly.FullName.Contains("Editor")); Type targetType = typeof(BehaviourNode); foreach (Assembly assembly in scriptAssemblies) { foreach (Type type in assembly.GetTypes() .Where(T => T.IsClass && !T.IsAbstract && T.IsSubclassOf(targetType))) { object[] nodeProperties = type.GetCustomAttributes(typeof(NodeEditorPropertiesAttribute), false); // The attribute is to simply get custom data about the node. // Like menu path and texture. NodeEditorPropertiesAttribute attrib = null; if (nodeProperties.Length > 0) { attrib = nodeProperties[0] as NodeEditorPropertiesAttribute; } string menuPath = "Uncategorized/"; string texName = "Play"; if (attrib != null) { menuPath = attrib.menuPath; texName = attrib.textureName; } bool bCreateInput = false; bool bCreateOutput = false; bool bCanHaveMultipleChildren = false; // Only action nodes have an input and no output. if (type.IsSubclassOf(typeof(Task))) { bCreateInput = true; } // Composites and decorators have in and out. else { bCreateInput = true; bCreateOutput = true; // Only composites can have more than 1 child. if (type.IsSubclassOf(typeof(Composite))) { bCanHaveMultipleChildren = true; } } menuPath += type.Name; var prop = new NodeTypeProperties(menuPath, texName, bCreateInput, bCreateOutput, bCanHaveMultipleChildren); _behaviourNodes.Add(type, prop); } } }