Example #1
0
        public async Task <ActionResult> ProcessAllAsync(object UserData = null, int MaxUnwindDepth = 0, bool one = false)
        {
            LastActionCancelled = false;
            bool DoneOne = false;

            while (!Paused && !IsBlockEmpty && !LastActionCancelled && !DoneOne)
            {
                if (one)
                {
                    DoneOne = true;
                }
                // Get next action and make sure it's up to date if cloned from another game
                var action = Queue.RemoveFront();
                action.Game = Game;
                if (action.Source.Game.GameId != Game.GameId)
                {
                    action.Source = Game.Entities[action.Source.Id];
                }
#if _QUEUE_DEBUG
                DebugLog.WriteLine("Queue (Game " + Game.GameId + "): Dequeued action " + action + " for " + action.Source.ShortDescription + " at depth " + Depth);
#endif
                // Get needed arguments for action from stack
                action.Args = new ActionResult[action.Action.Args.Count];
                for (int i = action.Action.Args.Count - 1; i >= 0; i--)
                {
                    // Prefer PreCompiledQueueAction items as arguments
                    var arg = action.Action.CompiledArgs[i];
                    if (!arg.HasResult)
                    {
                        // Otherwise prefer EagerQueueAction items as arguments
                        if (action.Action.EagerArgs[i] != null)
                        {
                            arg = action.Action.EagerArgs[i].Run(Game, action.Source, null);
                        }
                        else
                        {
                            // Otherwise use the ResultStack to get regular QueueAction items as arguments
                            // In this round, only pop arguments for which ActionGraph parameters were supplied
                            // to the QueueAction as these will be at the top of the stack
                            if (action.Action.Args[i] != null)
                            {
                                arg = StackPop();
                                List <IEntity> eList = arg;
                                if (eList != null && eList.Count > 0 && eList[0].Game != Game)
                                {
                                    arg = new List <IEntity>(eList.Select(e => Game.Entities[e.Id]));
                                }
                            }
                        }
                    }
                    action.Args[i] = arg;
                }
                // Now go through all of the arguments that weren't supplied as ActionGraphs and pop them off the stack
                for (int i = action.Action.Args.Count - 1; i >= 0; i--)
                {
                    if (action.Action.Args[i] == null)
                    {
                        var            arg   = StackPop();
                        List <IEntity> eList = arg;
                        if (eList != null && eList.Count > 0 && eList[0].Game != Game)
                        {
                            arg = new List <IEntity>(eList.Select(e => Game.Entities[e.Id]));
                        }
                        action.Args[i] = arg;
                    }
                }

                // Replace current UserData with new UserData if supplied
                if (UserData != null)
                {
                    this.UserData = UserData;
                }
                action.UserData = this.UserData;

                if (OnActionStarting != null)
                {
                    OnActionStarting(this, action);
                    if (action.Cancel)
                    {
                        LastActionCancelled = true;
                        continue;
                    }
                }
                var actionType = action.Action.GetType();
                if (ReplacedActions.ContainsKey(actionType))
                {
                    await ReplacedActions[actionType](this, action);
                    // action.Cancel implied when action is replaced
                    LastActionCancelled = true;
                    continue;
                }
                if (HasHistory)
                {
                    AddItem(action);
                }

                // Run action and push results onto stack
#if _QUEUE_DEBUG
                DebugLog.WriteLine("Queue (Game " + Game.GameId + "): Running action " + action + " for " + action.Source.ShortDescription + " at depth " + Depth);
#endif
                var @async = action.Action as QueueActionAsync;
                var result = (@async != null
                                        ? await @async.RunAsync(action.Game, action.Source, action.Args)
                                        : action.Action.Run(action.Game, action.Source, action.Args));
                if (result.HasResult)
                {
                    StackPush(result);
                }
                // The >= allows the current block to unwind for ProcessBlock()
                while (IsBlockEmpty && Depth >= MaxUnwindDepth)
                {
                    EndBlock();
                    if (IsEmpty)
                    {
                        break;
                    }
                }
#if _QUEUE_DEBUG
                DebugLog.WriteLine("Queue (Game " + Game.GameId + "): Finished action " + action + " for " + action.Source.ShortDescription + " at depth " + Depth);
#endif
                OnAction?.Invoke(this, action);

                // Propagate cancellation up the chain by only changing it if not already set
                LastActionCancelled = action.Cancel;
            }
            // Return whatever is left on the stack
            if (LastActionCancelled)
            {
                return(ActionResult.None);
            }
            var finalResult = ResultStack.Reverse().FirstOrDefault();
            if (!Paused && IsEmpty)
            {
                StackClear();
            }
            return(finalResult);
        }