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 EnhancedCommand
class. 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
@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