Exemplo n.º 1
0
        private Task CommandExecutionFailedAsync(CommandExecutionFailedEventArgs e)
        {
            if (e.Result.CommandExecutionStep == CommandExecutionStep.Command && e.Result.Exception is ContextTypeMismatchException contextTypeMismatchException)
            {
                var message = "A command context type mismatch occurred while attempting to execute {0}. " +
                              "The module expected {1}, but got {2}.";
                var args = new List <object>(5)
                {
                    e.Result.Command.Name,
                    contextTypeMismatchException.ExpectedType,
                    contextTypeMismatchException.ActualType
                };

                // If the expected type is a DiscordGuildCommandContext, the actual type is a DiscordCommandContext, and the module doesn't have guild restrictions.
                if (typeof(DiscordGuildCommandContext).IsAssignableFrom(contextTypeMismatchException.ExpectedType) &&
                    typeof(DiscordCommandContext).IsAssignableFrom(contextTypeMismatchException.ActualType) &&
                    !CommandUtilities.EnumerateAllChecks(e.Result.Command.Module).Any(x => x is RequireGuildAttribute))
                {
                    message += " Did you forget to decorate the module with {3}?";
                    args.Add(nameof(RequireGuildAttribute));
                }

                // If the expected type is a custom made context.
                if (contextTypeMismatchException.ExpectedType != typeof(DiscordGuildCommandContext) &&
                    contextTypeMismatchException.ExpectedType != typeof(DiscordCommandContext))
                {
                    message += " If you have not overridden {4}, you must do so and have it return the given context type. " +
                               "Otherwise ensure it returns the correct context types.";
                    args.Add(nameof(CreateCommandContext));
                }

                Logger.LogError(message, args.ToArray());
            }
            else
            {
                if (e.Result.Exception is OperationCanceledException && StoppingToken.IsCancellationRequested)
                {
                    // Means the bot is stopping and any exceptions caused by cancellation we can ignore.
                    return(Task.CompletedTask);
                }

                Logger.LogError(e.Result.Exception, e.Result.FailureReason);
            }

            if (e.Context is not DiscordCommandContext context)
            {
                return(Task.CompletedTask);
            }

            _ = InternalHandleFailedResultAsync(context, e.Result);
            return(Task.CompletedTask);
        }
Exemplo n.º 2
0
        public Task HelpAsync([Remainder, Description("Command or module.")] string command)
        {
            if (string.IsNullOrWhiteSpace(command))
            {
                return(HelpAsync());
            }

            var matchingCommands = _commands.FindCommands(command);

            if (matchingCommands.Count == 0)
            {
                string typoFix = command.Levenshtein(_commands);
                if (!string.IsNullOrWhiteSpace(typoFix))
                {
                    matchingCommands = _commands.FindCommands(typoFix);
                }
            }

            LocalEmbedBuilder embed;

            if (matchingCommands.Count == 0) //Could be a module.
            {
                var matchingModule = _commands.TopLevelModules.FirstOrDefault(x => x.Name.Equals(command, StringComparison.OrdinalIgnoreCase));
                if (matchingModule is null)
                {
                    matchingModule = _commands.TopLevelModules.FirstOrDefault(x => x.Name.Equals(command.Levenshtein(_commands), StringComparison.OrdinalIgnoreCase));
                }

                var modules = _commands.GetAllModules();
                if (matchingModule is null) //Look for nested modules
                {
                    matchingModule = modules.FirstOrDefault(x => x.FullAliases.Any(y => y.Equals(command, StringComparison.OrdinalIgnoreCase)));
                }

                if (matchingModule is null) //Look for nested modules with levenshtein
                {
                    matchingModule = modules.FirstOrDefault(x => x.FullAliases.Any(y => y.Equals(command.Levenshtein(modules.Select(z => z.FullAliases.FirstOrDefault()).ToList()), StringComparison.OrdinalIgnoreCase)));
                }

                if (matchingModule is null) //Look for submodule but without complete module path
                {
                    matchingModule = modules.FirstOrDefault(x => x.Name.Equals(command, StringComparison.OrdinalIgnoreCase));
                }

                if (matchingModule is null) //Look for submodule but without complete module path with levenshtein
                {
                    matchingModule = modules.FirstOrDefault(x => x.Name.Equals(command.Levenshtein(modules.Select(z => z.Name).ToList()), StringComparison.OrdinalIgnoreCase));
                }

                if (matchingModule is null) //Remove last input
                {
                    var cmdArgs = command.Split(' ').ToList();
                    cmdArgs.RemoveAt(cmdArgs.Count - 1);

                    return(HelpAsync(string.Join(' ', cmdArgs)));
                }

                embed = new LocalEmbedBuilder
                {
                    Title       = $"Help - {matchingModule.Name} Module",
                    Description = "This embed contains the list of every command in this module.",
                    Footer      = new LocalEmbedFooterBuilder
                    {
                        Text = $"{matchingModule.Commands.Count} commands available in this context."
                    }
                };

                if (matchingModule.Submodules.Count > 0)
                {
                    embed.AddField("Modules", string.Join(", ", matchingModule.Submodules.DistinctBy(x => x.Name).Select(x => $"`{x.Name}`")));
                }

                if (matchingModule.Commands.Count > 0)
                {
                    embed.AddField("Commands", string.Join(", ", matchingModule.Commands.DistinctBy(x => x.Name).Select(x => $"`{x.Name}`")));
                }

                var moduleChecks = CommandUtilities.EnumerateAllChecks(matchingModule).Cast <AbfCheckBaseAttribute>().ToArray();
                if (moduleChecks.Length > 0)
                {
                    embed.AddField("Requirements", string.Join("\n", moduleChecks.Select(x => $"`- {x.Name}{x.Details}`")));
                }

                return(ReplyAsync(embed: embed.Build()));
            }

            embed = new LocalEmbedBuilder
            {
                Title = "Help"
            };

            var builder = new StringBuilder();

            foreach (var cmd in matchingCommands.Where(c => c.Command.Attributes.All(a => !(a is HiddenAttribute))))
            {
                builder.AppendLine($"**{cmd.Command.Description ?? "Undocumented."}**");
                builder.AppendLine(($"`{Context.Prefix}{cmd.Command.Name} {string.Join(" ", cmd.Command.Parameters.Select(GetUsage(cmd.Command)))}`".ToLowerInvariant()).TrimEnd());
                foreach (var param in cmd.Command.Parameters)
                {
                    builder.AppendLine($"`[{param.Name}]`: {param.Description ?? "Undocumented."}");
                }
                builder.AppendLine($"\n**Example:** `{cmd.Command.Remarks ?? "No example provided."}`\n");
            }

            embed.AddField("Usages", builder.ToString());

            var defaultCmd = matchingCommands.First().Command;

            var checks = CommandUtilities.EnumerateAllChecks(defaultCmd.Module).Cast <AbfCheckBaseAttribute>().ToArray();

            if (checks.Length > 0)
            {
                embed.AddField("Module Requirements", string.Join("\n", checks.Select(x => $"- `{x.Name}{x.Details}`")));
            }

            if (defaultCmd.Checks.Count > 0)
            {
                embed.AddField("Command Requirements", string.Join("\n", defaultCmd.Checks.Cast <AbfCheckBaseAttribute>().Select(x => $"- `{x.Name}{x.Details}`")));
            }

            return(ReplyAsync(embed: embed.Build()));
        }
