HashSet <RunnableNode> FollowNode(Node currentNode, Node prevNode, RunnableNode lastRunnable, HashSet <Node> triedNodes, NodePath path) { // If this node has already been tried, it's path has already been followed - cancel this branch if (triedNodes.Contains(currentNode) && optimiseParallel) { if (recordNodePaths) { checkinNodePaths.Add(path); } return(new HashSet <RunnableNode>()); } /*if (triedNodes.Contains(currentNode) && optimiseParallel) { * HashSet<RunnableNode> retNodes = new HashSet<RunnableNode>(); * retNodes.Add(lastRunnable); * return retNodes; * }*/ // Node has been encountered - trigger the event currentNode.OnEncountered(prevNode, _machine, this); // The current chain's HashSet of runnables to stop at HashSet <RunnableNode> runnables = new HashSet <RunnableNode>(); runnables.Add(lastRunnable); // The HashSet of nodes to test next HashSet <Node> nextNodes = new HashSet <Node>(); // Get nodes from the current node to test next // If not specified, default to link testing Node[] givenNextNodes = currentNode.NextNodes(); if (givenNextNodes != null) { foreach (Node node in givenNextNodes) { if (node == null) { Debug.LogError("Given null node to follow from " + currentNode + "!"); } else { nextNodes.Add(node); } } } else { // Get links from the current node to test next // Use node specified links if specified Link[] links = currentNode.NextLinks(); if (links == null) { links = _model.GetOutputLinks(currentNode).ToArray(); } // Store the node in the loop checking HashSet if doing so if (optimiseParallel) { triedNodes.Add(currentNode); } // If the current node is blocking, kill the chain if (currentNode.IsBlocking()) { if (recordNodePaths) { checkinNodePaths.Add(path); } return(runnables); } // Test connected links foreach (Link link in links) { Node nextNode = _model.GetNodeFromID(link._to); // Add the tested link to the current link chain for live preview _currentLinks.Add(link); nextNodes.Add(nextNode); } } currentNode.OnPassed(nextNodes, _machine, this); foreach (Node nextNode in nextNodes) { // Record next node as an entry in the path NodePath newPath = null; if (recordNodePaths) { newPath = new NodePath(); newPath.currentNode = nextNode; newPath.fromPath = path; path.toPath = newPath; } // If nextNode is an EndNode, kill the chain if (nextNode is EndNode) { if (recordNodePaths) { checkinNodePaths.Add(newPath); } encounteredEnd = true; return(new HashSet <RunnableNode>()); } // If nextNode is a RunnableNode, store it as the next return point. // Otherwise continue with the last return point. RunnableNode makeLastRunnable = lastRunnable; if (nextNode is RunnableNode) { makeLastRunnable = nextNode as RunnableNode; } // Set up new triedNodes listing HashSet <Node> newTriedNodes = new HashSet <Node>(triedNodes); HashSet <RunnableNode> nextRunnables = FollowNode(nextNode, currentNode, makeLastRunnable, newTriedNodes, newPath); // If the model doesn't support parallel states, use first come first serve if (!_model.supportParallel) { return(nextRunnables); } else { runnables.Remove(lastRunnable); foreach (RunnableNode runnable in nextRunnables) { runnables.Add(runnable); } } } runnables.RemoveWhere(r => r == null); // Check if there are any runnables different from the last one given for this chain. bool runnableChange = false; foreach (RunnableNode runnable in runnables) { if (runnable != lastRunnable) { runnableChange = true; break; } } // If there is a change, remove the last runnable, otherwise maintain the chain. if (runnableChange) { runnables.Remove(lastRunnable); } if (recordNodePaths) { checkinNodePaths.Add(path); } return(runnables); }
void OnGUI() { if (_model == null) { if (_selectedMachine == null) { NodeMachineGUIUtils.DrawNothingOpenScreen(this); } else { NodeMachineGUIUtils.DrawMachineNoModelScreen(this); } return; } Vector2 center = new Vector2(position.width / 2, position.height / 2) - (_nodeEditor.position / 2); _offset = _uncenteredOffset + center; titleContent = _changesMade ? NodeMachineEditor.titleUnsaved : NodeMachineEditor.titlePlain; bool livePreview = _selectedMachine != null && EditorApplication.isPlaying; bool modelNeedsSaving = false; _nodeEditor = new Rect(250, 30, position.width - 250, position.height - 30); _sideMenu = new Rect(10, 20, 230, position.height - 20); _toolbar = new Rect(260, 5, position.width - 260, 25); // ----- TOOLBAR -------- GUILayout.BeginArea(_toolbar); GUILayout.BeginHorizontal(); _drawTransparentLinks = GUILayout.Toggle(_drawTransparentLinks, " Link X-Ray", GUILayout.ExpandWidth(false)); GUILayout.Label(" ", GUILayout.ExpandWidth(false)); _showInivisibleNodes = GUILayout.Toggle(_showInivisibleNodes, " Reveal hidden nodes", GUILayout.ExpandWidth(false)); GUILayout.Label(" ", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.EndArea(); // ----- SIDE MENU ------ GUILayout.BeginArea(_sideMenu); GUILayout.BeginVertical(); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); EditorGUILayout.LabelField(_model.name, EditorStyles.boldLabel); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); EditorGUILayout.Space(); float checkinTimeBeforeDraw = _model.CheckinTime; bool supportParallelBeforeDraw = _model.supportParallel; _model.CheckinTime = EditorGUILayout.FloatField("Checkin time", _model.CheckinTime); _model.supportParallel = EditorGUILayout.Toggle("Parallel flow", _model.supportParallel); if (checkinTimeBeforeDraw != _model.CheckinTime || supportParallelBeforeDraw != _model.supportParallel) { modelNeedsSaving = true; } EditorGUILayout.Space(); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); EditorGUILayout.Space(); _propertyMenu.DrawMenu(EditorApplication.isPlayingOrWillChangePlaymode, _selectedMachine); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); // --------- ERRORS --------- EditorGUILayout.Space(); _errorPanel.Draw(); EditorGUILayout.Space(); EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); GUILayout.EndVertical(); GUILayout.EndArea(); // ----- NODE EDITOR ----- GUILayout.BeginArea(_nodeEditor, new GUIStyle("Box")); NodeMachineGUIUtils.DrawGrid(10, 0.2f, Color.gray, this); // * zoom NodeMachineGUIUtils.DrawGrid(50, 0.4f, Color.gray, this); // * zoom foreach (Link link in _model.GetLinks()) { if (livePreview) { NodeMachineGUIUtils.DrawLink(link, _selectedMachine.CurrentLinks.Contains(link), this); } else { NodeMachineGUIUtils.DrawLink(link, false, this); } } if (_creatingLink) { Rect fromTransform = new Rect(_selectedNode.drawnTransform.position - _nodeEditor.position, _selectedNode.drawnTransform.size); NodeMachineGUIUtils.DrawArrow(fromTransform, Event.current.mousePosition, this); } foreach (Node node in _model.GetNodes()) { if (livePreview && node is RunnableNode) { RunnableNode runnable = node as RunnableNode; if (_selectedMachine.CurrentRunnables.Contains(node)) { if (NodeMachineGUIUtils.DrawNode(node, runnable.activeBackground, this, Event.current)) { modelNeedsSaving = true; } } else { if (NodeMachineGUIUtils.DrawNode(node, this, Event.current)) { modelNeedsSaving = true; } } } else { if (NodeMachineGUIUtils.DrawNode(node, this, Event.current)) { modelNeedsSaving = true; } } } // Draw transparent links over everything - looks like links are showing through from behind nodes if (_drawTransparentLinks) { foreach (Link link in _model.GetLinks()) { if (livePreview) { NodeMachineGUIUtils.DrawTransparentLink(link, _selectedMachine.CurrentLinks.Contains(link), this); } else { NodeMachineGUIUtils.DrawTransparentLink(link, false, this); } } } GUILayout.EndArea(); // --------------------- PROCESS EVENTS ---------------------------- if (_nodeEditor.Contains(Event.current.mousePosition)) { Vector2 totalOffset = _offset + _nodeEditor.position; foreach (Node node in _model.GetNodes().Reverse()) { if (node.visible || _showInivisibleNodes) { if (node.ProcessEvents(Event.current, _zoom, SelectNode, ProcessNodeContextMenu)) { modelNeedsSaving = true; } } } foreach (Link link in _model.GetLinks()) { link.ProcessEvents(Event.current, totalOffset, ProcessLinkContextMenu, SelectLink); } } ProcessEvents(Event.current); if (modelNeedsSaving) { MarkUnsaved(); } if (GUI.changed) { Repaint(); } }