-
Notifications
You must be signed in to change notification settings - Fork 0
Interactions
All slash commands are handled with the abstract class DiscordCommand
. To create a new command, you have to extend
this class and set a unique name as well as a description. The main method for a command is the execute method.
This method is called as soon as the user uses the command.
Important: Discord gives every application 3 seconds to acknowledge the request. If this does not happen, the user will see an error message.
@Interaction
class PingCommand : DiscordCommand("ping", "Send a ping command") {
override fun execute(event: SlashCommandInteractionEvent) {
//Reply to the user
val startTime = System.currentTimeMillis()
event.reply("Ping ...").setEphemeral(true).queue {
it.editOriginal("Pong: ${System.currentTimeMillis() - startTime}ms").queue()
}
}
}
This process is completely handled by the InteractionInitializer
, which jumps into action as soon as the first shard
is connected to Discord.
All commands which are extending DiscordCommand
are loaded during this time.
This handler will create a temporary instance of all commands and checks them against the currently on Discord
registered commands.
Any difference will be updated as needed. This includes deletion of no longer in the code present commands.
Discord commands can have options. These options have to be defined in the method initCommandOptions()
.
In this method you can define them like this: this.addOption(myOption)
.
For the option themselves we advise you to use the typed options of Aluna, found in the file Options.kt
.
Here is an example for a simple string option:
private val animalOption = StringOption("animal", "Preferred animal", isRequired = true)
override fun initCommandOptions() {
this.addOption(animalOption)
}
All currently available options are listed in the table below:
Option type | Aluna typed option |
---|---|
STRING | StringOption() |
INTEGER | IntegerOption() |
INTEGER | LongOption() |
NUMBER | DoubleOption() |
NUMBER | NumberOption() |
BOOLEAN | BooleanOption() |
USER | UserOption() |
ROLE | RoleOption() |
CHANNEL | ChannelOption() |
MENTIONABLE | MentionableOption() |
ATTACHMENT | AttachmentOption() |
ATTACHMENT | FileOption() |
By using these types, you can access the users input with event.getTypedOption()
in a type-safe manner.
To structure your commands, Discord allows you to create sub-commands and sub-command groups. How they can be combined can be found in the official Discord Documentation: Subcommands and Subcommand Groups
Here is an example for a command with a sub-command and a sub-command group:
@Interaction
class AnimalsCommand(
@SubCommandElement
private val forestSubCommandGroup: ForestSubCommandGroup,
@SubCommandElement
private val bunnyCommand: BunnyCommand
) : DiscordCommand("animal", "Show images of animals", handleSubCommands = true) {
override fun execute(event: SlashCommandInteractionEvent) {
}
}
@Interaction
class BunnyCommand(
private val objectMapper: ObjectMapper
) : DiscordSubCommand("bunny", "Show image of a bunny") {
override fun execute(event: SlashCommandInteractionEvent) {
}
}
@Interaction
class ForestSubCommandGroup(
@SubCommandElement
private val foxCommand: FoxCommand
) : DiscordSubCommandGroup("forest", "Forest animals")
@Interaction
class FoxCommand(
private val objectMapper: ObjectMapper
) : DiscordSubCommand("fox", "Show image of a fox") {
override fun execute(event: SlashCommandInteractionEvent) {
}
}
As you can see sub-commands are always loaded over autowired dependencies and the @SubCommandElement
. Also
sub-commands and sub-command-groups have their own abstract classes they extend.
One important note here is that the execute method of the parent classes is also called.
For the command /animal forst fox
, the following execute methods are called in this order:
AnimalsCommand.execute() -> FoxCommand.execute()
The ForestSubCommandGroup
has no execute method as it is a group and can not be used without a sub command.
Discord commands also support auto-complete for their options. These auto-complete request are also handled by Aluna if
you set the command property observeAutoComplete = true
.
In that case Aluna will automatically call the method onAutoCompleteEvent()
which you can and should override in that
case. Same as for the command itself, your bot has to acknowledge the request in under 3 seconds.
All options which have auto-complete enabled, have to be handled by this method.
Example implementation:
@Interaction
class SetPreferredAnimalCommand :
DiscordCommand("set-preferred-animal", "Define your preferred Animal", observeAutoComplete = true) {
private val animalOption = StringOption("animal", "Preferred animal", isRequired = true, isAutoComplete = true)
override fun initCommandOptions() {
this.addOption(animalOption)
}
override fun execute(event: SlashCommandInteractionEvent) {
event.reply(event.getTypedOption(animalOption, "")!!).complete()
}
override fun onAutoCompleteEvent(option: String, event: CommandAutoCompleteInteractionEvent) {
val options = hashMapOf<String, String>()
options["fox"] = "Fox"
options["bunny"] = "Bunny"
options["deer"] = "Deer"
event.replyStringChoices(options).queue()
}
}
Aluna comes with its own scope (@InteractionScoped
) for all interactions. If you use the annotation @Interaction
,
this will automatically be used.
This scope will ensure that a user always gets the same bean for a command if there are for examples buttons which can be clicked. The same is the case if a command has auto-complete for some options. In that case a bean of the command will be created on the first auto-complete request, and it will be reused if the user than uses the command itself.
By default, Aluna will keep a bean for 14 minutes. This is to ensure that on destruction of the bean, the
method onDestroy()
is still able to use the same interaction hook (the stays active for 15 min).
This timeout gets reset if the bean is reused because of component interaction (like buttons, select-menu or modals) as
well as if the bean cot created from a auto-complete request.
If you want to change the default behavior, you can set these properties in the constructor:
- beanTimoutDelay
- beanUseAutoCompleteBean
- beanRemoveObserverOnDestroy
- beanResetObserverTimeoutOnBeanExtend
- beanCallOnDestroy
There are two ways to handle components with Aluna: Integrated Way or Manually over the EventHandler.
To use the integrated way, the message has to be sent with the queueAndRegisterInteraction()
method or manually (
example for buttons) with discordBot.registerMessageForButtonEvents(it, this)
.
Aluna will than call the corresponding method onButtonInteraction()
and onButtonInteractionTimeout()
after the
defined timeout. *By default the timeout is set to 14 minutes.
Methods to override:
Type | Methods |
---|---|
Button | onButtonInteraction() |
String Select | onStringSelectInteraction() |
Entity Select | onEntitySelectInteraction() |
Modal | onModalInteraction() |
todo
todo
All context-menus are handled with either the abstract class DiscordUserContextMenu
or DiscordMessageContextMenu
. To
create a new context-menu, you have to extend
one of these classes and set a unique name. The main method for a command is the execute method.
This method is called as soon as the user uses the context-menu.
Important: Discord gives every application 3 seconds to acknowledge the request. If this does not happen, the user will see an error message.
@Interaction
class GetMessageAsWebhookMessageMenu(
private val objectMapper: ObjectMapper
) : DiscordMessageContextMenu("Extract as Webhook") {
override fun execute(event: MessageContextInteractionEvent) {
}
}
This process is completely handled by the InteractionInitializer
, which jumps into action as soon as the first shard
is connected to Discord.
All context-menus which are extending DiscordUserContextMenu
or DiscordMessageContextMenu
are loaded during this
time.
This handler will create a temporary instance of all context-menus and checks them against the currently on Discord
registered context-menus.
Any difference will be updated as needed. This includes deletion of no longer in the code present context-menus.
Aluna comes with its own scope (@InteractionScoped
) for all interactions. If you use the annotation @Interaction
,
this will automatically be used.
This scope will ensure that a user always gets the same bean for a context-menu if there are for examples buttons which can be clicked.
By default, Aluna will keep a bean for 14 minutes. This is to ensure that on destruction of the bean, the
method onDestroy()
is still able to use the same interaction hook (the stays active for 15 min).
This timeout gets reset if the bean is reused because of component interaction (like buttons, select-menu or modals) as
well as if the bean cot created from a auto-complete request.
If you want to change the default behavior, you can set these properties in the constructor:
- beanTimoutDelay
- beanUseAutoCompleteBean
- beanRemoveObserverOnDestroy
- beanCallOnDestroy
todo
todo
todo
todo
todo
todo
todo
todo
todo
todo
Viascom GmbH