/// <summary> /// Shows a context menu callback to add a new state. /// </summary> void OnAddContextMenu() { var menu = new GenericMenu(); var stateScripts = FileUtility.GetScripts <InternalStateBehaviour>(); for (int i = 0; i < stateScripts.Length; i++) { System.Type childStateType = stateScripts[i].GetClass(); // Get the component path string componentPath; AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(childStateType, true); if (componentMenu != null && componentMenu.componentMenu != string.Empty) { componentPath = componentMenu.componentMenu; } else { componentPath = childStateType.ToString().Replace('.', '/'); } menu.AddItem(new GUIContent(componentPath), false, delegate() { StateUtility.AddState(m_Parent, childStateType); }); } // Shows the context menu menu.ShowAsContext(); }
/// <summary> /// Callback to add a new node. /// </summary> private void OnAddNode(ReorderableList list) { // Get all node scripts var nodeTypes = new List <System.Type>(); foreach (System.Type type in BehaviourTreeUtility.GetNodeTypes()) { if (!type.IsSubclassOf(typeof(BranchNode))) { nodeTypes.Add(type); } } // Create the menu var menu = new UnityEditor.GenericMenu(); // Add node types to the menu for (int i = 0; i < nodeTypes.Count; i++) { var nodeType = nodeTypes[i]; var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(nodeType, false) ?? new NodeInfoAttribute(); menu.AddItem(new GUIContent(nodeInfo.category + nodeType.Name), false, delegate() { ActionStateUtility.AddNode(m_ActionState, nodeType); RegisterEditorOnGUI(); }); } // Show the context menu menu.ShowAsContext(); }
/// <summary> /// Returns a collection of ActionNode scripts ordered by category. /// <returns>A collection of MonoScript whose class inherits from ActionNode.</returns> /// </summary> public static MonoScript[] GetNodeScripts() { if (s_NodeScripts != null) { return(s_NodeScripts); } var categoryNodeScript = new Dictionary <string, MonoScript>(); foreach (var script in FileUtility.GetScripts <ActionNode>()) { System.Type type = script.GetClass(); if (type != null) { var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(type, false) ?? new NodeInfoAttribute(); categoryNodeScript.Add(nodeInfo.category + type.Name, script); } } // Sort the dictionary keys var sortedKeys = new List <string>(categoryNodeScript.Keys); sortedKeys.Sort(); // Add all scripts in the sortedNodeScripts var sortedNodeScripts = new List <MonoScript>(); for (int i = 0; i < sortedKeys.Count; i++) { sortedNodeScripts.Add(categoryNodeScript[sortedKeys[i]]); } s_NodeScripts = sortedNodeScripts.ToArray(); return(s_NodeScripts); }
/// <summary> /// Constructor. /// <param name="serializedNode">The target serialized node.</param> /// <param name="path">The property path.</param> /// <param name="propertyType">The serialize property type.</param> /// <param name="target">The object that owns the serialized field.</param> /// <param name="fieldInfo">The field info of the property.</param> /// </summary> public SerializedNodeField(SerializedNode serializedNode, string path, NodePropertyType propertyType, object target, FieldInfo fieldInfo) : base(target, serializedNode, path, fieldInfo.FieldType, propertyType) { m_FieldInfo = fieldInfo; this.hideInInspector = AttributeUtility.GetAttribute <HideInInspector>(fieldInfo, true) != null; // Variable? if (propertyType == NodePropertyType.Variable) { this.label = StringHelper.SplitCamelCase(fieldInfo.Name); m_VariableInfo = AttributeUtility.GetAttribute <VariableInfoAttribute>(fieldInfo, true) ?? new VariableInfoAttribute(); var variable = m_FieldInfo.GetValue(m_Target) as BehaviourMachine.Variable; System.Type variableType = variable != null?variable.GetType() : null; m_IsConcreteVariable = variableType != null && TypeUtility.GetConcreteType(variableType) == variableType; this.tooltip = (fieldInfo.FieldType.Name + ": " + m_VariableInfo.tooltip).Replace("Var", string.Empty); } else { this.label = StringHelper.SplitCamelCase(fieldInfo.Name); var tooltip = AttributeUtility.GetAttribute <BehaviourMachine.TooltipAttribute>(fieldInfo, true); if (tooltip != null) { m_Tooltip = tooltip.tooltip; } } }
/// <summary> /// Returns a list of derived types of the supllied variable that has the custom attribute. /// <param name="baseVariable">The base type of the variable.</param> /// <returns>An array of custom variables for the supplied type.</returns> /// </summary> public static Type[] GetCustomVariables(Type baseVariable) { Type[] customVariables = null; s_CustomVariables.TryGetValue(baseVariable, out customVariables); if (customVariables != null) { return(customVariables); } // Create a list o derived custom vars var customVarsList = new List <Type>(); // Get the derived types foreach (System.Type derivedType in TypeUtility.GetDerivedTypes(baseVariable)) { var customVarAttr = AttributeUtility.GetAttribute <CustomVariableAttribute>(derivedType, false); // Is there a CustomVariableAttribute on the derivedType? if (customVarAttr != null) { customVarsList.Add(derivedType); } } customVariables = customVarsList.ToArray(); s_CustomVariables.Add(baseVariable, customVariables); return(customVariables); }
/// <summary> /// Shows a context menu to add a new parent. /// </summary> void OnContextMenu() { var menu = new UnityEditor.GenericMenu(); // Get the active game object var gameObject = Selection.activeGameObject; // The selected game object is not null? if (gameObject != null) { // Gets all scripts that inherits from ParentBehaviour class MonoScript[] scripts = FileUtility.GetScripts <ParentBehaviour>(); for (int i = 0; i < scripts.Length; i++) { var type = scripts[i].GetClass(); // Get the component path string componentPath = "Add Parent/"; AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, false); if (componentMenu == null || componentMenu.componentMenu != string.Empty) { componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, true); if (componentMenu != null && componentMenu.componentMenu != string.Empty) { componentPath += componentMenu.componentMenu; } else { componentPath += type.ToString().Replace('.', '/'); } // Add to menu menu.AddItem(new GUIContent(componentPath), false, delegate() { BehaviourWindow.activeParent = StateUtility.AddState(gameObject, type) as ParentBehaviour; }); } } } else { menu.AddDisabledItem(new GUIContent("Add Parent/")); ShowNotification(new GUIContent("Select a Game Object and right click in this window!")); } // Add option to paste states if (Selection.activeGameObject != null && StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0) { menu.AddItem(new GUIContent("Paste State"), false, delegate() { StateUtility.CloneStates(Selection.activeGameObject, StateUtility.statesToPaste, null); }); } else { menu.AddDisabledItem(new GUIContent("Paste State")); } // Refresh window? // menu.AddSeparator(""); // menu.AddItem(new GUIContent("Refresh"), false ,Refresh); // Shows the controller menu menu.ShowAsContext(); }
/// <summary> /// Refresh items. /// </summary> void Refresh() { m_Root = new Category(null, string.Empty); m_CurrentCategory = m_Root; // Stores all scripts that inherites from ActionNode as child of m_Root foreach (var type in BehaviourTreeUtility.GetNodeTypes()) { var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(type, false) ?? new NodeInfoAttribute(); m_Root.AddChild(nodeInfo.category, type, nodeInfo); } }
/// <summary> /// Creates a new editor for the supplied node type. /// <param name="nodeType">The type of the node to be inspected.</param> /// <returns>An editor for the supplied type.</returns> /// </summary> public static NodeEditor CreateEditor(Type nodeType) { // Create type if (s_CustomEditors == null) { s_CustomEditors = new Dictionary <Type, Type>(); foreach (Type editorType in EditorTypeUtility.GetDerivedTypes(typeof(NodeEditor))) { var customEditorAttr = AttributeUtility.GetAttribute <CustomNodeEditorAttribute>(editorType, true); if (customEditorAttr != null) { if (s_CustomEditors.ContainsKey(customEditorAttr.inspectedType)) { s_CustomEditors[customEditorAttr.inspectedType] = editorType; } else { s_CustomEditors.Add(customEditorAttr.inspectedType, editorType); } // Add derived types? if (customEditorAttr.editorForChildClasses) { foreach (var childType in TypeUtility.GetDerivedTypes(customEditorAttr.inspectedType)) { if (!s_CustomEditors.ContainsKey(childType)) { s_CustomEditors.Add(childType, editorType); } } } } } } // Try get custom nodeeditor attribute Type customEditorType = null; s_CustomEditors.TryGetValue(nodeType, out customEditorType); if (customEditorType != null) { var nodeEditor = Activator.CreateInstance(customEditorType) as NodeEditor; if (nodeEditor != null) { return(nodeEditor); } } return(new NodeEditor()); }
/// <summary> /// Draws the node inspector. /// <param name="target">The node that is being inspected.</param> /// </summary> public void DrawNode(ActionNode target) { // Create style? if (s_Styles == null) { s_Styles = new NodeEditor.Styles(); } if (target == null) { m_SerializedNode = null; m_Target = null; m_TargetContent = GUIContent.none; m_TargetIconContent = GUIContent.none; m_TargetType = string.Empty; } // The target node has changed? else if (m_SerializedNode == null || m_SerializedNode.target != target) { m_SerializedNode = new SerializedNode(target); m_Target = target; Type targetType = m_Target.GetType(); m_TargetType = " (" + targetType.Name + ")"; var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(targetType, false) ?? new NodeInfoAttribute(); m_TargetContent = new GUIContent(target.name + m_TargetType, null, nodeInfo.description); m_TargetIconContent = new GUIContent(IconUtility.GetIcon(targetType)); // Update Values m_SerializedNode.Update(); } // The serialized node is not null? if (m_SerializedNode != null) { // Draw node title this.DrawTitle(); if (m_Target != null && BehaviourWindow.IsVisible(m_Target.instanceID)) { // Draw node properties this.OnInspectorGUI(); // Update target content? if (Event.current.type == EventType.Used && m_Target != null) { m_TargetContent.text = m_Target.name + m_TargetType; } } } }
/// <summary> /// Returns a collection of ActionNode types ordered by category. /// <returns>A collection of System.Type whose class inherits from ActionNode.</returns> /// </summary> public static System.Type[] GetNodeTypes() { if (s_NodeTypes != null) { return(s_NodeTypes); } var categoryNodeScript = new Dictionary <string, System.Type>(); foreach (var type in TypeUtility.GetDerivedTypes(typeof(ActionNode))) { if (type != null) { var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(type, false) ?? new NodeInfoAttribute(); string key = nodeInfo.category + type.Name; // The node was already added? if (categoryNodeScript.ContainsKey(key)) { Print.LogWarning("You have more than one \'" + type.Name + "\' node script. You should have only one copy of each node script. Please, search for them in the ProjectView and then delete its copies", null); } else { categoryNodeScript.Add(key, type); } } } // Sort the dictionary keys var sortedKeys = new List <string>(categoryNodeScript.Keys); sortedKeys.Sort(); // Add all scripts in the sortedNodeTypes var sortedNodeTypes = new List <System.Type>(); for (int i = 0; i < sortedKeys.Count; i++) { sortedNodeTypes.Add(categoryNodeScript[sortedKeys[i]]); } s_NodeTypes = sortedNodeTypes.ToArray(); return(s_NodeTypes); }
/// <summary> /// Returns the custom drawer for the supplied property attribute or null. /// <param name="attribute">The property attribute to search for a custom drawer.</param> /// <returns>The custom property drawer or null.</returns> /// </summary> public static NodePropertyDrawer GetDrawer(PropertyAttribute attribute) { if (attribute == null) { return(null); } // The custom drawer dictionary is not loaded? if (s_CustomDrawers == null) { s_CustomDrawers = new Dictionary <Type, Type>(); foreach (Type t in EditorTypeUtility.GetDerivedTypes(typeof(NodePropertyDrawer))) { var customDrawerAttr = AttributeUtility.GetAttribute <CustomNodePropertyDrawerAttribute>(t, false); if (customDrawerAttr != null && !s_CustomDrawers.ContainsKey(customDrawerAttr.type)) { s_CustomDrawers.Add(customDrawerAttr.type, t); } } } // Try to get the type of the custom property drawer Type drawerType; s_CustomDrawers.TryGetValue(attribute.GetType(), out drawerType); if (drawerType != null) { // Create the drawer var drawer = Activator.CreateInstance(drawerType) as NodePropertyDrawer; if (drawer != null) { // Set the attribute and return the drawer drawer.attribute = attribute; return(drawer); } } return(null); }
/// <summary> /// Updates the active node data. /// <param name="activeNode">The active node.</param> /// </summary> void UpdateActiveNode(ActionNode activeNode) { var activeNodeType = activeNode != null?activeNode.GetType() : null; // The active node type has changed? if (activeNodeType != m_ActiveNodeType) { if (activeNode == null) { m_ActiveNodeType = null; m_ActiveNodeInfo = null; m_ActiveNodeIcon = null; m_ActiveNodeTypeName = string.Empty; return; } else { m_ActiveNodeType = activeNodeType; m_ActiveNodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(m_ActiveNodeType, true) ?? new NodeInfoAttribute(); m_ActiveNodeIcon = IconUtility.GetIcon(m_ActiveNodeType); m_ActiveNodeTypeName = " (" + m_ActiveNodeType.Name + ")"; } } }
/// <summary> /// Returns a set of serialized properties in an object. /// <param name="serializedNode">The target serialized node.</param> /// <param name="target">The object to get the properties.</param> /// <param name="targetType">The target object type.</param> /// <param name="currentPath">The property path of the target.</param> /// <returns>The serialized properties in the target object.</returns> /// </summary> static SerializedNodeProperty[] GetPropertiesData(SerializedNode serializedNode, object target, Type targetType, string currentPath = "") { // Create the property data list var propertyData = new List <SerializedNodeProperty>(); // Get serialized fields for the target type FieldInfo[] serializedFields = NodeSerialization.GetSerializedFields(targetType); for (int i = 0; i < serializedFields.Length; i++) { // Get field FieldInfo field = serializedFields[i]; // Get field type var fieldType = field.FieldType; // Get the field property attribute var propertyAttr = AttributeUtility.GetAttribute <PropertyAttribute>(field, true); // Get the property type var propertyType = SerializedNode.GetPropertyType(fieldType); // Create the property data var currentSerializedField = new SerializedNodeField(serializedNode, currentPath + field.Name, propertyType, target, field); propertyData.Add(currentSerializedField); // Variable? if (propertyType == NodePropertyType.Variable) { // Get the field value object fieldValue = target != null?field.GetValue(target) : null; // Get the children fields SerializedNodeProperty[] children = SerializedNode.GetPropertiesData(serializedNode, fieldValue, fieldValue != null ? fieldValue.GetType() : fieldType, currentPath + field.Name + "."); // Create the property drawer for the "Value" child property if (propertyAttr != null && currentSerializedField.isConcreteVariable) { foreach (var child in children) { // It is the "Value" property? if (child.label == "Value") { child.customDrawer = NodePropertyDrawer.GetDrawer(propertyAttr); } } } // Set children currentSerializedField.SetChildren(children); } // Array? else if (propertyType == NodePropertyType.Array) { // Get the array value Array array = target != null?field.GetValue(target) as Array : null; // Get array element type var elementType = fieldType.GetElementType(); // Create the array children list var childrenList = new List <SerializedNodeProperty>(); // Create the array size childrenList.Add(new SerializedArraySize(target, serializedNode, currentSerializedField.path + ".size", currentSerializedField, array, elementType)); // Create children var variableInfo = AttributeUtility.GetAttribute <VariableInfoAttribute>(field, true) ?? new VariableInfoAttribute(); childrenList.AddRange(SerializedNode.GetPropertiesData(serializedNode, target, array, elementType, currentSerializedField.path + ".", variableInfo, propertyAttr)); // Set array data children currentSerializedField.SetChildren(childrenList.ToArray()); } // Get the property drawer else if (propertyAttr != null) { currentSerializedField.customDrawer = NodePropertyDrawer.GetDrawer(propertyAttr); } } return(propertyData.ToArray()); }
/// <summary> /// Returns an icon fot the supplied type. /// <param name="type">The type to get the icon.</param> /// <param name="obj">Optional paramater to get icon using EditorGUIUtility.ObjectContent.</param> /// <returns>The icon for the supplied type.</returns> /// </summary> public static Texture GetIcon(System.Type type, UnityEngine.Object obj = null) { Texture texture; s_Icons.TryGetValue(type, out texture); if (texture == null) { if (typeof(ActionNode).IsAssignableFrom(type)) { var attribute = AttributeUtility.GetAttribute <NodeInfoAttribute>(type, true) ?? new NodeInfoAttribute(); texture = Resources.Load("Icons/" + attribute.icon) as Texture ?? EditorGUIUtility.FindTexture(attribute.icon + " Icon"); if (texture == null) { texture = EditorGUIUtility.FindTexture(attribute.icon); } } else if (typeof(UnityEngine.Object).IsAssignableFrom(type)) { texture = EditorGUIUtility.ObjectContent(obj, type).image; if (texture == null) { EditorGUIUtility.FindTexture(type.Name + " Icon"); } } else if (typeof(BehaviourMachine.Variable).IsAssignableFrom(type)) { var customVarAttr = AttributeUtility.GetAttribute <CustomVariableAttribute>(type, false); if (customVarAttr != null) { texture = Resources.Load("Icons/" + customVarAttr.icon) as Texture ?? EditorGUIUtility.FindTexture(customVarAttr.icon + " Icon"); if (texture == null) { texture = EditorGUIUtility.FindTexture(customVarAttr.icon); } } } else { texture = EditorGUIUtility.FindTexture(type.Name + " Icon"); } if (texture == null) { texture = EditorGUIUtility.FindTexture("DefaultAsset Icon"); } if (texture != null) { if (!s_Icons.ContainsKey(type)) { s_Icons.Add(type, texture); } else { s_Icons[type] = texture; } } } return(texture); }
/// <summary> /// Shows the context menu. /// </summary> void OnContextMenu() { var menu = new GenericMenu(); var activeFsm = BehaviourWindow.activeFsm; if (activeFsm != null) { m_LastMousePos = Event.current.mousePosition; // Get the states scripts MonoScript[] stateScripts = FileUtility.GetScripts <InternalStateBehaviour>(); for (int i = 0; i < stateScripts.Length; i++) { System.Type type = stateScripts[i].GetClass(); // Get the component path string componentPath = "Add State/"; AddComponentMenu componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, false); if (componentMenu == null || componentMenu.componentMenu != string.Empty) { componentMenu = AttributeUtility.GetAttribute <AddComponentMenu>(type, true); if (componentMenu != null && componentMenu.componentMenu != string.Empty) { componentPath += componentMenu.componentMenu; } else { componentPath += type.ToString().Replace('.', '/'); } menu.AddItem(new GUIContent(componentPath), false, delegate() { InternalStateBehaviour newState = StateUtility.AddState(activeFsm, type); // Sets the newState position and dirty flag if (newState != null) { newState.position = m_LastMousePos - new Vector2(StateGUI.defaultWidth, StateGUI.defaultHeight) * .5f; EditorUtility.SetDirty(newState); } }); } } } else { menu.AddDisabledItem(new GUIContent("Add State")); } // Separator menu.AddSeparator(""); menu.AddItem(new GUIContent("Copy FSM"), false, delegate() { StateUtility.statesToPaste = new InternalStateBehaviour[] { activeFsm }; }); if (StateUtility.statesToPaste != null && StateUtility.statesToPaste.Length > 0 && activeFsm != null) { menu.AddItem(new GUIContent("Paste State"), false, delegate() { StateUtility.PasteStates(activeFsm); }); } else { menu.AddDisabledItem(new GUIContent("Paste State")); } // Separator menu.AddSeparator(""); menu.AddItem(new GUIContent("Delete FSM"), false, delegate() { StateUtility.Destroy(activeFsm); }); // menu.AddSeparator(""); // Separator // if (BehaviourWindow.Instance != null) // menu.AddItem(new GUIContent("Refresh"), false, BehaviourWindow.Instance.Refresh); // else // menu.AddDisabledItem(new GUIContent("Refresh")); // Shows the context menu menu.ShowAsContext(); }
/// <summary> /// Reset target node. /// </summary> void OpenNodeReference() { var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(target.GetType(), false) ?? new NodeInfoAttribute(); Application.OpenURL(nodeInfo.url); }