A generic CDI-based command framework. This library requires Java 8 or newer but is fully Java 9+ compatible and can run
as a proper Java module on the module path. Any arbitrary underlying message framework like a Discord library, an IRC
library, or a Skype library can be used by providing an according CommandHandler
implementation. You are also welcome to contribute such implementations back to the main project for all users' benefit.
- Prerequisites
- Supported Message Frameworks
- Setup
- Usage
- Message Framework
- Creating Commands
- Command Aliases
- Asynchronous Command Execution
- Command Description
- Command Restrictions
- Command Usage
- Parsing Parameters
- Customizing Parameter Converters
- Customizing Command Prefix
- Customizing Alias Calculation
- Customizing the Command Recognition and Resolution Process
- Storing Additional Data in the Command Context
- CDI Events
- Getting the Library Version Programmatically
- Supporting other Message Frameworks
- Version Numbers
- License
- Java 8+
- At least one of the supported message frameworks unless a custom
CommandHandleris used; without one there will be no error, but this framework will simply have nothing to do - An implementation of CDI that implements CDI 3.0.1 like Weld SE
- [Optional] ANTLR runtime 4.13.2 if the
ParameterParseris used
The following message frameworks are currently supported out of the box:
If you want to have support for an additional framework, do not hesitate to open a pull request or feature request issue.
repositories {
mavenCentral()
}
dependencies {
implementation("net.kautler:command-framework:0.7.0-SNAPSHOT")
}There are also feature variants published that Gradle consumers can conveniently depend on.
One such variant per message framework support and one for the parameter parser.
The code artifact is the same for all variants currently, but you will benefit from automatically getting
the necessary transitive dependencies that are only mentioned as optional in the POM.
For example to use the Javacord support and the parameter parser, you can request the according feature variants like this:
dependencies {
implementation("net.kautler:command-framework:0.7.0-SNAPSHOT") {
capabilities {
requireFeature("javacord-support")
}
}
implementation("net.kautler:command-framework") {
capabilities {
requireFeature("parameter-parser")
}
}
}Published Feature Variants:
net.kautler:command-framework-javacord-supportnet.kautler:command-framework-jda-supportnet.kautler:command-framework-parameter-parser
<dependency>
<groupId>net.kautler</groupId>
<artifactId>command-framework</artifactId>
<version>0.7.0-SNAPSHOT</version>
</dependency>Download the JAR for the latest release from the Latest Release Page and include it in your project.
For the Javacord support, include Javacord as implementation dependency and create a CDI producer
that produces either one DiscordApi, or if you use sharding a Collection<DiscordApi> with all shards where you want
commands to be handled. You should also have a disposer method that properly disconnects the produced DiscordApi
instances.
Example:
@ApplicationScoped
class JavacordProducer {
@Inject
Logger logger;
@Inject
@Named
String discordToken;
@Produces
@ApplicationScoped
DiscordApi produceDiscordApi() {
return new DiscordApiBuilder()
.setToken(discordToken)
// comment in the next line when using text commands
//.addIntents(MESSAGE_CONTENT)
.login()
.exceptionally(ExceptionLogger.get())
.join();
}
private void disposeDiscordApi(@Disposes DiscordApi discordApi) {
discordApi.disconnect();
}
}Tested versions:
3.8.0
For slash commands you need to do the same as for Text Commands.
Additionally, the commands have to implement
SlashCommandJavacord instead of Command. Furthermore, they must have a
description defined, and all aliases have to consist of one to three
slash separated parts, so either command, command/subcommand, or command/subcommand-group/subcommand.
If your command needs parameters, you overwrite the SlashCommandJavacord#getOptions method, which just returns
an empty list in its default implementation. In the implementation of the method you can then use the full API
for Javacord slash command options.
When using command context transformers with slash
commands, all phases before BEFORE_COMMAND_COMPUTATION are skipped by the command handler already.
Finally, this framework does not register the slash commands with Discord for you automatically, because you
might want to register them globally, or per server, or you might want to add further commands not managed by
this framework, and so on. Instead, you can register the commands yourself by injecting the provided
Set<SlashCommandBuilder>. This injected list can directly be used as argument for methods like
DiscordApi#bulkOverwriteGlobalApplicationCommands or DiscordApi#bulkOverwriteServerApplicationCommands.
The requirements described above regarding description and aliases are only enforced if you inject it somewhere.
A fully self-contained example containing a text, a slash, and a combined command can be found at
examples/simplePingBotJavacord.
Example:
@ApplicationScoped
public class SlashCommandRegisterer {
@Inject
DiscordApi discordApi;
@Inject
Set<SlashCommandBuilder> slashCommandBuilders;
void registerSlashCommands(@Observes @Initialized(ApplicationScoped.class) Object __) {
discordApi
.bulkOverwriteGlobalApplicationCommands(slashCommandBuilders)
.exceptionally(ExceptionLogger.get());
}
}Tested versions:
3.8.0
For the JDA support, include JDA as implementation dependency and create a CDI producer that produces
either one JDA, of if you use sharding a Collection<JDA>, a ShardManager or a Collection<ShardManager> with all
shards where you want commands to be handled. You should also have a disposer method that properly shuts down the
produced JDA and / or ShardManager instances.
Example:
@ApplicationScoped
class JdaProducer {
@Inject
Logger logger;
@Inject
@Named
String discordToken;
@Produces
@ApplicationScoped
JDA produceJda() {
try {
return JDABuilder
.createLight(discordToken)
// comment in the next line when using text commands
//.enableIntents(MESSAGE_CONTENT)
.build()
.awaitReady();
} catch (InterruptedException e) {
logger
.atError()
.withThrowable(e)
.log("Exception while logging in to Discord");
return null;
}
}
private void disposeJda(@Disposes JDA jda) {
jda.shutdown();
}
}Tested versions:
6.4.0
For slash commands you need to do the same as for