예제 #1
0
        public static async Task <ICommandResult> Run(string commandMessage, ICommandContext context, string prefix, bool awaitResult)
        {
            var    args        = commandMessage.Trim().Substring(prefix.Length).Split(' ');
            string commandName = args[0];

            args = CommandTools.ParseArguments(string.Join(" ", args.Skip(1)));
            //MethodInfo command = GetCommand(commandName, args.Length);
            var commands = GetCommands(commandName);

            await DiscordBot.Log(context.LogMessage(commandName));

            List <object>  values       = null;
            ICommandResult error        = null;
            MethodInfo     commandToRun = null;

            foreach (var command in commands)
            {
                var parameters         = command.GetParameters();
                var requiredParameters = parameters.Where(param => !param.IsOptional).ToArray();

                Type contextType = context.GetType();
                if (!parameters[0].ParameterType.IsAssignableFrom(contextType))
                {
                    string message = $"That command is not valid in the context {context.GetType().Name}";
                    error = error ?? new ErrorResult(message, "Invalid Context");
                    continue;
                }

                if (args.Length < requiredParameters.Length - 1)
                {
                    string message = $"The syntax of the command was incorrect. The following parameters are required: `{string.Join("`, `", requiredParameters.Select(param => param.GetCustomAttribute<DisplayNameAttribute>()?.Name ?? param.Name).Skip(args.Length + 1))}`\nUse `{prefix}help {commandName}` for command info";
                    error = error ?? new ErrorResult(message, "Syntax Error");
                    continue;
                }

                if (context is DiscordMessageContext discordContext)
                {
                    if (!(command.GetCustomAttribute <CommandScopeAttribute>()?.ChannelTypes.Contains(discordContext.ChannelType) ?? true))
                    {
                        string message = $"The command `{prefix}{commandName}` is not valid in the scope {discordContext.ChannelType}";
                        error = error ?? new ErrorResult(message, "Scope Error");
                        continue;
                    }

                    string permissionError = command.GetCustomAttribute <PermissionsAttribute>()?.GetPermissionError(discordContext);
                    if (permissionError != null)
                    {
                        error = error ?? new ErrorResult(permissionError, "Permission Error");
                        continue;
                    }
                }

                values = new List <object>
                {
                    context
                };

                bool err = false;
                for (int i = 1; i < parameters.Length; i++)
                {
                    if (parameters[i].IsOptional && i > args.Length)
                    {
                        values.Add(Type.Missing);
                        continue;
                    }

                    if (i == parameters.Length - 1 && parameters[i].IsDefined(typeof(JoinRemainingParametersAttribute)))
                    {
                        if (parameters[i].ParameterType == typeof(string))
                        {
                            values.Add(string.Join(" ", args.Skip(i - 1)));
                        }
                        else if (parameters[i].ParameterType == typeof(string[]))
                        {
                            values.Add(args.Skip(i - 1).ToArray());
                        }
                        else
                        {
                            object converted = ConvertToType(parameters[i].ParameterType, string.Join(" ", args.Skip(i - 1)), context);
                            if (converted == null)
                            {
                                error = error ?? ThrowTypeError(context, string.Join(" ", args.Skip(i - 1)), parameters[i]);
                                err   = true;
                                break;
                            }
                            values.Add(converted);
                        }
                        break;
                    }

                    var result = ConvertToType(parameters[i].ParameterType, args[i - 1], context);
                    if (result == null)
                    {
                        error = error ?? ThrowTypeError(context, args[i - 1], parameters[i]);
                        err   = true;
                        break;
                    }

                    values.Add(result);
                }

                if (err)
                {
                    continue;
                }
                error        = null;
                commandToRun = command;
                break;
            }

            if (args.Length > 0 && context is DiscordMessageContext d && args[0] == "help" && commandName != "help")
            {
                var embed = new EmbedBuilder()
                            .WithDescription($"Did you mean `{prefix}help {commandName}`?")
                            .WithColor(new Color(0x2AC2E9))
                            .WithAuthor(author =>
                {
                    author
                    .WithName("Help")
                    .WithIconUrl("https://www.shareicon.net/data/128x128/2016/08/18/809295_info_512x512.png");
                });
                await d.Reply("", embed : embed.Build());
            }

            if (error != null)
            {
                await context.ReplyError(error.Message, ((ErrorResult)error).Title);

                return(error);
            }
            else
            {
                if (awaitResult)
                {
                    return(await RunCommand(context, commandToRun, values.ToArray()));
                }

#pragma warning disable 4014
                RunCommand(context, commandToRun, values.ToArray());
#pragma warning restore 4014
                return(new SuccessResult());
            }
        }