/// <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();
        }
예제 #2
0
        /// <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();
        }
예제 #3
0
        /// <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);
        }
예제 #6
0
        /// <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();
        }
예제 #7
0
        /// <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);
            }
        }
예제 #8
0
        /// <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());
        }
예제 #9
0
        /// <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;
                    }
                }
            }
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
        /// <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 + ")";
                }
            }
        }
예제 #13
0
        /// <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());
        }
예제 #14
0
        /// <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);
        }
예제 #15
0
        /// <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();
        }
예제 #16
0
        /// <summary>
        /// Reset target node.
        /// </summary>
        void OpenNodeReference()
        {
            var nodeInfo = AttributeUtility.GetAttribute <NodeInfoAttribute>(target.GetType(), false) ?? new NodeInfoAttribute();

            Application.OpenURL(nodeInfo.url);
        }