/// <summary>
        /// Creates a new instance of a <see cref="DiscordApplicationCommandOption"/>.
        /// </summary>
        /// <param name="name">The name of this parameter.</param>
        /// <param name="description">The description of the parameter.</param>
        /// <param name="type">The type of this parameter.</param>
        /// <param name="required">Whether the parameter is required.</param>
        /// <param name="choices">The optional choice selection for this parameter.</param>
        /// <param name="options">The optional subcommands for this parameter.</param>
        public DiscordApplicationCommandOption(string name, string description, ApplicationCommandOptionType type, bool?required = null, IEnumerable <DiscordApplicationCommandOptionChoice> choices = null, IEnumerable <DiscordApplicationCommandOption> options = null)
        {
            if (!Utilities.IsValidSlashCommandName(name))
            {
                throw new ArgumentException("Invalid slash command option name specified. It must be below 32 characters and not contain any whitespace.", nameof(name));
            }
            if (name.Any(ch => char.IsUpper(ch)))
            {
                throw new ArgumentException("Slash command option name cannot have any upper case characters.", nameof(name));
            }
            if (description.Length > 100)
            {
                throw new ArgumentException("Slash command option description cannot exceed 100 characters.", nameof(description));
            }

            var choiceList = choices != null ? new ReadOnlyCollection <DiscordApplicationCommandOptionChoice>(choices.ToList()) : null;
            var optionList = options != null ? new ReadOnlyCollection <DiscordApplicationCommandOption>(options.ToList()) : null;

            this.Name        = name;
            this.Description = description;
            this.Type        = type;
            this.Required    = required;
            this.Choices     = choiceList;
            this.Options     = optionList;
        }
Esempio n. 2
0
 internal AutocompleteOption(ApplicationCommandOptionType type, string name, object value, bool focused)
 {
     Type    = type;
     Name    = name;
     Value   = value;
     Focused = focused;
 }
Esempio n. 3
0
        /// <summary>
        /// Creates a new instance of a <see cref="DiscordApplicationCommandOption"/>.
        /// </summary>
        /// <param name="name">The name of this parameter.</param>
        /// <param name="description">The description of the parameter.</param>
        /// <param name="type">The type of this parameter.</param>
        /// <param name="required">Whether the parameter is required.</param>
        /// <param name="choices">The optional choice selection for this parameter.</param>
        /// <param name="options">The optional subcommands for this parameter.</param>
        public DiscordApplicationCommandOption(string name, string description, ApplicationCommandOptionType type, bool?required = null, IEnumerable <DiscordApplicationCommandOptionChoice> choices = null, IEnumerable <DiscordApplicationCommandOption> options = null)
        {
            var choiceList = choices != null ? new ReadOnlyCollection <DiscordApplicationCommandOptionChoice>(choices.ToList()) : null;
            var optionList = options != null ? new ReadOnlyCollection <DiscordApplicationCommandOption>(options.ToList()) : null;

            this.Name        = name;
            this.Description = description;
            this.Type        = type;
            this.Required    = required;
            this.Choices     = choiceList;
            this.Options     = optionList;
        }
Esempio n. 4
0
        /// <summary>
        ///     Adds an option to the current slash command.
        /// </summary>
        /// <param name="Name">The name of the option to add.</param>
        /// <param name="Type">The type of this option.</param>
        /// <param name="Description">The description of this option.</param>
        /// <param name="Required">If this option is required for this command.</param>
        /// <param name="Default">If this option is the default option.</param>
        /// <param name="Options">The options of the option to add.</param>
        /// <param name="Choices">The choices of this option.</param>
        /// <returns>The current builder.</returns>
        public SlashCommandBuilder AddOption(string Name, ApplicationCommandOptionType Type,
                                             string Description, bool Required = true, bool Default = false, List <SlashCommandOptionBuilder> Options = null, params ApplicationCommandOptionChoiceProperties[] Choices)
        {
            // Make sure the name matches the requirements from discord
            Preconditions.NotNullOrEmpty(Name, nameof(Name));
            Preconditions.AtLeast(Name.Length, 3, nameof(Name));
            Preconditions.AtMost(Name.Length, MaxNameLength, nameof(Name));

            // Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc,
            // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand
            if (!Regex.IsMatch(Name, @"^[\w-]{3,32}$"))
            {
                throw new ArgumentException("Command name cannot contian any special characters or whitespaces!", nameof(Name));
            }

            // same with description
            Preconditions.NotNullOrEmpty(Description, nameof(Description));
            Preconditions.AtLeast(Description.Length, 3, nameof(Description));
            Preconditions.AtMost(Description.Length, MaxDescriptionLength, nameof(Description));

            // make sure theres only one option with default set to true
            if (Default)
            {
                if (this.Options != null)
                {
                    if (this.Options.Any(x => x.Default))
                    {
                        throw new ArgumentException("There can only be one command option with default set to true!", nameof(Default));
                    }
                }
            }

            SlashCommandOptionBuilder option = new SlashCommandOptionBuilder();

            option.Name        = Name;
            option.Description = Description;
            option.Required    = Required;
            option.Default     = Default;
            option.Options     = Options;
            option.Choices     = Choices != null ? new List <ApplicationCommandOptionChoiceProperties>(Choices) : null;

            return(AddOption(option));
        }
