Skip to content

Vampire/command-framework

Repository files navigation

Command Framework

Version JavaDoc License Discord

Unit Test Coverage Badge Mutant Coverage Badge Integration Test Coverage Badge

Supported Java Versions

Supported Message Frameworks

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.

Table of Contents

Prerequisites

  • Java 8+
  • At least one of the supported message frameworks unless a custom CommandHandler is 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 ParameterParser is used

Supported Message Frameworks

The following message frameworks are currently supported out of the box:

  • Javacord (text and slash commands)
  • JDA (text and slash commands)

If you want to have support for an additional framework, do not hesitate to open a pull request or feature request issue.

Setup

Gradle

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-support
  • net.kautler:command-framework-jda-support
  • net.kautler:command-framework-parameter-parser

Maven

<dependency>
    <groupId>net.kautler</groupId>
    <artifactId>command-framework</artifactId>
    <version>0.7.0-SNAPSHOT</version>
</dependency>

Manually

Download the JAR for the latest release from the Latest Release Page and include it in your project.

Usage

Message Framework

Javacord

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

JDA

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