private static bool CheckCondition(QueueItem item) { return(item.Condition != null && item.Condition.Invoke(item.Nodes)); }
/// <summary> /// Selects a composite to be run /// This is called every tick and returns a composite /// Which composite is returned changes based on the QueueItem currently being processed. /// </summary> private static Composite Next() { // 1. No active node if (_active == null) { // 1.1 Nothing in the Queue. if (!Q.Any()) { return(Continue); } // 1.2 Start the next QueueItem that has passed its condition var nextItem = Q.FirstOrDefault(n => n.ConditionPassed); if (nextItem != null) { Logger.Verbose("Starting QueueItem"); if (Q.Remove(nextItem)) { _active = nextItem; if (_active.OnStart != null) { _active.OnStart.Invoke(_active); } return(Loop); } ; } // 1.3 Nothing has passed condition yet. return(Continue); } // 2. We're currently processing a QueueItem // But havent started processing its nodes. if (_active.ActiveNode == null) { // 2.1 Handle starting the first Node _active.ActiveNode = _active.Nodes.First(); _active.ActiveNode.Run(); if (_active.OnNodeStart != null) { _active.OnNodeStart.Invoke(_active); } return(_active.ActiveNode.Behavior); } BotMain.StatusText = _active.ActiveNode.StatusText; // 3. We're currently processing a QueueItem // And the current node is Done if (_active.ActiveNode.IsDone) { // 3.1 Handle ActiveNode has finished _active.CompletedNodes++; _active.ActiveNode.OnDone(); Logger.Verbose("[{0}] Complete {1}/{2} ({3})", _active.Name, _active.CompletedNodes, _active.Nodes.Count, _active.ActiveNode.GetType()); if (_active.OnNodeDone != null) { _active.OnNodeDone.Invoke(_active); } // 3.2 All nodes are finished, so the QueueItem is now Done. if (_active.IsComplete) { // 3.2.1 Handle all nodes are finished if (_active.OnDone != null) { _active.OnDone.Invoke(_active); } Logger.Verbose("[{1}] Completed {0}", _active.CompletedNodes, _active.Name); // 3.2.2 Traverse Upwards // If this QueueItem is a child, we need to continue with its parent // Parent gets taken off the shelf (unpaused) and set as the new active Queueitem. var parent = Shelf.FirstOrDefault(i => i.ParentOf == _active.Id); Logger.Verbose("All Nodes Complete ParentId={0} ThisId={1}", parent != null ? parent.Id.ToString() : "Null", _active.Id); if (parent != null) { _active = parent; Shelf.Remove(parent); Logger.Verbose("ShelfCount={0}", Shelf.Count); return(Loop); } // 3.2.3 Shove it back at the bottom of the queue if it should be repeated if (_active.Repeat) { var temp = _active; _active.Reset(); _active = null; Queue(temp); return(Loop); } // 3.2.4 No parent, No Repeat, so just end the QueueItem _active = null; return(Loop); } // 3.3 Handle start of next node var currentPosition = _active.Nodes.IndexOf(_active.ActiveNode); _active.ActiveNode = _active.Nodes.ElementAt(currentPosition + 1); _active.ActiveNode.Run(); if (_active.OnNodeStart != null) { _active.OnNodeStart.Invoke(_active); } return(_active.ActiveNode.Behavior); } // 4.1 Traverse Downwards // We're currently processing a QueueItem // And the current node is NOT Done // And the current node has children Logger.Verbose("ShelfCount={0}", Shelf.Count); var children = _active.ActiveNode.GetChildren(); if (children.Count > 0) { Logger.Log("Processing {0} Children of '{1}' ({2})", children.Count, _active.Name, _active.Id); // Copy QueueItem so we can resume it later. var queueItemToShelve = _active; // Wrap the children as a new QueueItem var childQueueItem = new QueueItem { Name = string.Format("Children of {0}", _active.Name), Nodes = _active.ActiveNode.GetChildren() }; // Store a references between parent and child queueItemToShelve.ParentOf = childQueueItem.Id; childQueueItem.ChildOf = _active.Id; // Pause the active QueueItem by moving it to the shelf Shelf.Add(queueItemToShelve); // Start working on the children. _active = childQueueItem; return(Loop); } // Handle continuing an in-progress Node LogBehavior(_active); return(_active.ActiveNode.Behavior); }