Skip to main content

Slash Commands

EnhancedJDA adds a really modern and easy-to-use system for creating slash commands. To create slash commands, you should create a package (or multiple packages) with all commands. They should extend EnhancedCommandclass. To register it, use the ⁣PackageMapping annotation in the main class. When ENV is set to DEV then commands will be registered as guild commands; when ENV is set to PRODUCTION then they will be registered as global commands.

dev.projectenhanced.enhancedjda.controller.PackageMapping
public @interface PackageMapping {
String[] commands() default {};
String[] contexts() default {};
String[] listeners() default {};
String[] tables() default {};
String[] persisters() default {};
}

Example setup:

.
├── myCommands/
│ ├── PingCommand.class
│ ├── AnotherCommand.class
│ └── ...
└── Main.class
myCommands.PingCommand
public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}

// Explained in the next sections...
}
Main
@PackageMapping(
commands = {"myCommands"},
)
public class Main extends EnhancedBot {
  // ...
}

Creating commands

Each command/subcommand is represented by its own method with SlashCommandInteractionEvent param. The name of command is a name of class without a ⁣Command suffix, so i.e. PingCommand creates /ping command. The name of subcommand is a name of method. On Discord, you can create commands that execute something or multiple subcommands that execute something. If you want to create one main command, then add @MainCommand annotation. If you want to create multiple subcommands, then don’t use that annotation.

Example of main command (it will create /ping command_):_

public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}

    @MainCommand
public void execute(SlashCommandInteractionEvent event) {
        event.reply("Pong!").queue();
    }
}

Example of subcommands (/ping a and /ping b):

public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}

public void a(SlashCommandInteractionEvent event) {
        event.reply("Pong A!").queue();
    }

    public void b(SlashCommandInteractionEvent event) {
        event.reply("Pong B!").queue();
    }
}

You can also create subcommand groups by creating inner classes. The name of a group is a name of an inner class.

Example of subcommand groups & subcommand (/ping a, /ping something a, /ping something b):

public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}

public void a(SlashCommandInteractionEvent event) {
        event.reply("Pong A!").queue();
    }

    public class Something {
       public void a(SlashCommandInteractionEvent event) {
            event.reply("Pong Something A!").queue();
        }

       public void b(SlashCommandInteractionEvent event) {
            event.reply("Pong Something B!").queue();
        }
    }
}

Command options

You can add options to your commands by using @CommandOption annotation (you can add multiple annotations of this type) on the method.

dev.projectenhanced.enhancedjda.controller.command.annotation.CommandOption
public @interface CommandOption {
OptionType type();
String name();
String description();
boolean required() default false;
boolean autoComplete() default false;
}

Example of using options (/ping <user>):

public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}

    @MainCommand
    @CommandOption(type=OptionType.USER, name="user", description = "User to play with", required = true)
public void execute(SlashCommandInteractionEvent event) {
        User user = event.getOption("user").getAsUser();
        event.reply("Pong "+ user.getName() +"!").queue();
    }
}

Autocomplete

You can create an autocompleter by overriding method autoComplete(CommandAutoCompleteInteractionEvent event, String option, String value)

Components & Modals

You can easily create interactive components and modals using: EnhancedButton, EnhancedStringSelect, EnhancedEntitySelect and EnhancedModal. They work in the same way. There are 2 ways to create component / modal: temporary and permanent.

Creating temporary component

To create a temporary component, use (EnhancedBot bot, Function<String,T> configure, Consumer<Z> action) and pass id param in the configure method. A created object you should directly pass into the addActionRow method of event.reply().

Template example of creating temp component:

public void a(SlashCommandInteractionEvent event) {
    event.reply("Pong A!")
        .addActionRow(
            new EnhancedButton(this.bot,
(id) -> Button.primary(id, "Click me").withEmoji(Emoji.fromUnicode("uD83EuDD7A")), // Creating button
(e) -> {
e.reply("Yup!").setEphemeral(true).queue(); // Response
}
).getComponent()
        ).queue();
}

Creating permanent component

Permanent components work even after restarting the bot. They need to have their own unique ID. To create it, you should create it using (EnhancedBot bot, String permanentId, Function<String,T> configure, Consumer<Z> action) constructor and register it into ComponentController i.e. in the command constructor. Later, you can get it using ComponentController#getComponent and add it into ActionRow.

Template example of creating perm component:

public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;

public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
        bot.getComponentController().registerComponents(
new EnhancedButton(this.bot,
"report_stuff",
(id) -> Button.danger(id, "Report something"), // Configure button
(e) -> {
                    e.reply("Works!").queue(); // Result
                }
            )
        );
}

    @MainCommand
public void execute(SlashCommandInteractionEvent event) {
        event.reply("Pong!")
            .addActionRow(bot.getComponentController().getComponent("report_stuff"))
            .queue();
    }
}

Examples of all components

EnhancedButton
new EnhancedButton(this.bot,
(id) -> Button.primary(id, "Click me")), // Configure JDA Button
(e) -> { // Action when clicked
e.reply("Yup!").setEphemeral(true).queue();
}
)
EnhancedStringSelect
new EnhancedStringSelect(this.bot,
(id) -> StringSelectMenu.create(id)
.addOption("Something", "sth")
.addOption("Nothing", "nope")
.addOption("Maybe", ":/")
                .setRequiredRange(1,2)
.build(), // Configure JDA StringSelectMenu
(e) -> { // Action when confirmed
e.reply("You selected: " + String.join(", ", e.getValues())).setEphemeral(true).queue();
}
)
EnhancedEntitySelect
new EnhancedEntitySelect(this.bot,
(id) -> EntitySelectMenu.create(id,EntitySelectMenu.SelectTarget.CHANNEL)
                .setRequiredRange(1,3)
                .build(), // Configure JDA EnhancedEntitySelect
(e) -> { // Action when confirmed
e.reply("You selected: " +
                String.join(", ",
e.getMentions().getChannels()
                                .stream().map(GuildChannel::getName).toList()
)
).setEphemeral(true).queue();
}
)
EnhancedModal
new EnhancedModal(this.bot,
        (id) -> Modal.create(id, "Report something")
    .addActionRow(TextInput.create("subject", "Report subject", TextInputStyle.SHORT).build())
.addActionRow( TextInput.create("description", "Report description", TextInputStyle.PARAGRAPH).build())
.build(),
(e) -> {
            e.reply("# " + modalEvent.getValue("subject").getAsString() + "n*" + modalEvent.getValue("description").getAsString() + "*").queue();
}
)

Another configuration options

  • Setting command / subcommand description - use @CommandDescription annotation on class / method
  • Setting command permissions - use @CommandPermission annotation on class
  • Setting command as guild only - use @GuildOnlyCommand annotation on class
  • Setting command only for certain guilds - use @GuildCommand annotation on class (and set guild ids as value)
  • Setting command as NSFW cmd - use @NsfwCommand annotation on class
  • Setting method as not command - use @Utility annotation on method