Пример #1
0
        private static void ProcessCommandsWorkerThread()
        {
            while (!ShuttingDown)
            {
                CommandReadyHandle.WaitOne();

                try
                {
                    //if (NextCommand.Actor.ConnectedClient != null)
                    //    NextCommand.Actor.ConnectedClient.TimeOfLastCommand = DateTime.Now;
                    NextCommand.Actor.CommandHandler.HandleCommand(NextCommand);
                }
                catch (System.Threading.ThreadAbortException)
                {
                    LogError("Command worker thread was aborted. Timeout hit?");
                    Core.ClearPendingMessages();
                }
                catch (Exception e)
                {
                    LogCommandError(e);
                    Core.ClearPendingMessages();
                }

                NextCommand = null;

                CommandFinishedHandle.Set();
            }
        }
Пример #2
0
        /// <summary>
        /// Process commands in a single thread, until there are no more queued commands.
        /// Heartbeat is called between every command.
        /// </summary>
        public static void ProcessCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) != StartupFlags.SingleThreaded)
            {
                throw new InvalidOperationException("ProcessCommands should only be called in single threaded mode.");
            }

            while (PendingCommands.Count > 0 && !ShuttingDown)
            {
                GlobalRules.ConsiderPerformRule("heartbeat");

                Core.SendPendingMessages();

                PendingCommand PendingCommand = null;

                try
                {
                    PendingCommand = PendingCommands.FirstOrDefault();
                    if (PendingCommand != null)
                    {
                        PendingCommands.Remove(PendingCommand);
                    }
                }
                catch (Exception e)
                {
                    LogCommandError(e);
                    PendingCommand = null;
                }

                if (PendingCommand != null)
                {
                    NextCommand = PendingCommand;

                    //Reset flags that the last command may have changed
                    CommandTimeoutEnabled = true;
                    SilentFlag            = false;
                    GlobalRules.LogRules(null);

                    try
                    {
                        var handler = NextCommand.Actor.GetProperty <ClientCommandHandler>("command handler");
                        if (handler != null)
                        {
                            handler.HandleCommand(NextCommand);
                        }
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        Core.DiscardPendingMessages();
                    }
                    if (PendingCommand.ProcessingCompleteCallback != null)
                    {
                        PendingCommand.ProcessingCompleteCallback();
                    }
                }
            }
        }
Пример #3
0
        public MatchedCommand ParseCommand(PendingCommand Command)
        {
            var tokens = new LinkedList<String>(Command.RawCommand.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));

            var rootMatch = new PossibleMatch(tokens.First);
            rootMatch.Upsert("ACTOR", Command.Actor);
            rootMatch.Upsert("LOCATION", Command.Actor == null ? null : Command.Actor.Location);

            // A pending command can have some properties set when it is queued. For example, the 'go' action
            // generates a 'look' command after processing. It will give the 'look' command a property named
            // 'auto' to indicate that the look command was generated. Rules can then use this property to
            // implement behavior. From the same example, 'look' may emit a brief description if it is generated
            // by the 'go' action, but emit a more detailed description if the player enters the command 'look'.
            //      See StandardActions.Go
            if (Command.PreSettings != null)
                foreach (var setting in Command.PreSettings)
                    rootMatch.Upsert(setting.Key.ToUpper(), setting.Value);

            var matchContext = new MatchContext { ExecutingActor = Command.Actor };

            // Try every single command defined, until one matches.
            foreach (var command in Commands)
            {
                IEnumerable<PossibleMatch> matches;

                try
                {
                    matches = command.Matcher.Match(rootMatch, matchContext);
                }
                catch (MatchAborted ma)
                {
                    // The match didn't fail; it generated an error. These means the match progressed to a point
                    // where the author of the command felt that the input could not logically match any other
                    // command, however, the input was still malformed in some way. Abort matching, and dummy up
                    // a command entry to display the error message to the player.
                    return new MatchedCommand(
                        new CommandEntry().ProceduralRule((match, actor) =>
                        {
                            MudObject.SendMessage(actor, ma.Message);
                            return PerformResult.Continue;
                        }),
                        // We need a fake match just so it can be passed to the procedural rule.
                        new PossibleMatch[] { new PossibleMatch(null) });
                }

                // Only accept matches that consumed all of the input.
                matches = matches.Where(m => m.Next == null);

                // If we did consume all of the input, we will assume this match is successful. Note it is
                // possible for a command to generate multiple matches, but not possible to match multiple commands.
                if (matches.Count() > 0)
                    return new MatchedCommand(command, matches);
            }
            return null;
        }