Exemplo n.º 3
0
        public static async ValueTask <EmbedBuilder> CreateCommandEmbedAsync(Command command, VolteContext ctx)
        {
            var embed = ctx.CreateEmbedBuilder()
                        .WithTitle(command.Name)
                        .WithDescription(command.Description ?? "No description provided.");
            var checks = CommandUtilities.EnumerateAllChecks(command).ToList();

            async Task AddSubcommandsFieldAsync()
            {
                embed.AddField("Subcommands", (await command.Module.Commands.WhereAccessibleAsync(ctx)
                                               .Where(x => !x.Attributes.Any(a => a is DummyCommandAttribute)).ToListAsync())
                               .Select(x => FormatCommandShort(x, false))
                               .Join(", "));
            }

            if (command.Attributes.Any(x => x is DummyCommandAttribute))
            {
                await AddSubcommandsFieldAsync();

                return(!checks.IsEmpty()
                    ? embed.AddField("Checks",
                                     (await Task.WhenAll(checks.Select(check => FormatCheckAsync(check, ctx)))).Join("\n"))
                    : embed);
            }

            if (command.Remarks != null)
            {
                embed.AppendDescription($" {command.Remarks}");
            }

            if (!command.FullAliases.IsEmpty())
            {
                embed.AddField("Aliases", command.FullAliases.Select(x => Format.Code(x)).Join(", "), true);
            }

            if (!command.Parameters.IsEmpty())
            {
                embed.AddField("Parameters", command.Parameters.Select(FormatParameter).Join("\n"));
            }

            if (command.CustomArgumentParserType is null)
            {
                embed.AddField("Usage", FormatUsage(ctx, command));
            }

            if (command.Attributes.Any(x => x is ShowPlaceholdersInHelpAttribute))
            {
                embed.AddField("Placeholders",
                               WelcomeOptions.ValidPlaceholders
                               .Select(x => $"{Format.Code($"{{{x.Key}}}")}: {Format.Italics(x.Value)}")
                               .Join("\n"));
            }

            if (command.Attributes.Any(x => x is ShowTimeFormatInHelpAttribute))
            {
                embed.AddField("Example Valid Time",
                               $"{Format.Code("4d3h2m1s")}: {Format.Italics("4 days, 3 hours, 2 minutes and one second.")}");
            }

            if (command.Attributes.Any(x => x is ShowSubcommandsInHelpOverrideAttribute))
            {
                await AddSubcommandsFieldAsync();
            }

            if (command.Attributes.AnyGet(x => x is ShowUnixArgumentsInHelpAttribute, out var unixAttr) &&
                unixAttr is ShowUnixArgumentsInHelpAttribute attr)
            {