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.
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
public class PingCommand extends EnhancedCommand {
private final EnhancedBot bot;
public PingCommand(EnhancedBot bot) {
super(bot);
this.bot = bot;
}
// Explained in the next sections...
}
@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.
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
new EnhancedButton(this.bot,
(id) -> Button.primary(id, "Click me")), // Configure JDA Button
(e) -> { // Action when clicked
e.reply("Yup!").setEphemeral(true).queue();
}
)
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();
}
)
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();
}
)
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
@CommandDescriptionannotation on class / method - Setting command permissions - use
@CommandPermissionannotation on class - Setting command as guild only - use
@GuildOnlyCommandannotation on class - Setting command only for certain guilds - use
@GuildCommandannotation on class (and set guild ids as value) - Setting command as NSFW cmd - use
@NsfwCommandannotation on class - Setting method as not command - use
@Utilityannotation on method