Пример #4
0
        /// <summary>
        /// Process commands in a single thread, until there are no more queued commands.
        /// Heartbeat is called between every command.
        /// </summary>
        public static void ProcessCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) != StartupFlags.SingleThreaded)
                throw new InvalidOperationException("ProcessCommands should only be called in single threaded mode.");

            while (PendingCommands.Count > 0 && !ShuttingDown)
            {
                GlobalRules.ConsiderPerformRule("heartbeat");

                Core.SendPendingMessages();

                PendingCommand PendingCommand = null;

                try
                {
                    PendingCommand = PendingCommands.FirstOrDefault();
                    if (PendingCommand != null)
                        PendingCommands.Remove(PendingCommand);
                }
                catch (Exception e)
                {
                    LogCommandError(e);
                    PendingCommand = null;
                }

                if (PendingCommand != null)
                {
                    NextCommand = PendingCommand;

                    //Reset flags that the last command may have changed
                    CommandTimeoutEnabled = true;
                    SilentFlag = false;
                    GlobalRules.LogRules(null);

                    try
                    {
                        NextCommand.Actor.CommandHandler.HandleCommand(NextCommand);
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        Core.ClearPendingMessages();
                    }
                    if (PendingCommand.ProcessingCompleteCallback != null)
                        PendingCommand.ProcessingCompleteCallback();

                }
            }
        }
Пример #5
0
 public void HandleCommand(PendingCommand Command)
 {
     try
     {
         var matchedCommand = Parser.ParseCommand(Command);
         if (matchedCommand != null)
         {
             Core.ProcessPlayerCommand(matchedCommand.Command, matchedCommand.Matches[0], Command.Actor);
         }
         else
             MudObject.SendMessage(Command.Actor, "I do not understand.");
     }
     catch (Exception e)
     {
         Core.ClearPendingMessages();
         MudObject.SendMessage(Command.Actor, e.Message);
     }
 }
Пример #6
0
        public void HandleCommand(PendingCommand Command)
        {
            Command.Actor.SetProperty("command handler", ParentHandler);

            //Just retry if the attempt to help has failed.
            if (DisambigObjects == null)
            {
                Core.EnqueuActorCommand(Command);
                return;
            }

            int ordinal = 0;

            if (Int32.TryParse(Command.RawCommand, out ordinal))
            {
                if (ordinal < 0 || ordinal >= DisambigObjects.Count)
                {
                    Core.SendMessage(Command.Actor, "That wasn't a valid option. I'm aborting disambiguation.");
                }
                else
                {
                    var choosenMatches = MatchedCommand.Matches.Where(m => Object.ReferenceEquals(m[DisambigArgument], DisambigObjects[ordinal]));
                    MatchedCommand.Matches = new List <PossibleMatch>(choosenMatches);

                    if (MatchedCommand.Matches.Count == 1)
                    {
                        Core.ProcessPlayerCommand(MatchedCommand.Command, MatchedCommand.Matches[0], Command.Actor);
                    }
                    else
                    {
                        // WHat? There are still multiple options?
                        Core.SendMessage(Command.Actor, "That helped narrow it down, but I'm still not sure what you mean.");
                        Command.Actor.SetProperty("command handler", new DisambigCommandHandler(Command.Actor, MatchedCommand, ParentHandler));
                    }
                }
            }
            else
            {
                // The input was nor an ordial. Go ahead and requeue the command so the normal command handler
                // can take care of it.
                Core.EnqueuActorCommand(Command);
            }
        }
Пример #7
0
 public void HandleCommand(PendingCommand Command)
 {
     try
     {
         var matchedCommand = Parser.ParseCommand(Command);
         if (matchedCommand != null)
         {
             Core.ProcessPlayerCommand(matchedCommand.Command, matchedCommand.Matches[0], Command.Actor);
         }
         else
         {
             Core.SendMessage(Command.Actor, "I do not understand.");
         }
     }
     catch (Exception e)
     {
         Core.DiscardPendingMessages();
         Core.SendMessage(Command.Actor, e.Message);
     }
 }
Пример #8
0
 public static void EnqueuActorCommand(PendingCommand Command)
 {
     PendingCommandLock.WaitOne();
     PendingCommands.AddLast(Command);
     PendingCommandLock.ReleaseMutex();
 }
