/// <summary> /// Save type data as NodeTypeData scriptable object in resources folder /// </summary> public void SaveTypeData() { NodeTypeData typeData = ScriptableObject.CreateInstance <NodeTypeData>(); if (!AssetDatabase.IsValidFolder("Assets/BehaviourTrees")) { AssetDatabase.CreateFolder("Assets", "BehaviourTrees"); } if (!AssetDatabase.IsValidFolder("Assets/BehaviourTrees/Resources")) { AssetDatabase.CreateFolder("Assets/BehaviourTrees", "Resources"); } if (!File.Exists("Assets/BehaviourTrees/Resources/TypeData.asset")) { AssetDatabase.CreateAsset(typeData, $"Assets/BehaviourTrees/Resources/TypeData.asset"); AssetDatabase.SaveAssets(); } }
/// <summary> /// Loads type data object from resources folder and populates with AddNodeMenu attribute data /// </summary> public void LoadTypeData() { Debug.Log("loading typedata"); typeData = Resources.Load("TypeData") as NodeTypeData; if (typeData == null) { EditorUtility.DisplayDialog("No typedata object found", "The type data object could not be found in the resources folder", "ok"); return; } typeData.pathData = new Tree <NodeTypeData.NodePathData>(new NodeTypeData.NodePathData()); Tree <NodeTypeData.NodePathData> currentNode; foreach (Type type in typeof(AbstractNode).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(AbstractNode)))) // Load all subclasses of abstractnode from assembly { object[] attributes = type.GetCustomAttributes(typeof(AddNodeMenu), false); // Get attributes from subclass if (attributes.Length > 0) { AddNodeMenu attribute = attributes[0] as AddNodeMenu; // Push path and nodename into queue to be added to typedata tree Queue <string> pathQueue = new Queue <string>(attribute.menuPath.Split('/')); pathQueue.Enqueue(attribute.nodeName); // Get name and nodetype from attribute string nodeName = attribute.nodeName; NodeTypes nodeType; // Set nodetype depending on class inheritence of the attributed class if (type.IsSubclassOf(typeof(Action))) { nodeType = NodeTypes.Action; } else if (type.IsSubclassOf(typeof(Composite))) { nodeType = NodeTypes.Composite; } else { nodeType = NodeTypes.Decorator; } currentNode = typeData.pathData; while (pathQueue.Count > 0) // Loop until queue is empty { string currentFolderName = pathQueue.Dequeue(); // Get name of folder to be added bool folderExists = false; // If current node has no children it is a behaviour for (int i = 0; i < currentNode.ChildCount; i++) { if (currentNode.GetChild(i).GetValue().pathName == currentFolderName) { currentNode = currentNode.GetChild(i); folderExists = true; break; } } if (pathQueue.Count == 0) // if this was the last path destination, give it node data { currentNode.AddChild(new Tree <NodeTypeData.NodePathData>( new NodeTypeData.NodePathData { pathName = currentFolderName, nodeName = nodeName, nodeType = nodeType }, currentNode)); } else if (!folderExists) // if the existing path was not found, (and this is not the last path destination) create a new folder { currentNode = currentNode.AddChild(new Tree <NodeTypeData.NodePathData>(new NodeTypeData.NodePathData { pathName = currentFolderName })); } } } } }