Exemple #1
0
        /// <summary>Creates a scripting command from action input.</summary>
        /// <param name="actionInput">The action input to transform into a ScriptingCommand instance.</param>
        /// <returns>A new ScriptingCommand instance for the specified input, if found, else null.</returns>
        public ScriptingCommand Create(ActionInput actionInput)
        {
            // TODO: Build targeting into command selection when there are multiple valid targets; IE if multiple
            //     openable things registered an "open" context command, then if the user said "open door" then we
            //     want to select the context command attached to the closest match for "door" as our command; if
            //     there are still multiple targets, we can start a conflict resolution prompt, etc.  Individual non-
            //     context commands may also wish to use such targeting code, so it should be built to be reusable.
            ScriptingCommand command = TryCreateMasterCommand(actionInput, 0) ??
                                       TryCreateMasterCommand(actionInput, 1) ??
                                       TryCreateContextCommand(actionInput, 0) ??
                                       TryCreateContextCommand(actionInput, 1);

            if (command == null)
            {
                actionInput.Controller.Write(new OutputBuilder().AppendLine(unknownCommandResponse));
            }

            return(command);
        }
Exemple #2
0
        /// <summary>Try to execute the specified action input as a command.</summary>
        /// <param name="actionInput">The action input to try to execute.</param>
        private void TryExecuteAction(ActionInput actionInput)
        {
            try
            {
                ScriptingCommand command = CommandCreator.Instance.Create(actionInput);
                if (command == null)
                {
                    return;
                }

                // Verify the user has permissions to use this command.
                string guardsErrorMessage = CommandGuardHelpers.VerifyCommandPermission(command);
                if (guardsErrorMessage == null)
                {
                    guardsErrorMessage = (string)command.GuardsDelegate.DynamicInvoke(actionInput);
                }

                // Verify that the other command-specific guards are passed.
                if (guardsErrorMessage == null)
                {
                    // Execute the command if we passed all the guards.
                    command.ExecuteDelegate.DynamicInvoke(actionInput);
                }
                else
                {
                    // Otherwise display what went wrong to the user of the action.
                    IController controller = actionInput.Controller;
                    controller.Write(new OutputBuilder().AppendLine(guardsErrorMessage));
                }
            }
            catch (Exception ex)
            {
                // Most of our exceptions should be TargetInvocationExceptions but we're going to
                // handle them basically the same way as others, except that we only care about the
                // inner exception (what actually went wrong, since we know we're doing invokes here).
                if (ex is TargetInvocationException && ex.InnerException != null)
                {
                    ex = ex.InnerException;
                }

                // In order to isolate command-specific issues, we're going to trap the exception, log
                // the details, and kill that command.  (Other commands and the game itself should be
                // able to continue through such situations.)
                // Start gathering info, but carefully to avoid causing potential further exceptions here.
                IController controller = actionInput.Controller;
#if DEBUG
                Thing  thing     = controller != null ? controller.Thing : null;
                string thingName = thing != null ? thing.Name : "[null]";
                string thingID   = thing != null?thing.Id.ToString() : "[null]";

                string fullCommand = actionInput != null ? actionInput.FullText : "[null]";
                string format      = "Exception encountered for command: {1}{0}From thing: {2} (ID: {3}){0}{4}";
                string message     = string.Format(format, Environment.NewLine, fullCommand, thingName, thingID, ex.ToDeepString());
#endif

                // If the debugger is attached, we probably want to break now in order to better debug
                // the issue closer to where it occurred; if your debugger broke here you may want to
                // look at the stack trace to see where the exception originated.
                if (Debugger.IsAttached)
                {
                    string stackTrace = ex.StackTrace;
                    Debugger.Break();
                }

                // TODO: FIX: this.host..UpdateSubSystemHost(this, message);
                if (controller != null)
                {
#if DEBUG
                    controller.Write(new OutputBuilder().AppendLine(message));
#else
                    controller.Write(new OutputBuilder().AppendLine("An error occured processing your command."));
#endif
                }
            }
        }