Пример #9
0
        private static void ProcessThreadedCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) == StartupFlags.SingleThreaded)
            {
                throw new InvalidOperationException("ProcessThreadedCommands should never be called in single threaded mode.");
            }

            IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
            IndividualCommandThread.Start();

            while (!ShuttingDown)
            {
                System.Threading.Thread.Sleep(10);
                DatabaseLock.WaitOne();
                Heartbeat();
                DatabaseLock.ReleaseMutex();

                while (PendingCommands.Count > 0 && !ShuttingDown)
                {
                    PendingCommand PendingCommand = null;

                    PendingCommandLock.WaitOne();

                    try
                    {
                        PendingCommand = PendingCommands.FirstOrDefault(pc =>
                        {
                            return(true);
                            //if (pc.Actor.ConnectedClient == null) return true;
                            //else return (DateTime.Now - pc.Actor.ConnectedClient.TimeOfLastCommand).TotalMilliseconds > SettingsObject.AllowedCommandRate;
                        });
                        if (PendingCommand != null)
                        {
                            PendingCommands.Remove(PendingCommand);
                        }
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        PendingCommand = null;
                    }

                    PendingCommandLock.ReleaseMutex();

                    if (PendingCommand != null)
                    {
                        DatabaseLock.WaitOne();

                        NextCommand = PendingCommand;

                        //Reset flags that the last command may have changed
                        CommandTimeoutEnabled = true;
                        SilentFlag            = false;
                        GlobalRules.LogRules(null);

                        CommandReadyHandle.Set(); //Signal worker thread to proceed.
                        if (!CommandFinishedHandle.WaitOne(SettingsObject.CommandTimeOut))
                        {
                            if (!CommandTimeoutEnabled) //Timeout is disabled, go ahead and wait for infinity.
                            {
                                CommandFinishedHandle.WaitOne();
                            }
                            else
                            {
                                //Kill the command processor thread.
                                IndividualCommandThread.Abort();
                                ClearPendingMessages();
                                if (PendingCommand.Actor.ConnectedClient != null)
                                {
                                    PendingCommand.Actor.ConnectedClient.Send("Command timeout.\r\n");
                                    LogError(String.Format("Command timeout. {0} - {1}", PendingCommand.Actor.ConnectedClient.ConnectionDescription, PendingCommand.RawCommand));
                                }
                                else
                                {
                                    LogError(String.Format("Command timeout [No client] - {1}", PendingCommand.RawCommand));
                                }
                                IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
                                IndividualCommandThread.Start();
                            }
                        }

                        if (PendingCommand.ProcessingCompleteCallback != null)
                        {
                            PendingCommand.ProcessingCompleteCallback();
                        }

                        DatabaseLock.ReleaseMutex();
                    }
                }
            }

            IndividualCommandThread.Abort();
            if (Core.OnShutDown != null)
            {
                Core.OnShutDown();
            }
        }
Пример #10
0
 public void HandleCommand(PendingCommand Command)
 {
     Command.Actor.CommandHandler = ParentHandler;
     AuthenticatingCommand(Command.Actor, UserName, Command.RawCommand);
 }