Esempio n. 5
0
 /// <summary>
 ///     Adds an option to the current slash command.
 /// </summary>
 /// <param name="Name">The name of the option to add.</param>
 /// <param name="Type">The type of this option.</param>
 /// <param name="Description">The sescription of this option.</param>
 /// <returns>The current builder.</returns>
 public SlashCommandBuilder AddOption(string Name, ApplicationCommandOptionType Type, string Description)
 => AddOption(Name, Type, Description, Options: null, Choices: null);
Esempio n. 6
0
 /// <summary>
 ///     Adds an option to the current slash command.
 /// </summary>
 /// <param name="Name">The name of the option to add.</param>
 /// <param name="Type">The type of this option.</param>
 /// <param name="Description">The description of this option.</param>
 /// <param name="Required">If this option is required for this command.</param>
 /// <param name="Default">If this option is the default option.</param>
 /// <param name="Choices">The choices of this option.</param>
 /// <returns>The current builder.</returns>
 public SlashCommandBuilder AddOption(string Name, ApplicationCommandOptionType Type,
                                      string Description, bool Required = true, bool Default = false, params ApplicationCommandOptionChoiceProperties[] Choices)
 => AddOption(Name, Type, Description, Required, Default, null, Choices);
Esempio n. 7
0
        private void RegisterCommands(Type[] types, ulong?guildid)
        {
            CommandMethod[]   InternalCommandMethods   = Array.Empty <CommandMethod>();
            GroupCommand[]    InternalGroupCommands    = Array.Empty <GroupCommand>();
            SubGroupCommand[] InternalSubGroupCommands = Array.Empty <SubGroupCommand>();
            List <DiscordApplicationCommand> ToUpdate  = new List <DiscordApplicationCommand>();

            _ = Task.Run(async() =>
            {
                foreach (var t in types)
                {
                    try
                    {
                        var ti = t.GetTypeInfo();

                        var classes = ti.DeclaredNestedTypes;
                        foreach (var tti in classes.Where(x => x.GetCustomAttribute <SlashCommandGroupAttribute>() != null))
                        {
                            var groupatt   = tti.GetCustomAttribute <SlashCommandGroupAttribute>();
                            var submethods = tti.DeclaredMethods;
                            var subclasses = tti.DeclaredNestedTypes;
                            if (subclasses.Any(x => x.GetCustomAttribute <SlashCommandGroupAttribute>() != null) && submethods.Any(x => x.GetCustomAttribute <SlashCommandAttribute>() != null))
                            {
                                throw new ArgumentException("Slash command groups cannot have both subcommands and subgroups!");
                            }
                            var payload = new DiscordApplicationCommand(groupatt.Name, groupatt.Description);


                            var commandmethods = new Dictionary <string, MethodInfo>();
                            foreach (var submethod in submethods.Where(x => x.GetCustomAttribute <SlashCommandAttribute>() != null))
                            {
                                var commandattribute = submethod.GetCustomAttribute <SlashCommandAttribute>();


                                var parameters = submethod.GetParameters();
                                if (!ReferenceEquals(parameters.First().ParameterType, typeof(InteractionContext)))
                                {
                                    throw new ArgumentException($"The first argument must be an InteractionContext!");
                                }
                                parameters = parameters.Skip(1).ToArray();

                                var options = ParseParameters(parameters);

                                var subpayload = new DiscordApplicationCommandOption(commandattribute.Name, commandattribute.Description, ApplicationCommandOptionType.SubCommand, null, null, options);

                                commandmethods.Add(commandattribute.Name, submethod);

                                payload = new DiscordApplicationCommand(payload.Name, payload.Description, payload.Options != null ? payload.Options.ToArray().Append(subpayload) : new DiscordApplicationCommandOption[] { subpayload });

                                InternalGroupCommands = InternalGroupCommands.Append(new GroupCommand {
                                    Name = groupatt.Name, ParentClass = tti, Methods = commandmethods
                                }).ToArray();
                            }
                            foreach (var subclass in subclasses.Where(x => x.GetCustomAttribute <SlashCommandGroupAttribute>() != null))
                            {
                                var subgroupatt   = subclass.GetCustomAttribute <SlashCommandGroupAttribute>();
                                var subsubmethods = subclass.DeclaredMethods.Where(x => x.GetCustomAttribute <SlashCommandAttribute>() != null);

                                var command = new SubGroupCommand {
                                    Name = groupatt.Name
                                };

                                var options = new List <DiscordApplicationCommandOption>();

                                foreach (var subsubmethod in subsubmethods)
                                {
                                    var suboptions = new List <DiscordApplicationCommandOption>();
                                    var commatt    = subsubmethod.GetCustomAttribute <SlashCommandAttribute>();
                                    var parameters = subsubmethod.GetParameters();
                                    if (!ReferenceEquals(parameters.First().ParameterType, typeof(InteractionContext)))
                                    {
                                        throw new ArgumentException($"The first argument must be an InteractionContext!");
                                    }
                                    parameters = parameters.Skip(1).ToArray();
                                    options    = options.Concat(ParseParameters(parameters)).ToList();

                                    var subsubpayload = new DiscordApplicationCommandOption(commatt.Name, commatt.Description, ApplicationCommandOptionType.SubCommand, null, null, suboptions);
                                    options.Add(subsubpayload);
                                    commandmethods.Add(commatt.Name, subsubmethod);
                                }

                                var subpayload = new DiscordApplicationCommandOption(subgroupatt.Name, subgroupatt.Description, ApplicationCommandOptionType.SubCommandGroup, null, null, options);
                                command.SubCommands.Add(new GroupCommand {
                                    Name = subgroupatt.Name, ParentClass = subclass, Methods = commandmethods
                                });
                                InternalSubGroupCommands = InternalSubGroupCommands.Append(command).ToArray();
                                payload = new DiscordApplicationCommand(payload.Name, payload.Description, payload.Options != null ? payload.Options.ToArray().Append(subpayload) : new DiscordApplicationCommandOption[] { subpayload });
                            }
                            ToUpdate.Add(payload);
                        }

                        var methods = ti.DeclaredMethods;
                        foreach (var method in methods.Where(x => x.GetCustomAttribute <SlashCommandAttribute>() != null))
                        {
                            var commandattribute = method.GetCustomAttribute <SlashCommandAttribute>();

                            var options = new List <DiscordApplicationCommandOption>();

                            var parameters = method.GetParameters();
                            if (parameters.Length == 0 || parameters == null || !ReferenceEquals(parameters.FirstOrDefault()?.ParameterType, typeof(InteractionContext)))
                            {
                                throw new ArgumentException($"The first argument must be an InteractionContext!");
                            }
                            parameters = parameters.Skip(1).ToArray();
                            foreach (var parameter in parameters)
                            {
                                var optionattribute = parameter.GetCustomAttribute <OptionAttribute>();
                                if (optionattribute == null)
                                {
                                    throw new ArgumentException("Arguments must have the SlashOption attribute!");
                                }

                                var type = parameter.ParameterType;
                                ApplicationCommandOptionType parametertype = GetParameterType(type);

                                DiscordApplicationCommandOptionChoice[] choices = GetChoiceAttributesFromParameter(parameter.GetCustomAttributes <ChoiceAttribute>());

                                options.Add(new DiscordApplicationCommandOption(optionattribute.Name, optionattribute.Description, parametertype, !parameter.IsOptional, choices));
                            }
                            InternalCommandMethods = InternalCommandMethods.Append(new CommandMethod {
                                Method = method, Name = commandattribute.Name, ParentClass = t
                            }).ToArray();

                            var payload = new DiscordApplicationCommand(commandattribute.Name, commandattribute.Description, options);
                            ToUpdate.Add(payload);
                        }
                    }
                    catch (Exception ex)
                    {
                        Client.Logger.LogError(ex, $"There was an error registering slash commands");
                        Environment.Exit(-1);
                    }
                }
                try
                {
                    IEnumerable <DiscordApplicationCommand> commands;
                    if (guildid == null)
                    {
                        commands = await Client.BulkOverwriteGlobalApplicationCommandsAsync(ToUpdate);
                    }
                    else
                    {
                        commands = await Client.BulkOverwriteGuildApplicationCommandsAsync(guildid.Value, ToUpdate);
                    }
                    foreach (var command in commands)
                    {
                        if (InternalCommandMethods.Any(x => x.Name == command.Name))
                        {
                            InternalCommandMethods.First(x => x.Name == command.Name).Id = command.Id;
                        }

                        else if (InternalGroupCommands.Any(x => x.Name == command.Name))
                        {
                            InternalGroupCommands.First(x => x.Name == command.Name).Id = command.Id;
                        }

                        else if (InternalSubGroupCommands.Any(x => x.Name == command.Name))
                        {
                            InternalSubGroupCommands.First(x => x.Name == command.Name).Id = command.Id;
                        }
                    }
                    CommandMethods.AddRange(InternalCommandMethods);
                    GroupCommands.AddRange(InternalGroupCommands);
                    SubGroupCommands.AddRange(InternalSubGroupCommands);
                }
                catch (Exception ex)
                {
                    Client.Logger.LogError(ex, $"There was an error registering slash commands");
                    Environment.Exit(-1);
                }
            });
        }
Esempio n. 8
0
 public ApplicationCommandOptionBuilder WithType(ApplicationCommandOptionType type)
 {
     Type = type;
     return(this);
 }