Exemple #3
0
        /// <summary>Verifies that the proposed command can be performed by the acting entity.</summary>
        /// <param name="command">The issued command to be carried out.</param>
        /// <returns>A string defining why the permission was not given, else null if permission is given.</returns>
        public static string VerifyCommandPermission(ScriptingCommand command)
        {
            if (command.SecurityRole == SecurityRole.none)
            {
                // If you are debugging here after trying to set up your own action,
                // you probably forgot to assign an appropriate [ActionSecurity(...)]
                // attribute for your new GameAction class.
                return string.Format("Nobody can use '{0}' right now!", command.Name);
            }

            Thing entity = command.ActionInput.Controller.Thing;
            if (entity == null)
            {
                return "You must exist before issuing commands!";
            }

            PlayerBehavior player = entity.Behaviors.FindFirst<PlayerBehavior>();
            if (player != null)
            {
                // @@@ TODO: Ascertain the ACTUAL player's specific permissions, so we can
                //     check for fullAdmin, fullBuilder, etc, instead of assuming just
                //     'SecurityRole.player'
                SecurityRole playerRoles = SecurityRole.player | SecurityRole.minorBuilder |
                        SecurityRole.fullBuilder | SecurityRole.minorAdmin | SecurityRole.fullAdmin;

                // If any of the command's security roles and the player's security roles
                // overlap (such as the command is marked with 'minorBuilder' and the
                // player has the 'minorBuilder' flag) then we permit the command.
                if ((command.SecurityRole & playerRoles) != SecurityRole.none)
                {
                    return null;
                }

                // Otherwise, this player does not have permission; we do not want to
                // check the mobile/item/room security role on players, so we're done.
                return string.Format("You do not have permission to use '{0}' right now.", command.Name);
            }

            MobileBehavior mobile = entity.Behaviors.FindFirst<MobileBehavior>();
            if (mobile != null)
            {
                if ((command.SecurityRole & SecurityRole.mobile) != SecurityRole.none)
                {
                    return null;
                }

                return string.Format("A mobile can not use '{0}' right now!", command.Name);
            }

            RoomBehavior room = entity.Behaviors.FindFirst<RoomBehavior>();
            if (room != null)
            {
                if ((command.SecurityRole & SecurityRole.room) == SecurityRole.none)
                {
                    return null;
                }

                return string.Format("A room can not use '{0}' right now!", command.Name);
            }

            // @@@ For now, everything else which doesn't meet any above category will need the 'item' security
            //     role. (Do we need an ItemBehavior or is there something else relevant... CanPickupBehavior etc?)
            if ((command.SecurityRole & SecurityRole.item) != SecurityRole.none)
            {
                return null;
            }

            return string.Format("An item (or unrecognized entity) can not use '{0}' right now!", command.Name);
        }
        /// <summary>Try to execute the specified action input as a command.</summary>
        /// <param name="actionInput">The action input to try to execute.</param>
        private void TryExecuteAction(ActionInput actionInput)
        {
            Debug.Assert(actionInput != null, "actionInput must be defined.");
            try
            {
                ScriptingCommand command = CommandCreator.Instance.Create(actionInput);
                if (command == null)
                {
                    return;
                }

                // Verify the user has permissions to use this command.
                string guardsErrorMessage = CommandGuardHelpers.VerifyCommandPermission(command);
                if (guardsErrorMessage == null)
                {
                    guardsErrorMessage = (string)command.GuardsDelegate.DynamicInvoke(actionInput);
                }

                // Verify that the other command-specific guards are passed.
                if (guardsErrorMessage == null)
                {
                    // Execute the command if we passed all the guards.
                    command.ExecuteDelegate.DynamicInvoke(actionInput);
                }
                else
                {
                    // Otherwise display what went wrong to the issuing session of this action input.
                    // (If there is no such session, such as an AI issuing a malformed action, for now this is just ignored. TODO: Send this issue to server log?)
                    actionInput.Session?.WriteLine(guardsErrorMessage);
                }
            }
            catch (Exception ex)
            {
                // Most of our exceptions should be TargetInvocationExceptions but we're going to
                // handle them basically the same way as others, except that we only care about the
                // inner exception (what actually went wrong, since we know we're doing invokes here).
                if (ex is TargetInvocationException && ex.InnerException != null)
                {
                    ex = ex.InnerException;
                }

                // In order to isolate command-specific issues, we're going to trap the exception, log
                // the details, and kill that command.  (Other commands and the game itself should be
                // able to continue through such situations.)
                // Start gathering info, but carefully to avoid causing potential further exceptions here.
#if DEBUG
                // TODO: Improve action error output to always provide full details to server log and admin players.
                //       https://github.com/DavidRieman/WheelMUD/issues/136
                string thingName   = actionInput.Actor?.Name ?? "[null]";
                string thingID     = actionInput.Actor?.Id.ToString() ?? "[null]";
                string fullCommand = actionInput.FullText ?? "[null]";
                string format      = "Exception encountered for command: {1}{0}From thing: {2} (ID: {3}){0}{4}";
                string message     = string.Format(format, Environment.NewLine, fullCommand, thingName, thingID, ex.ToDeepString());
#else
                string message = "An error occurred while processing your command.";
#endif
                actionInput.Session?.WriteLine(message);

                // If the debugger is attached, we probably want to break now in order to better debug
                // the issue closer to where it occurred; if your debugger broke here you may want to
                // look at the stack trace to see where the exception originated.
                if (Debugger.IsAttached)
                {
                    string stackTrace = ex.StackTrace;
                    Debugger.Break();
                }
            }
        }