Пример #11
0
        public void HandleCommand(PendingCommand Command)
        {
            if (String.IsNullOrEmpty(Command.RawCommand))
            {
                return;
            }

            bool displayMatches = false;
            bool displayTime    = false;

            // Debug commands always start with '@'.
            if (Command.RawCommand[0] == '@')
            {
                if (Command.RawCommand.ToUpper().StartsWith("@MATCH "))
                {
                    // Display all matches of the player's input. Do not actually execute the command.
                    Command.RawCommand = Command.RawCommand.Substring("@MATCH ".Length);
                    displayMatches     = true;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@TIME "))
                {
                    // Time how long the command takes to match and execute.
                    Command.RawCommand = Command.RawCommand.Substring("@TIME ".Length);
                    displayTime        = true;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@DEBUG "))
                {
                    // Turn off the automatic command execution timeout while executing the command.
                    // Use this when testing a command in the debugger. Otherwise, the command processing thread might
                    // be aborted while you are debugging it.
                    Command.RawCommand = Command.RawCommand.Substring("@DEBUG ".Length);
                    if (Command.Actor.Rank < 500)
                    {
                        MudObject.SendMessage(Command.Actor, "You do not have sufficient rank to use the debug command.");
                        return;
                    }

                    // This will be reset by the command queue before the next command is parsed.
                    Core.CommandTimeoutEnabled = false;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@RULES "))
                {
                    // Display all the rules invoked while executing this command.
                    Command.RawCommand = Command.RawCommand.Substring("@RULES ".Length);
                    Core.GlobalRules.LogRules(Command.Actor);
                }
                else
                {
                    MudObject.SendMessage(Command.Actor, "I don't recognize that debugging command.");
                    return;
                }
            }

            var startTime = DateTime.Now;

            var matchedCommand = Core.DefaultParser.ParseCommand(Command);

            if (displayMatches)
            {
                var matchEndTime = DateTime.Now;

                if (matchedCommand == null)
                {
                    MudObject.SendMessage(Command.Actor, String.Format("Matched nothing in {0:n0} milliseconds.",
                                                                       (matchEndTime - startTime).TotalMilliseconds));
                }
                else
                {
                    MudObject.SendMessage(Command.Actor, String.Format("Matched {0} in {1:n0} milliseconds. {2} unique matches.",
                                                                       matchedCommand.Command.ManualName,
                                                                       (matchEndTime - startTime).TotalMilliseconds,
                                                                       matchedCommand.Matches.Count));
                    foreach (var match in matchedCommand.Matches)
                    {
                        var builder = new StringBuilder();

                        foreach (var arg in match)
                        {
                            builder.Append("[");
                            builder.Append(arg.Key);
                            builder.Append(" : ");
                            builder.Append(arg.Value.ToString());
                            builder.Append("] ");
                        }

                        MudObject.SendMessage(Command.Actor, builder.ToString());
                    }
                }
            }
            else
            {
                if (matchedCommand != null)
                {
                    // If there are multiple matches, replace this handler with a disambiguation handler.
                    if (matchedCommand.Matches.Count > 1)
                    {
                        Command.Actor.CommandHandler = new DisambigCommandHandler(Command.Actor, matchedCommand, this);
                    }
                    else
                    {
                        Core.ProcessPlayerCommand(matchedCommand.Command, matchedCommand.Matches[0], Command.Actor);
                    }
                }
                else
                {
                    MudObject.SendMessage(Command.Actor, "huh?");
                }
            }

            Core.GlobalRules.LogRules(null);

            if (displayTime)
            {
                var endTime = DateTime.Now;

                MudObject.SendMessage(Command.Actor, String.Format("Command completed in {0} milliseconds.", (endTime - startTime).TotalMilliseconds));
            }
        }
Пример #12
0
 public static void EnqueuActorCommand(PendingCommand Command)
 {
     PendingCommandLock.WaitOne();
     PendingCommands.AddLast(Command);
     PendingCommandLock.ReleaseMutex();
 }
Пример #13
0
        private static void ProcessThreadedCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) == StartupFlags.SingleThreaded)
                throw new InvalidOperationException("ProcessThreadedCommands should never be called in single threaded mode.");

            IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
            IndividualCommandThread.Start();

            while (!ShuttingDown)
            {
                System.Threading.Thread.Sleep(10);
                DatabaseLock.WaitOne();
                Heartbeat();
                DatabaseLock.ReleaseMutex();

                while (PendingCommands.Count > 0 && !ShuttingDown)
                {
                    PendingCommand PendingCommand = null;

                    PendingCommandLock.WaitOne();

                    try
                    {
                        PendingCommand = PendingCommands.FirstOrDefault(pc =>
                            {
                                return true;
                                //if (pc.Actor.ConnectedClient == null) return true;
                                //else return (DateTime.Now - pc.Actor.ConnectedClient.TimeOfLastCommand).TotalMilliseconds > SettingsObject.AllowedCommandRate;
                            });
                        if (PendingCommand != null)
                            PendingCommands.Remove(PendingCommand);
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        PendingCommand = null;
                    }

                    PendingCommandLock.ReleaseMutex();

                    if (PendingCommand != null)
                    {
                        DatabaseLock.WaitOne();

                        NextCommand = PendingCommand;

                        //Reset flags that the last command may have changed
                        CommandTimeoutEnabled = true;
                        SilentFlag = false;
                        GlobalRules.LogRules(null);

                        CommandReadyHandle.Set(); //Signal worker thread to proceed.
                        if (!CommandFinishedHandle.WaitOne(SettingsObject.CommandTimeOut))
                        {
                            if (!CommandTimeoutEnabled) //Timeout is disabled, go ahead and wait for infinity.
                                CommandFinishedHandle.WaitOne();
                            else
                            {
                                //Kill the command processor thread.
                                IndividualCommandThread.Abort();
                                ClearPendingMessages();
                                if (PendingCommand.Actor.ConnectedClient != null)
                                {
                                    PendingCommand.Actor.ConnectedClient.Send("Command timeout.\r\n");
                                    LogError(String.Format("Command timeout. {0} - {1}", PendingCommand.Actor.ConnectedClient.ConnectionDescription, PendingCommand.RawCommand));
                                }
                                else
                                    LogError(String.Format("Command timeout [No client] - {1}", PendingCommand.RawCommand));
                                IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
                                IndividualCommandThread.Start();
                            }
                        }

                        if (PendingCommand.ProcessingCompleteCallback != null)
                            PendingCommand.ProcessingCompleteCallback();

                        DatabaseLock.ReleaseMutex();
                    }
                }
            }

            IndividualCommandThread.Abort();
            if (Core.OnShutDown != null) Core.OnShutDown();
        }
