/// <summary> Parses and calls a specified command. </summary>
        /// <param name="player"> Player who issued the command. </param>
        /// <param name="cmd"> Command to be parsed and executed. </param>
        /// <param name="fromConsole"> Whether this command is being called from a non-player (e.g. Console). </param>
        /// <returns> True if the command was called, false if something prevented it from being called. </returns>
        public static bool ParseCommand([NotNull] Player player, [NotNull] Command cmd, bool fromConsole)
        {
            if (player == null)
            {
                throw new ArgumentNullException("player");
            }
            if (cmd == null)
            {
                throw new ArgumentNullException("cmd");
            }
            CommandDescriptor descriptor = GetDescriptor(cmd.Name, true);

            if (descriptor == null)
            {
                player.Message("Unknown command \"{0}\". See &H/Commands", cmd.Name);
                return(false);
            }

            if (!descriptor.IsConsoleSafe && fromConsole)
            {
                player.Message("You cannot use this command from console.");
            }
            else
            {
                if (descriptor.Permissions != null)
                {
                    if (!descriptor.CanBeCalledBy(player.Info.Rank, fromConsole))
                    {
                        player.MessageNoAccess(descriptor);
                    }
                    else if (!descriptor.Call(player, cmd, true))
                    {
                        player.Message("Command was cancelled.");
                    }
                    else
                    {
                        return(true);
                    }
                }
                else
                {
                    if (descriptor.Call(player, cmd, true))
                    {
                        return(true);
                    }
                    else
                    {
                        player.Message("Command was cancelled.");
                    }
                }
            }
            return(false);
        }
        internal static bool RaiseCommandCallingEvent(Command cmd, CommandDescriptor descriptor, Player player)
        {
            var h = CommandCalling;

            if (h == null)
            {
                return(false);
            }
            var e = new CommandCallingEventArgs(cmd, descriptor, player);

            h(null, e);
            return(e.Cancel);
        }
        static bool RaiseCommandRegisteringEvent(CommandDescriptor descriptor)
        {
            var h = CommandRegistering;

            if (h == null)
            {
                return(false);
            }
            var e = new CommandRegistringEventArgs(descriptor);

            h(null, e);
            return(e.Cancel);
        }
        internal static void RegisterCommand([NotNull] CommandDescriptor descriptor)
        {
            if (descriptor == null)
            {
                throw new ArgumentNullException("descriptor");
            }

#if DEBUG
            if (descriptor.Category == CommandCategory.None && !descriptor.IsCustom)
            {
                throw new CommandRegistrationException("Standard commands must have a category set.");
            }
#endif

            if (!IsValidCommandName(descriptor.Name))
            {
                throw new CommandRegistrationException("All commands need a name, between 1 and 16 alphanumeric characters long.");
            }

            string normalizedName = descriptor.Name.ToLower();

            if (Commands.ContainsKey(normalizedName))
            {
                throw new CommandRegistrationException("A command with the name \"{0}\" is already registered.", descriptor.Name);
            }

            if (ReservedCommandNames.Contains(normalizedName))
            {
                throw new CommandRegistrationException("The command name is reserved.");
            }

            if (descriptor.Handler == null)
            {
                throw new CommandRegistrationException("All command descriptors are required to provide a handler callback.");
            }

            if (descriptor.Aliases != null)
            {
                if (descriptor.Aliases.Any(alias => Commands.ContainsKey(alias)))
                {
                    throw new CommandRegistrationException("One of the aliases for \"{0}\" is using the name of an already-defined command.", descriptor.ToString());
                }
            }

            if (!Char.IsUpper(descriptor.Name[0]))
            {
                descriptor.Name = descriptor.Name.UppercaseFirst();
            }

            if (descriptor.Usage == null)
            {
                descriptor.Usage = "/" + descriptor.Name;
            }

            if (RaiseCommandRegisteringEvent(descriptor))
            {
                return;
            }

            if (Aliases.ContainsKey(normalizedName))
            {
                Logger.Log(LogType.Warning,
                           "CommandManager.RegisterCommand: \"{0}\" was defined as an alias for \"{1}\", " +
                           "but has now been replaced by a different command of the same name.",
                           descriptor.Name, Aliases[descriptor.Name]);
                Aliases.Remove(normalizedName);
            }

            if (descriptor.Aliases != null)
            {
                foreach (string alias in descriptor.Aliases)
                {
                    string normalizedAlias = alias.ToLower();
                    if (ReservedCommandNames.Contains(normalizedAlias))
                    {
                        Logger.Log(LogType.Warning,
                                   "CommandManager.RegisterCommand: Alias \"{0}\" for \"{1}\" ignored (reserved name).",
                                   alias, descriptor.Name);
                    }
                    else if (Aliases.ContainsKey(normalizedAlias))
                    {
                        Logger.Log(LogType.Warning,
                                   "CommandManager.RegisterCommand: \"{0}\" was defined as an alias for \"{1}\", " +
                                   "but has been overridden to resolve to \"{2}\" instead.",
                                   alias, Aliases[normalizedAlias], descriptor.Name);
                    }
                    else
                    {
                        Aliases.Add(normalizedAlias, normalizedName);
                    }
                }
            }

            Commands.Add(normalizedName, descriptor);

            RaiseCommandRegisteredEvent(descriptor);
        }
        private static void RaiseCommandRegisteredEvent(CommandDescriptor descriptor)
        {
            var h = CommandRegistered;

            h?.Invoke(null, new CommandRegisteredEventArgs(descriptor));
        }