public override void OnValidate(Graph assignedGraph) { if (actionList == null){ actionList = (ActionList)Task.Create(typeof(ActionList), assignedGraph); actionList.executionMode = ActionList.ActionsExecutionMode.ActionsRunInParallel; } }
//Duplicate a node along with all children hierarchy static Node DuplicateBranch(BTNode root, Graph targetGraph){ if (targetGraph == null) return null; var newNode = root.Duplicate(targetGraph); var dupConnections = new List<Connection>(); for (var i = 0; i < root.outConnections.Count; i++) dupConnections.Add( root.outConnections[i].Duplicate(newNode, DuplicateBranch( (BTNode)root.outConnections[i].targetNode, targetGraph) )); newNode.outConnections.Clear(); foreach (var c in dupConnections) newNode.outConnections.Add(c); return newNode; }
public override void OnValidate(Graph assignedGraph) { if (_onEnterList == null){ _onEnterList = (ActionList)Task.Create(typeof(ActionList), assignedGraph); _onEnterList.executionMode = ActionList.ActionsExecutionMode.ActionsRunInParallel; } if (_onUpdateList == null){ _onUpdateList = (ActionList)Task.Create(typeof(ActionList), assignedGraph); _onUpdateList.executionMode = ActionList.ActionsExecutionMode.ActionsRunInParallel; } if (_onExitList == null){ _onExitList = (ActionList)Task.Create(typeof(ActionList), assignedGraph); _onExitList.executionMode = ActionList.ActionsExecutionMode.ActionsRunInParallel; } }
public override void OnCreate(NodeCanvas.Framework.Graph assignedGraph) { _selectedInstanceMembers = new string[_instanceMemberNames.Count]; GatherPorts(); }
///Thats the same as calling the static Graph.SendGlobalEvent public static void SendGlobalEvent(string eventName) { Graph.SendGlobalEvent(new EventData(eventName)); }
///Thats the same as calling the static Graph.SendGlobalEvent public static void SendGlobalEvent <T>(string eventName, T eventValue) { Graph.SendGlobalEvent(new EventData <T>(eventName, eventValue)); }
///Duplicate node alone assigned to the provided graph public Node Duplicate(Graph targetGraph){ if (targetGraph == null){ Debug.LogError("Can't duplicate a Node without providing a Target Graph"); return null; } //deep clone var newNode = JSON.Deserialize<Node>( JSON.Serialize(typeof(Node), this ) ); #if UNITY_EDITOR if (!Application.isPlaying){ UnityEditor.Undo.RecordObject(targetGraph, "Duplicate"); } #endif targetGraph.allNodes.Add(newNode); newNode.inConnections.Clear(); newNode.outConnections.Clear(); if (targetGraph == this.graph) newNode.nodePosition += new Vector2(50,50); newNode.graph = targetGraph; BBParameter.SetBBFields(newNode, targetGraph.blackboard); var assignable = this as ITaskAssignable; if (assignable != null && assignable.task != null) (newNode as ITaskAssignable).task = assignable.task.Duplicate(graph); newNode.OnValidate(targetGraph); return newNode; }
///Called when the Node is created, duplicated or otherwise needs validation. virtual public void OnValidate(Graph assignedGraph){}
//Open GraphEditor initializing target graph public static GraphEditor OpenWindow(Graph newGraph, Component agent, IBlackboard blackboard) { var window = GetWindow<GraphEditor>(); if (newGraph != null){ //force assign references only in edit mode so that we can debug correctly if (!Application.isPlaying){ newGraph.agent = agent; newGraph.blackboard = blackboard; } newGraph.currentChildGraph = null; newGraph.UpdateNodeIDs(false); } window.rootGraph = newGraph; window.targetOwner = null; Graph.currentSelection = null; if (NCPrefs.showWelcomeWindow && !Application.isPlaying && welcomeShown == false){ welcomeShown = true; WelcomeWindow.OpenWindow(); } return window; }
///Create a new Node of type and assigned to the provided graph. Use this for constructor public static Node Create(Graph targetGraph, System.Type nodeType, Vector2 pos){ if (targetGraph == null){ Debug.LogError("Can't Create a Node without providing a Target Graph"); return null; } var newNode = (Node)System.Activator.CreateInstance(nodeType); #if UNITY_EDITOR if (!Application.isPlaying){ UnityEditor.Undo.RecordObject(targetGraph, "Create Node"); } #endif newNode.graph = targetGraph; newNode.nodePosition = pos; BBParameter.SetBBFields(newNode, targetGraph.blackboard); newNode.OnValidate(targetGraph); return newNode; }
//For opening the window from gui button in the nodegraph's Inspector. public static GraphEditor OpenWindow(Graph newGraph){ return OpenWindow(newGraph, newGraph.agent, newGraph.blackboard); }
/* private bool isShowingHotBox = false; void DoHotBoxPanel(){ var e = Event.current; if (e.type == EventType.KeyDown && e.keyCode == KeyCode.Space){ isShowingHotBox = true; } if (e.type == EventType.KeyUp && e.keyCode == KeyCode.Space){ isShowingHotBox = false; } if (isShowingHotBox){ var hotboxRect = new Rect( 50, 50, Screen.width - 100, Screen.height - 100 ); GUI.Box(hotboxRect, "minimap", (GUIStyle)"editorPanel"); GUI.BeginGroup(hotboxRect); //TODO? GUI.EndGroup(); } } */ //This is the hierarchy shown at top left. Recusrsively show the nested path void ShowBreadCrumbNavigation(Graph root){ if (root == null) return; //if something selected the inspector panel shows on top of the breadcrub. If external inspector active it doesnt matter, so draw anyway. if (Graph.currentSelection != null && !NCPrefs.useExternalInspector) return; var agentInfo = root.agent != null? root.agent.gameObject.name : "No Agent"; var bbInfo = root.blackboard != null? root.blackboard.name : "No Blackboard"; var graphInfo = string.Format("<color=#ff4d4d>({0})</color>", targetOwner != null && targetOwner.graph == root && targetOwner.graphIsLocal? "Bound" : ( EditorUtility.IsPersistent(root)? "Asset Reference" : "Instance" ) ); GUI.color = new Color(1f,1f,1f,0.5f); GUILayout.BeginVertical(); if (root.currentChildGraph == null){ if (root.agent == null && root.blackboard == null){ GUILayout.Label(string.Format("<b><size=22>{0} {1}</size></b>", root.name, graphInfo)); } else { GUILayout.Label(string.Format("<b><size=22>{0} {1}</size></b>\n<size=10>{2} | {3}</size>", root.name, graphInfo, agentInfo, bbInfo)); } } else { GUILayout.BeginHorizontal(); //"button" implemented this way due to e.used. It's a delegate matter.. GUILayout.Label("⤴ " + root.name, (GUIStyle)"button"); if (Event.current.type == EventType.MouseUp && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)){ root.currentChildGraph = null; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); ShowBreadCrumbNavigation(root.currentChildGraph); } GUILayout.EndVertical(); GUI.color = Color.white; }
//Recursively get the currenlty showing nested graph starting from the root Graph GetCurrentGraph(Graph root){ if (root.currentChildGraph == null) return root; return GetCurrentGraph(root.currentChildGraph); }
void OnGUI(){ if (EditorApplication.isCompiling){ ShowNotification(new GUIContent("Compiling Please Wait...")); return; } //Init GUI.color = Color.white; GUI.backgroundColor = Color.white; e = Event.current; GUI.skin = guiSkin; //get the graph from the GraphOwner if one is set if (targetOwner != null) rootGraph = targetOwner.graph; if (rootGraph == null){ ShowNotification(new GUIContent("Please select a GraphOwner GameObject or a Graph Asset")); return; } //hande undo/redo keyboard commands if (e.type == EventType.ValidateCommand && e.commandName == "UndoRedoPerformed"){ GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; Graph.currentSelection = null; //TODO: fix this to not happen currentGraph.Validate(); //validate the graph after the undo e.Use(); return; } ///should we set dirty the owner (if any). Put in practise at the end var setDirty = false; if ( (e.type == EventType.MouseUp && e.button != 2) || e.type == EventType.KeyUp ){ setDirty = true; } //set the currently viewing graph by getting the current child graph from the root graph recursively currentGraph = GetCurrentGraph(rootGraph); if (currentGraph == null || ReferenceEquals(currentGraph, null)){ return; } //handles mouse & keyboard inputs HandleEvents(e); //initialize canvasRect canvasRect = new Rect(5, topMargin, position.width -10, position.height - topMargin - 5); //canvas background GUI.Box(canvasRect, string.Format("{0}\n{1}", currentGraph.GetType().Name, "@NodeCanvas v2.3.6"), "canvasBG"); if (zoomFactor != 1) canvasRect = StartZoomArea(canvasRect); //main group GUI.BeginGroup(canvasRect); //pan the view rect totalCanvas = canvasRect; totalCanvas.x = 0; totalCanvas.y = 0; totalCanvas.x += pan.x/zoomFactor; totalCanvas.y += pan.y/zoomFactor; totalCanvas.width -= pan.x/zoomFactor; totalCanvas.height -= pan.y/zoomFactor; //begin panning group GUI.BeginGroup(totalCanvas); //inverse pan the view rect viewRect = totalCanvas; viewRect.x = 0; viewRect.y = 0; viewRect.x -= pan.x/zoomFactor; viewRect.y -= pan.y/zoomFactor; viewRect.width += pan.x/zoomFactor; viewRect.height += pan.y/zoomFactor; nodeBounds = GetNodeBounds(viewRect, true); DrawGrid(viewRect, pan, zoomFactor); DoCanvasGroups(e); BeginWindows(); currentGraph.ShowNodesGUI(e, viewRect, fullDrawPass, mousePosInCanvas, zoomFactor); EndWindows(); DoCanvasRectSelection(viewRect); GUI.EndGroup(); GUI.EndGroup(); if (zoomFactor != 1) EndZoomArea(); ShowScrollBars(); //Breadcrumb navigation GUILayout.BeginArea(new Rect(20, topMargin + 5, Screen.width, Screen.height)); ShowBreadCrumbNavigation(rootGraph); GUILayout.EndArea(); //Graph controls (after windows so that panels (inspector, blackboard) show on top) currentGraph.ShowGraphControls(e, mousePosInCanvas); //repaint? if (willRepaint > 0 || rootGraph.isRunning){ willRepaint = Mathf.Max(willRepaint -1, 0); Repaint(); } //Set nodes size to minimum. They rescale to fit automaticaly since they use GUILayout.Window. //This is done if GUI.changed since basicaly the only reason for a size to change is because some node inspector value has changed if (GUI.changed){ foreach (var node in currentGraph.allNodes){ node.nodeRect = new Rect( node.nodePosition.x, node.nodePosition.y, Node.minSize.x, Node.minSize.y ); } Repaint(); } //Set the targetowner if any dirty for correct prefab override in case of local graphs if (setDirty){ setDirty = false; EditorUtility.SetDirty(currentGraph); } //closure GUI.Box(canvasRect,"", "canvasBorders"); GUI.skin = null; GUI.color = Color.white; GUI.backgroundColor = Color.white; fullDrawPass = false; }
//Handles and shows the right click mouse button for the node context menu void HandleContextMenu(Event e) { var isContextClick = (e.type == EventType.MouseUp && e.button == 1) || (e.control && e.type == EventType.MouseUp || e.type == EventType.ContextClick); if (Graph.allowClick && isContextClick) { //Multiselection menu if (Graph.multiSelection.Count > 1) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Duplicate Selected Nodes"), false, () => { var newNodes = Graph.CopyNodesToGraph(Graph.multiSelection.OfType <Node>().ToList(), graph); Graph.multiSelection = newNodes.Cast <object>().ToList(); }); menu.AddItem(new GUIContent("Copy Selected Nodes"), false, () => { copiedNodes = Graph.multiSelection.OfType <Node>().ToArray(); }); menu.AddSeparator("/"); menu.AddItem(new GUIContent("Delete Selected Nodes"), false, () => { foreach (Node node in Graph.multiSelection.ToArray()) { graph.RemoveNode(node); } }); Graph.PostGUI += () => { menu.ShowAsContext(); }; //Post GUI cause of zoom e.Use(); return; //Single node menu } else { var menu = new GenericMenu(); if (graph.primeNode != this && allowAsPrime) { menu.AddItem(new GUIContent("Set Start"), false, () => { graph.primeNode = this; }); } if (this is IGraphAssignable) { menu.AddItem(new GUIContent("Edit Nested (Double Click)"), false, () => { graph.currentChildGraph = (this as IGraphAssignable).nestedGraph; }); } menu.AddItem(new GUIContent("Duplicate (CTRL+D)"), false, () => { Graph.currentSelection = Duplicate(graph); }); menu.AddItem(new GUIContent("Copy Node"), false, () => { copiedNodes = new Node[] { this }; }); if (inConnections.Count > 0) { menu.AddItem(new GUIContent(isActive? "Disable" : "Enable"), false, () => { SetActive(!isActive); }); } if (graph.autoSort && outConnections.Count > 0) { menu.AddItem(new GUIContent(collapsed? "Expand Children" : "Collapse Children"), false, () => { collapsed = !collapsed; }); } if (this is ITaskAssignable) { var assignable = this as ITaskAssignable; if (assignable.task != null) { menu.AddItem(new GUIContent("Copy Assigned Task"), false, () => { Task.copiedTask = assignable.task; }); } else { menu.AddDisabledItem(new GUIContent("Copy Assigned Task")); } if (Task.copiedTask != null) { menu.AddItem(new GUIContent("Paste Assigned Task"), false, () => { if (assignable.task == Task.copiedTask) { return; } if (assignable.task != null) { if (!EditorUtility.DisplayDialog("Paste Task", string.Format("Node already has a Task assigned '{0}'. Replace assigned task with pasted task '{1}'?", assignable.task.name, Task.copiedTask.name), "YES", "NO")) { return; } } try { assignable.task = Task.copiedTask.Duplicate(graph); } catch { Debug.LogWarning("Can't paste Task here. Incombatible Types"); } }); } else { menu.AddDisabledItem(new GUIContent("Paste Assigned Task")); } } menu = OnContextMenu(menu); if (menu != null) { menu.AddSeparator("/"); menu.AddItem(new GUIContent("Delete (DEL)"), false, () => { graph.RemoveNode(this); }); Graph.PostGUI += () => { menu.ShowAsContext(); }; } e.Use(); } } }