Пример #14
0
        public MatchedCommand ParseCommand(PendingCommand Command)
        {
            var tokens = new LinkedList <String>(Command.RawCommand.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));

            var rootMatch = new PossibleMatch(tokens.First);

            rootMatch.Upsert("ACTOR", Command.Actor);
            rootMatch.Upsert("LOCATION", Command.Actor == null ? null : Command.Actor.Location);

            // A pending command can have some properties set when it is queued. For example, the 'go' action
            // generates a 'look' command after processing. It will give the 'look' command a property named
            // 'auto' to indicate that the look command was generated. Rules can then use this property to
            // implement behavior. From the same example, 'look' may emit a brief description if it is generated
            // by the 'go' action, but emit a more detailed description if the player enters the command 'look'.
            //      See StandardActions.Go
            if (Command.PreSettings != null)
            {
                foreach (var setting in Command.PreSettings)
                {
                    rootMatch.Upsert(setting.Key.ToUpper(), setting.Value);
                }
            }

            var matchContext = new MatchContext {
                ExecutingActor = Command.Actor
            };

            // Try every single command defined, until one matches.
            foreach (var command in Commands)
            {
                IEnumerable <PossibleMatch> matches;

                try
                {
                    matches = command.Matcher.Match(rootMatch, matchContext);
                }
                catch (MatchAborted ma)
                {
                    // The match didn't fail; it generated an error. These means the match progressed to a point
                    // where the author of the command felt that the input could not logically match any other
                    // command, however, the input was still malformed in some way. Abort matching, and dummy up
                    // a command entry to display the error message to the player.
                    return(new MatchedCommand(
                               new CommandEntry().ProceduralRule((match, actor) =>
                    {
                        MudObject.SendMessage(actor, ma.Message);
                        return PerformResult.Continue;
                    }),
                               // We need a fake match just so it can be passed to the procedural rule.
                               new PossibleMatch[] { new PossibleMatch(null) }));
                }

                // Only accept matches that consumed all of the input.
                matches = matches.Where(m => m.Next == null);

                // If we did consume all of the input, we will assume this match is successful. Note it is
                // possible for a command to generate multiple matches, but not possible to match multiple commands.
                if (matches.Count() > 0)
                {
                    return(new MatchedCommand(command, matches));
                }
            }
            return(null);
        }
Пример #15
0
 public void HandleCommand(PendingCommand Command)
 {
     Command.Actor.SetProperty("command handler", ParentHandler);
     AuthenticatingCommand(Command.Actor, UserName, Command.RawCommand);
 }
