Annotation-based multifunctional command handler framework for JDA & Javacord. KCommando has a external plugin system.
All these features have a modular structure and you can edit all of these modules and integrate them for your projects.
package com.example.mybot;
public class Main {
public void main(String[] args) throws Exception {
JDA jda = JDABuilder.createDefault("TOKEN").build();
jda.awaitReady();
JDAIntegration integration = new JDAIntegration(jda);
KCommando kcommando = new KCommando(integration)
.setOwners(00000000L, 00000000L) // varargs LONG
.addPackage("com.example.mybot") // package to analyze
.setCooldown(5000L) // 5 seconds as 5000 ms
.setPrefix("!")
.setReadBotMessages(false) // default false
.setUseCaseSensitivity(false) // default false
.setAllowSpacesInPrefix(true) // default false
.setDefaultFalseMethodName("defaultCallback")
.setVerbose(true) // for logging
.build();
}
}
That's it. Now, we can create slash commands or classic commands.
You don't have to identify the guildId
. If you don't, it will be a global command. Also options are optional. It's okay if the method is static.
package com.example.mybot.slash;
public class MySlashCommands {
@HandleSlash(name = "hello", desc = "Test command.", guildId = 000000L,
options = @Option(type = OptionType.STRING, name = "yourName", required = true))
public void helloCommand(SlashCommandInteractionEvent e) {
e.deferReply(false).queue();
String name = e.getOption("yourName").getAsString();
e.getHook().sendMessage("Hello " + name + "!").queue();
}
@HandleSlash(name = "ping", desc = "Pong!")
public static void pingCommand(SlashCommandInteractionEvent e) {
e.reply("Pong!!").addActionRow(
Button.primary("buttonHello", "Button Text"),
Button.secondary("processData", "Process")
).queue();
}
}
package com.example.mybot.buttons;
public class Hello {
@HandleButton("buttonHello")
public void helloButton(ButtonInteractionEvent e) {
// ...
}
@HandleButton("processData")
public void processor(ButtonInteractionEvent e) {
// ...
}
}
package com.example.mybot.commands;
public class BasicCommands {
@HandleCommand(name = "Ping", aliases = "ping",
description = "Pong!", /* "-" default */
/* "defaultCallback" is default because we set it to it above here */
falseMethod = "customFalse",
guildOnly = false, /* false default */
ownerOnly = false, /* false default */
privateOnly = false /* false default */)
public boolean ping(MessageReceivedEvent e /*, String[] args, String prefix */) {
e.getChannel().sendMessage("Pong!").queue();
return false; // for test the customFalse callback method
}
@HandleCommand(name = "Test", aliases = {"test", "testo"})
public void test(MessageReceivedEvent e, String[] args /*, String prefix */) {
// ...
}
@HandleFalse
public static void customFalse(MessageReceivedEvent e /*, String[] args, String prefix */) {
e.getMessage().addReaction("⛔").queue();
}
@HandleFalse // we set it to default with method name while initializing the KCommando
public static void defaultCallback(MessageReceivedEvent e, String[] args, String prefix) {
// ...
}
}
Optionally you can use the class and handle method as final to reduce compile time.
Aliases field can be an array: aliases = {"ping", "pingu"}
package com.example.mybot;
public class Example {
// kcommando doesn't have a database manager
// this is example for how to use parameterized classes with kcommando
private final DatabaseManager databaseManager;
public Example(DatabaseManager databaseManager) {
this.databaseManager = databaseManager;
}
@HandleCommand(name = "ListDatabase", aliases = {"db", "listdb"})
public void command(MessageReceivedEvent e) {
String example = databaseManager.query("SELECT * FROM logs");
// ...
}
}
package com.example.mybot;
public class Main {
public void main(String[] args) throws Exception {
JDA jda = JDABuilder.createDefault("TOKEN").build();
jda.awaitReady();
JDAIntegration integration = new JDAIntegration(jda);
KCommando kcommando = new KCommando(integration)
.setPackage("com.example.mybot") // package to analyze
.setPrefix("!")
.setVerbose(true)
.build();
DatabaseManager databaseManager = new DatabaseManager();
// this class includes command
// kcommando will use this instance while executing the command
Example myObject = new Example(databaseManager);
// also you can do this before build the kcommando
kcommando.registerObject(myObject); // <--------
}
}
You can use just one of these in your command class. Parameters will never be null. You don't need null checks.
<void/boolean> commandMethod(<Event> e)
<void/boolean> commandMethod(<Event> e, String[] args)
<void/boolean> commandMethod(<Event> e, String[] args, String prefix)
Args are splitted by the "space" characters. The 0. index is the command text itself (without the prefix).
Entered Command: "!ping test 123"
args[0]: "ping"
args[1]: "test"
args[2]: "123"
prefix: "!"
This callback will be called with the suggestions list and the event object when an incorrect command is used. Currently, the suggestions are based on the JaroWrinklerDistance algorithm.
package com.example.mybot;
public class OtherThings {
// also you can use the Set<String> instead of the List<String>
@SimilarCallback
public static void similar(MessageReceivedEvent e, List<String> similarCommands /*, String enteredCommand */) {
String commands = String.join(", ", similarCommands);
e.getChannel().sendMessage("Similar commands are here: " + commands).queue();
}
}
You can add custom prefixes for guilds.
// adds a prefix for the selected guild.
Integration#addCustomPrefix(long guildID, String prefix)
// removes a prefix for the selected guild. This method is safe to use.
Integration#removeCustomPrefix(long guildID, String prefix)
// removes all custom prefixes for selected guild.
Integration#removeAllCustomPrefixes(long guildID)
If a guild has a custom prefix, the normal prefix will be overridden for that guild but it is possible to use more than one prefix at the same time. You can remove and disable custom prefixes for the single guild.
KCommando has a minute-based async CronService and you can use it.
CronService.getInstance().addRunnable(() -> {
// do stuff
}, 5); /* every 5 minutes */
To always use the latest version, you can write '-SNAPSHOT' in the version field. This use is not recommended because new versions may not always be fully backwards compatible.
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<!-- FOR JDA -->
<dependency>
<groupId>com.github.koply.KCommando</groupId>
<artifactId>jda-integration</artifactId>
<version>JITPACK-VERSION</version>
</dependency>
<!-- FOR JAVACORD -->
<dependency>
<groupId>com.github.koply.KCommando</groupId>
<artifactId>javacord-integration</artifactId>
<version>JITPACK-VERSION</version>
</dependency>
repositories {
maven { url 'https://jitpack.io' }
}
// FOR JDA
dependencies {
implementation 'com.github.koply.KCommando:jda-integration:JITPACK-VERSION'
}
// FOR JAVACORD
dependencies {
implementation 'com.github.koply.KCommando:javacord-integration:JITPACK-VERSION'
}
Please change 'JITPACK-VERSION' fields to the latest release version.
Github packages are ignored. Please use jitpack repositories.