/// <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> /// 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(); }