Пример #16
0
        public void HandleCommand(PendingCommand Command)
        {
            if (String.IsNullOrEmpty(Command.RawCommand)) return;

            bool displayMatches = false;
            bool displayTime = false;

            // Debug commands always start with '@'.
            if (Command.RawCommand[0] == '@')
            {
                if (Command.RawCommand.ToUpper().StartsWith("@MATCH "))
                {
                    // Display all matches of the player's input. Do not actually execute the command.
                    Command.RawCommand = Command.RawCommand.Substring("@MATCH ".Length);
                    displayMatches = true;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@TIME "))
                {
                    // Time how long the command takes to match and execute.
                    Command.RawCommand = Command.RawCommand.Substring("@TIME ".Length);
                    displayTime = true;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@DEBUG "))
                {
                    // Turn off the automatic command execution timeout while executing the command.
                    // Use this when testing a command in the debugger. Otherwise, the command processing thread might
                    // be aborted while you are debugging it.
                    Command.RawCommand = Command.RawCommand.Substring("@DEBUG ".Length);
                    if (Command.Actor.Rank < 500)
                    {
                        MudObject.SendMessage(Command.Actor, "You do not have sufficient rank to use the debug command.");
                        return;
                    }

                    // This will be reset by the command queue before the next command is parsed.
                    Core.CommandTimeoutEnabled = false;
                }
                else if (Command.RawCommand.ToUpper().StartsWith("@RULES "))
                {
                    // Display all the rules invoked while executing this command.
                    Command.RawCommand = Command.RawCommand.Substring("@RULES ".Length);
                    Core.GlobalRules.LogRules(Command.Actor);
                }
                else
                {
                    MudObject.SendMessage(Command.Actor, "I don't recognize that debugging command.");
                    return;
                }
            }

            var startTime = DateTime.Now;

            var matchedCommand = Core.DefaultParser.ParseCommand(Command);

            if (displayMatches)
            {
                var matchEndTime = DateTime.Now;

                if (matchedCommand == null)
                {
                    MudObject.SendMessage(Command.Actor, String.Format("Matched nothing in {0:n0} milliseconds.",
                        (matchEndTime - startTime).TotalMilliseconds));
                }
                else
                {
                    MudObject.SendMessage(Command.Actor, String.Format("Matched {0} in {1:n0} milliseconds. {2} unique matches.",
                        matchedCommand.Command.ManualName,
                        (matchEndTime - startTime).TotalMilliseconds,
                        matchedCommand.Matches.Count));
                    foreach (var match in matchedCommand.Matches)
                    {
                        var builder = new StringBuilder();

                        foreach (var arg in match)
                        {
                            builder.Append("[");
                            builder.Append(arg.Key);
                            builder.Append(" : ");
                            builder.Append(arg.Value.ToString());
                            builder.Append("] ");
                        }

                        MudObject.SendMessage(Command.Actor, builder.ToString());
                    }
                }
            }
            else
            {

                if (matchedCommand != null)
                {
                    // If there are multiple matches, replace this handler with a disambiguation handler.
                    if (matchedCommand.Matches.Count > 1)
                        Command.Actor.CommandHandler = new DisambigCommandHandler(Command.Actor, matchedCommand, this);
                    else
                        Core.ProcessPlayerCommand(matchedCommand.Command, matchedCommand.Matches[0], Command.Actor);
                }
                else
                    MudObject.SendMessage(Command.Actor, "huh?");
            }

            Core.GlobalRules.LogRules(null);

            if (displayTime)
            {
                var endTime = DateTime.Now;

                MudObject.SendMessage(Command.Actor, String.Format("Command completed in {0} milliseconds.", (endTime - startTime).TotalMilliseconds));
            }
        }
Пример #17
0
        public MatchedCommand ParseCommand(PendingCommand Command)
        {
            var tokens = new LinkedList <String>(Command.RawCommand.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));

            var rootMatch = new PossibleMatch(tokens.First);

            rootMatch.Upsert("ACTOR", Command.Actor);
            rootMatch.Upsert("LOCATION", Command.Actor == null ? null : Command.Actor.Location);

            // A pending command can have some properties set when it is queued. For example, the 'go' action
            // generates a 'look' command after processing. It will give the 'look' command a property named
            // 'auto' to indicate that the look command was generated. Rules can then use this property to
            // implement behavior. From the same example, 'look' may emit a brief description if it is generated
            // by the 'go' action, but emit a more detailed description if the player enters the command 'look'.
            //      See StandardActions.Go
            if (Command.PreSettings != null)
            {
                foreach (var setting in Command.PreSettings)
                {
                    rootMatch.Upsert(setting.Key.ToUpper(), setting.Value);
                }
            }

            var matchContext = new MatchContext {
                ExecutingActor = Command.Actor
            };

            // Try every single command defined, until one matches.
            foreach (var command in Commands)
            {
                IEnumerable <PossibleMatch> matches;
                matchContext.CurrentParseCommand = command;

                try
                {
                    matches = command.Matcher.Match(rootMatch, matchContext);
                }
                catch (MatchAborted ma)
                {
                    // The match didn't fail; it generated an error. This usually represents an oversite in the command's grammar.
                    // Abort matching, and dummy up a command entry to display the error message to the player.
                    return(new MatchedCommand(
                               new CommandEntry().ProceduralRule((match, actor) =>
                    {
                        Core.SendMessage(actor, ma.Message);
                        return PerformResult.Continue;
                    }),
                               // We need a fake match just so it can be passed to the procedural rule.
                               new PossibleMatch[] { new PossibleMatch(null) }));
                }

                // Only accept matches that consumed all of the input as valid, successful matches.
                matches = matches.Where(m => m.Next == null);

                // If we did consume all of the input, we will assume this match is successful. Note it is
                // possible for a command to generate multiple matches, but not possible to match multiple commands.
                if (matches.Count() > 0)
                {
                    return(new MatchedCommand(command, matches));
                }
            }

            // No command matched; lets return a dummy command that display's the huh? text.
            return(new MatchedCommand(
                       new CommandEntry()
                       .ProceduralRule((match, actor) =>
            {
                // Todo: Expand match arguments into error message.
                if (matchContext.BestFailedCommand != null && matchContext.BestFailedMatch.ParseDepth > 0)
                {
                    Core.SendMessage(actor, "That's the name of a command, but I couldn't figure out what you meant.");
                    Core.SendMessage(actor, "The best failed match was " + matchContext.BestFailedCommand.ManualName + ", which reached a depth of " + matchContext.BestFailedMatch.ParseDepth);
                    if (!String.IsNullOrEmpty(matchContext.BestFailedParseStageDescription))
                    {
                        Core.SendMessage(actor, Core.FormatParserMessage(actor, matchContext.BestFailedParseStageDescription, matchContext.BestFailedMatch));
                    }
                }
                else
                {
                    Core.SendMessage(actor, "I don't think that is a command I know. I could not parse any of it.");
                }

                return PerformResult.Continue;
            }),
                       new PossibleMatch[] { new PossibleMatch(null) }
                       ));
        }
Пример #18
0
        public void HandleCommand(PendingCommand Command)
        {
            Command.Actor.CommandHandler = ParentHandler;

            //Just retry if the attempt to help has failed.
            if (DisambigObjects == null)
            {
                Core.EnqueuActorCommand(Command);
                return;
            }

            int ordinal = 0;
            if (Int32.TryParse(Command.RawCommand, out ordinal))
            {
                if (ordinal < 0 || ordinal >= DisambigObjects.Count)
                    MudObject.SendMessage(Command.Actor, "That wasn't a valid option. I'm aborting disambiguation.");
                else
                {
                    var choosenMatches = MatchedCommand.Matches.Where(m => Object.ReferenceEquals(m[DisambigArgument], DisambigObjects[ordinal]));
                    MatchedCommand.Matches = new List<PossibleMatch>(choosenMatches);

                    if (MatchedCommand.Matches.Count == 1)
                        Core.ProcessPlayerCommand(MatchedCommand.Command, MatchedCommand.Matches[0], Command.Actor);
                    else
                    {
                        // WHat? There are still multiple options?
                        MudObject.SendMessage(Command.Actor, "That helped narrow it down, but I'm still not sure what you mean.");
                        Command.Actor.CommandHandler = new DisambigCommandHandler(Command.Actor, MatchedCommand, ParentHandler);
                    }
                }
            }
            else
            {
                // The input was nor an ordial. Go ahead and requeue the command so the normal command handler
                // can take care of it.
                Core.EnqueuActorCommand(Command);
            }
        }
Пример #19
0
        private static void ProcessCommandsWorkerThread()
        {
            while (!ShuttingDown)
            {
                CommandReadyHandle.WaitOne();

                try
                {
                    //if (NextCommand.Actor.ConnectedClient != null)
                    //    NextCommand.Actor.ConnectedClient.TimeOfLastCommand = DateTime.Now;
                    NextCommand.Actor.CommandHandler.HandleCommand(NextCommand);
                }
                catch (System.Threading.ThreadAbortException)
                {
                    LogError("Command worker thread was aborted. Timeout hit?");
                    Core.ClearPendingMessages();
                }
                catch (Exception e)
                {
                    LogCommandError(e);
                    Core.ClearPendingMessages();
                }

                NextCommand = null;

                CommandFinishedHandle.Set();
            }
        }