/// <summary> /// Returns the behavior which is associated with a tree node. /// </summary> /// <param name="nodetag">The NodeTag of the tree node.</param> /// <param name="label">The label of the tree node.</param> /// <returns>Returns null if no matching behavior could be found or loaded.</returns> internal BehaviorNode GetBehavior(NodeTag nodetag, string label) { BehaviorNode behavior = LoadBehavior(nodetag.Filename); if (behavior != null) return behavior; MessageBox.Show(string.Format(Resources.NoBehaviorInfo, label, nodetag.Filename), Resources.FileError, MessageBoxButtons.OK); return null; }
/// <summary> /// Attaches a dragged node from the node explorer to an existing node. /// </summary> /// <param name="nvd">The node the new node will be attached to.</param> /// <param name="mode">The way the new node will be attached.</param> /// <param name="nodetag">The tag of the you want to create.</param> /// <param name="label">The label of the new node.</param> private void InsertNewNode(NodeViewData nvd, NodeAttachMode mode, NodeTag nodetag, PointF mousePos) { if (nodetag.Type != NodeTagType.Behavior && nodetag.Type != NodeTagType.Prefab && nodetag.Type != NodeTagType.Node) { throw new Exception("Only behaviours, prefabs and nodes can be attached to a behaviour tree"); } Node newnode = null; bool isPrefabInstance = false; // when we attach a behaviour we must create a special referenced behaviour node if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab) { if (!File.Exists(nodetag.Filename)) { if (!SaveBehavior(nodetag.Filename)) { return; } } // get the behavior we want to reference BehaviorNode behavior = _behaviorTreeList.LoadBehavior(nodetag.Filename); // a behaviour reference itself if (nvd != null && nvd.IsBehaviorReferenced(behavior)) { if (DialogResult.Cancel == MessageBox.Show(Resources.CircularReferencedInfo, Resources.Warning, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning)) { return; } } if (nodetag.Type == NodeTagType.Prefab) { behavior = (BehaviorNode)behavior.Clone(); } Behavior rootB = _rootNodeView.RootBehavior as Behavior; Behavior b = behavior as Behavior; if (rootB.AgentType == null) { rootB.AgentType = b.AgentType; } else if (!IsCompatibleAgentType(rootB, b)) { return; } // behavior if (nodetag.Type == NodeTagType.Behavior) { // create the referenced behaviour node for the behaviour ReferencedBehavior refnode = Node.CreateReferencedBehaviorNode(_rootNodeView.RootBehavior, behavior, mode == NodeAttachMode.None || ((Node)this.RootNode).IsFSM); newnode = (Node)refnode; //the comment seems too long to overlap the node //newnode.CommentText = Resources.ThisIsReferenceTree; newnode.CommentBackground = Node.CommentColor.Gray; } // prefab else { // Copy all Pars from the prefab file into the current behavior node. List<ParInfo> pars = new List<ParInfo>(); foreach(ParInfo par in b.LocalVars) { bool found = false; foreach(ParInfo rootPar in rootB.LocalVars) { if (par.Name == rootPar.Name) { if (par.Type != rootPar.Type) { string errorMsg = string.Format(Resources.ParErrorInfo, par.Name, b.Label, rootB.Label); MessageBox.Show(errorMsg, Resources.LoadError, MessageBoxButtons.OK); return; } found = true; break; } } if (!found) { pars.Add(par); } } rootB.LocalVars.AddRange(pars); // The first child should be the root node of the prefab tree. Node behaviorNode = (Node)behavior; if (behaviorNode.Children.Count > 0) { newnode = (Node)behaviorNode.Children[0]; string prefab = Path.GetFileNameWithoutExtension(behavior.Filename); newnode.CommentText = string.Format("Prefab[{0}]", prefab); isPrefabInstance = true; string prefabName = FileManagers.FileManager.GetRelativePath(behavior.Filename); newnode.SetPrefab(prefabName); } } } else { // simply create the node which is supposed to be created. newnode = Node.Create(nodetag.NodeType); if (newnode != null) newnode.PostCreatedByEditor(); } if (newnode == null) { return; } // update label newnode.OnPropertyValueChanged(false); Node node = (nvd != null) ? nvd.Node : null; if (node == null) { mode = NodeAttachMode.None; } Attachments.Attachment startCondition = null; // attach the new node with the correct mode switch (mode) { // the new node is inserted in front of the target node case NodeAttachMode.Left: if (node != null) { Node parent = (Node)node.Parent; int k = node.ParentConnector.GetChildIndex(node); Node.Connector conn = node.ParentConnector; Debug.Check(conn != null); parent.RemoveChild(conn, node); parent.AddChild(conn, newnode, k); Node.Connector newconn = newnode.GetConnector(conn.Identifier); Debug.Check(newconn != null); newnode.AddChild(newconn, node); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; } break; // the new node is simply added to the target node's children case NodeAttachMode.Right: if (newnode != null && newnode.IsFSM) { startCondition = this.addFSMNode(newnode, mousePos); newnode.ScreenLocation = new PointF(_rootNodeView.BoundingBox.Left + _rootNodeView.BoundingBox.Width * 1.5f, _rootNodeView.BoundingBox.Top); } else if (node != null) { node.AddChild(_dragTargetConnector, newnode); _dragTargetConnector.IsExpanded = true; // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd; } break; // the new node is placed above the target node case NodeAttachMode.Top: if (node != null) { int n = _dragTargetNode.Node.ParentConnector.GetChildIndex(node); ((Node)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, n); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; } break; // the new node is placed below the target node case NodeAttachMode.Bottom: if (node != null) { int m = _dragTargetNode.Node.ParentConnector.GetChildIndex(node); ((Node)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, m + 1); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; } break; // the node will replace the target node case NodeAttachMode.Center: if (node != null && replaceNode(node, newnode)) { // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; this.Redraw(); } break; case NodeAttachMode.None: if (newnode != null && newnode.IsFSM) { startCondition = this.addFSMNode(newnode, mousePos); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = this.RootNodeView; } break; } // After being created, its Id should be reset. if (newnode != null) { newnode.ResetId(true); // set the prefab dirty for the current parent if (newnode.Parent != null) { Node parent = (Node)newnode.Parent; if (!string.IsNullOrEmpty(parent.PrefabName)) { parent.HasOwnPrefabData = true; if (!isPrefabInstance) { newnode.SetPrefab(parent.PrefabName); newnode.HasOwnPrefabData = true; } } } if (startCondition != null) { startCondition.TargetFSMNodeId = newnode.Id; } UndoManager.Save(this.RootNode); } // the layout needs to be recalculated LayoutChanged(); }
/// <summary> /// Returns the behavior which is associated with a tree node. /// </summary> /// <param name="nodetag">The NodeTag of the tree node.</param> /// <param name="label">The label of the tree node.</param> /// <returns>Returns null if no matching behavior could be found or loaded.</returns> internal BehaviorNode GetBehavior(NodeTag nodetag, string label, List<Nodes.Node.ErrorCheck> result = null) { BehaviorNode behavior = LoadBehavior(nodetag.Filename, false, result); if (behavior != null) { return behavior; } MessageBox.Show(string.Format(Resources.NoBehaviorInfo, label, nodetag.Filename), Resources.FileError, MessageBoxButtons.OK); return null; }
private static void resetPar(NodeTag.DefaultObject obj, ParInfo par, string newName) { Node node = getNode(obj); if (node != null && par != null) { Type type = obj.GetType(); foreach (PropertyInfo property in type.GetProperties()) { try { object value = property.GetValue(obj, null); if (value != null) { if (property.PropertyType == typeof(MethodDef)) { MethodDef method = value as MethodDef; Debug.Check(method != null); method.ResetPar(par, newName); } else if (property.PropertyType == typeof(VariableDef)) { VariableDef var = value as VariableDef; Debug.Check(var != null); var.ResetPar(par, newName); } else if (property.PropertyType == typeof(RightValueDef)) { RightValueDef rv = value as RightValueDef; Debug.Check(rv != null); rv.ResetPar(par, newName); } } } catch { } } } }
/// <summary> /// Adds this NodeGroup to the TreeView of the node explorer. /// </summary> /// <param name="pool">The TreeNodeCollection the group and its sub-groups and childrens will be added.</param> public void Register(TreeNodeCollection pool) { // check if this NodeGroup already exists in the node explorer TreeNode tnode = null; foreach(TreeNode node in pool) { if (node.Text == _name) { tnode = node; break; } } // create a new group if it does not yet exist if (tnode == null) { tnode = new TreeNode(_name, (int)_icon, (int)_icon); tnode.Tag = new NodeTag(NodeTagType.NodeFolder, null, string.Empty); pool.Add(tnode); } // add the nodes which will be shown in this group foreach(NodeItem item in _items) { NodeTagType ntt = NodeTagType.Node; if (item.Type.IsSubclassOf(typeof(Attachments.Attachment))) { ntt = NodeTagType.Attachment; } NodeTag nodetag = new NodeTag(ntt, item.Type, string.Empty); TreeNode inode = new TreeNode(nodetag.Defaults.Label, (int)item.Icon, (int)item.Icon); inode.Tag = nodetag; inode.ToolTipText = nodetag.Defaults.Description; tnode.Nodes.Add(inode); } // add any sub-group foreach(NodeGroup group in _children) group.Register(tnode.Nodes); tnode.ExpandAll(); }
private static Node getNode(NodeTag.DefaultObject obj) { Node node = obj as Node; if (node == null) { Attachments.Attachment attach = obj as Attachments.Attachment; if (attach != null) node = attach.Node; } return node; }
private static void checkPar(NodeTag.DefaultObject obj, ParInfo par, ref List<Node.ErrorCheck> result) { Node node = getNode(obj); if (node != null && par != null) { Type type = obj.GetType(); foreach (PropertyInfo property in type.GetProperties()) { try { object value = property.GetValue(obj, null); if (value != null) { if (property.PropertyType == typeof(MethodDef)) { MethodDef method = value as MethodDef; Debug.Check(method != null); if (method.CheckPar(par)) result.Add(new Node.ErrorCheck(node, ErrorCheckLevel.Error, "Par as a parameter of the method.")); } else if (property.PropertyType == typeof(VariableDef)) { VariableDef var = value as VariableDef; Debug.Check(var != null); if (var.CheckPar(par)) result.Add(new Node.ErrorCheck(node, ErrorCheckLevel.Error, "Par as a value.")); } else if (property.PropertyType == typeof(RightValueDef)) { RightValueDef rv = value as RightValueDef; Debug.Check(rv != null); if (rv.CheckPar(par)) result.Add(new Node.ErrorCheck(node, ErrorCheckLevel.Error, "Par as a right value.")); } } } catch { } } } }
public static bool InvokeTypeParser(Type type, string parStr, SetValue setter, NodeTag.DefaultObject node, string paramName = null) { Debug.Check(type != null); if (_typeHandlers.ContainsKey(type)) { Type typeHandler = _typeHandlers[type]; MethodInfo parserMethod = typeHandler.GetMethod("Parse"); Debug.Check(parserMethod != null); if (string.IsNullOrEmpty(parStr) && type.IsPrimitive && type == typeof(string)) { return false; } object[] pars = { node, paramName, parStr, setter }; return (bool)parserMethod.Invoke(null, pars); } else if (type.IsEnum) { Array values = Enum.GetValues(type); foreach (object enumVal in values) { string enumValueName = Enum.GetName(type, enumVal); if (enumValueName == parStr) { setter(enumVal); return true; } } } else if (Plugin.IsArrayType(type)) { object obj = DesignerArray.ParseStringValue(type, parStr, node); setter(obj); return true; } else if (Plugin.IsCustomClassType(type)) { object obj = Behaviac.Design.Attributes.DesignerStruct.ParseStringValue(type, paramName, parStr, node); setter(obj); return true; } else { string message = string.Format("parser for {0} is not registered!", type.Name); throw new Exception(message); } return false; }
public static NodeTag.DefaultObject GetPreviousObjectById(Node root, int id, NodeTag.DefaultObject currentObj) { if (root == null || root == currentObj) return null; if (root.Id == id) return root; foreach (Attachments.Attachment attach in root.Attachments) { if (attach == currentObj) return null; if (attach.Id == id) return attach; } if (!(root is ReferencedBehavior)) { foreach (Node child in root.Children) { NodeTag.DefaultObject obj = GetPreviousObjectById(child, id, currentObj); if (null != obj) return obj; } } return null; }
/// <summary> /// Attaches a dragged node from the node explorer to an existing node. /// </summary> /// <param name="nvd">The node the new node will be attached to.</param> /// <param name="mode">The way the new node will be attached.</param> /// <param name="nodetag">The tag of the you want to create.</param> /// <param name="label">The label of the new node.</param> private void InsertNewNode(NodeViewData nvd, NodeAttachMode mode, NodeTag nodetag) { // check if the attach mode is valid if (mode == NodeAttachMode.Attachment || mode == NodeAttachMode.None) throw new Exception("A node cannot be created with the given attach mode"); if (nodetag.Type != NodeTagType.Behavior && nodetag.Type != NodeTagType.Prefab && nodetag.Type != NodeTagType.Node) throw new Exception("Only behaviours, prefabs and nodes can be attached to a behaviour tree"); Node node = nvd.Node; Node newnode = null; bool isPrefabInstance = false; // when we attach a behaviour we must create a special referenced behaviour node if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab) { if (!File.Exists(nodetag.Filename)) { if (!SaveBehavior(nodetag.Filename)) return; } // get the behavior we want to reference BehaviorNode behavior = _behaviorTreeList.LoadBehavior(nodetag.Filename); // a behaviour reference itself if (nvd.IsBehaviorReferenced(behavior)) { if (DialogResult.Cancel == MessageBox.Show(Resources.CircularReferencedInfo, Resources.Warning, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning)) return; } if (nodetag.Type == NodeTagType.Prefab) { behavior = (BehaviorNode)behavior.Clone(); } Behavior rootB = _rootNode.RootBehavior as Behavior; Behavior b = behavior as Behavior; if (rootB.AgentType == null) { rootB.AgentType = b.AgentType; } else if (!IsCompatibleAgentType(rootB, b)) { return; } // behavior if (nodetag.Type == NodeTagType.Behavior) { // create the referenced behaviour node for the behaviour ReferencedBehaviorNode refnode = Node.CreateReferencedBehaviorNode(_rootNode.RootBehavior, behavior); // register the view so it gets updated when the referenced behaviour gets updated. refnode.ReferencedBehaviorWasModified += new ReferencedBehavior.ReferencedBehaviorWasModifiedEventDelegate(refnode_ReferencedBehaviorWasModified); newnode = (Node)refnode; newnode.CommentText = Resources.ThisIsReferenceTree; newnode.CommentBackground = Node.CommentColor.Gray; } // prefab else { // Copy all Pars from the prefab file into the current behavior node. List<ParInfo> pars = new List<ParInfo>(); foreach (ParInfo par in b.Pars) { bool found = false; foreach (ParInfo rootPar in rootB.Pars) { if (par.Name == rootPar.Name) { if (par.Type != rootPar.Type) { string errorMsg = string.Format(Resources.ParErrorInfo, par.Name, b.Label, rootB.Label); MessageBox.Show(errorMsg, Resources.LoadError, MessageBoxButtons.OK); return; } found = true; break; } } if (!found) pars.Add(par); } rootB.Pars.AddRange(pars); if (ParSettingsDock.IsVisible()) ParSettingsDock.Inspect((Node)_rootNode.RootBehavior); // The first child should be the root node of the prefab tree. Node behaviorNode = (Node)behavior; if (behaviorNode.Children.Count > 0) { newnode = (Node)behaviorNode.Children[0]; string prefab = Path.GetFileNameWithoutExtension(behavior.Filename); newnode.CommentText = string.Format("Prefab[{0}]", prefab); isPrefabInstance = true; string prefabName = FileManagers.FileManager.GetRelativePath(behavior.Filename); newnode.SetPrefab(prefabName); } } } else { // simply create the node which is supposed to be created. newnode = Node.Create(nodetag.NodeType); } if (newnode == null) return; // update label newnode.OnPropertyValueChanged(false); // attach the new node with the correct mode switch (mode) { // the new node is inserted in front of the target node case (NodeAttachMode.Left): Node parent = (Node)node.Parent; int k = node.ParentConnector.GetChildIndex(node); Node.Connector conn = node.ParentConnector; Debug.Check(conn != null); parent.RemoveChild(conn, node); parent.AddChild(conn, newnode, k); Node.Connector newconn = newnode.GetConnector(conn.Identifier); Debug.Check(newconn != null); newnode.AddChild(newconn, node); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; break; // the new node is simply added to the target node's children case (NodeAttachMode.Right): node.AddChild(_dragTargetConnector, newnode); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd; break; // the new node is placed above the target node case (NodeAttachMode.Top): int n = _dragTargetNode.Node.ParentConnector.GetChildIndex(node); ((Node)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, n); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; break; // the new node is placed below the target node case (NodeAttachMode.Bottom): int m = _dragTargetNode.Node.ParentConnector.GetChildIndex(node); ((Node)node.Parent).AddChild(_dragTargetNode.Node.ParentConnector, newnode, m + 1); // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; break; // the node will replace the target node case (NodeAttachMode.Center): if (replaceNode(node, newnode)) { // automatically select the new node _selectedNodePending = newnode; _selectedNodePendingParent = nvd.Parent; } break; } // After being created, its Id should be reset. if (newnode != null) { newnode.ResetId(isPrefabInstance); // set the prefab dirty for the current parent if (newnode.Parent != null) { Node parent = (Node)newnode.Parent; if (!string.IsNullOrEmpty(parent.PrefabName)) { parent.HasOwnPrefabData = true; if (!isPrefabInstance) { newnode.SetPrefab(parent.PrefabName); newnode.HasOwnPrefabData = true; } } } if (nodetag.Type == NodeTagType.Behavior || nodetag.Type == NodeTagType.Prefab) ExpandedNodePool.SetExpandedNode(newnode.Behavior.RelativePath, newnode.Id.ToString(), false); UndoManager.Save(this.RootNode, newnode.Behavior); } // the layout needs to be recalculated LayoutChanged(); }