A Discord bot framework built on top of JDA designed to be easy to use. The framework is designed to be modular, allowing you to only use the features you need and to focus on your bot's functionality.
- Discord Server: https://asrp.dev/discord
- Twitter: https://twitter.com/AlphaSerpentis_
- GitHub Issues: https://github.com/Alpha-Serpentis-Developments/CoffeeCore/issues
Notice: Coffee Core requires Java 17+!
Maven
<dependency>
<groupId>dev.alphaserpentis</groupId>
<artifactId>CoffeeCore</artifactId>
<version>0.6.2-alpha</version>
</dependency>
Gradle
implementation 'dev.alphaserpentis:CoffeeCore:0.6.2-alpha'
Maven
<dependency>
<groupId>dev.alphaserpentis</groupId>
<artifactId>CoffeeCore</artifactId>
<version>0.7.0-alpha-011924-SNAPSHOT</version>
</dependency>
By default, JDA includes a package to handle voice connections. If you don't need voice support, you can exclude it:
<dependencies>
<dependency>
<groupId>dev.alphaserpentis</groupId>
<artifactId>CoffeeCore</artifactId>
<version>VERSION-HERE</version>
<exclusions>
<exclusion>
<groupId>club.minnced</groupId>
<artifactId>opus-java</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
The default settings are as follows:
- Chunking Filter:
ChunkingFilter.NONE
- Enabled Cache Flags: None
- Disabled Cache Flags:
MEMBER_OVERRIDES
andVOICE_STATE
- Enabled Gateway Intents: None
- Disabled Gateway Intents: None
- Member Cache Policy:
MemberCachePolicy.NONE
- Sharding: Disabled
- Shards Total: -1 (set by Discord)
- Builder Configuration:
BuilderConfiguration.DEFAULT
Note: BuilderConfiguration
is the equivalent of JDABuilder
or DefaultShardManagerBuilder
, depending on if the bot is sharded or not
- (Optional) Create a new
.env
file in the root of your project and fill it out with the following (adjust to your liking):
DISCORD_BOT_TOKEN=YOUR_DISCORD_BOT_TOKEN
BOT_OWNER_ID=YOUR_DISCORD_USER_ID
SERVER_DATA_PATH=PATH_TO_SERVER_DATA_FOLDER
UPDATE_COMMANDS_AT_LAUNCH=true
REGISTER_DEFAULT_COMMANDS=true
- Create a new CoffeeCore instance using CoffeeCoreBuilder and (optionally) load in your bot settings from the
.env
file (or other source):
public static void main(String[] args) throws Exception {
Dotenv dotenv = Dotenv.load(); // Load a local .env file
CoffeeCoreBuilder builder = new CoffeeCoreBuilder();
CoffeeCore core;
// Load in the settings from the .env file
builder
.setSettings(
new BotSettings(
Long.parseLong(dotenv.get("BOT_OWNER_ID")), // the bot owner's user ID
dotenv.get("SERVER_DATA_PATH"), // the path to the server data file
Boolean.parseBoolean(dotenv.get("UPDATE_COMMANDS_AT_LAUNCH")), // whether to update commands at launch
Boolean.parseBoolean(dotenv.get("REGISTER_DEFAULT_COMMANDS")) // whether to register default commands
)
)
.setServerDataHandler(new MyServerDataHandler()) // (Experimental!) Optionally, assign your own ServerDataHandler
.setCommandsHandler(new MyCommandsHandler()); // (Experimental!) Optionally, also assign your own CommandsHandler
// Start the bot
core = builder.build(dotenv.get("DISCORD_BOT_TOKEN"));
// Register your commands with core.registerCommands(...)
core.registerCommands(new MyEpicCommand(), new QuackCommand());
}
When you update commands at launch, any changes made to the structure of the command (e.g., name, description, subcommands)
will be reflected in Discord. However, if this is not toggled to true
, it will not update the changes!
If you wish to use the default commands that Coffee Core offers (e.g., help
, about
, shutdown
, settings
) you can
set this true to have them added to your bot.
Default commands can still be accessed without toggling the setting to true
if needed, and can even be extended off of
to grant more functionality.
Coffee Core offers a flexible command system, catering to various interaction types.
At its core is the BotCommand
class, which provides the foundational behavior for defining and executing commands.
Types of Commands:
- Slash Commands (
SLASH
): The default type of command. Invoked by typing/
in Discord. - User Context Menu Options (
USER
): Invoked by right-clicking on a user in Discord. - Message Context Menu Options (
MESSAGE
): Invoked by right-clicking on a message in Discord.
Regardless of the command type, these types can be used in conjunction with ButtonCommand
or ModalCommand
to add
buttons or modals to your commands.
The CommandResponse
class provides a structured way to define the output of a command. Depending on the nature of the
command, you can choose to send a single string, embed, or multiple embeds.
Note: If you're using String
as your response, you can only return one string!
Default Constructor:
return new CommandResponse<>(
true, // Is the message an ephemeral response
true, // If the user's ratelimit should be forgiven after running this command,
new EmbedBuilder().setDescription("Hello world!").build() // Takes in generic type T which can either be a String or MessageEmbed
);
The following constructors omit the forgiveRatelimit
parameter, which defaults to false
.
Single String:
return new CommandResponse<>(true, "Hello world!");
Multiple Embeds:
return new CommandResponse<>(true, embed1, embed2, embed3);
public class ExampleCommand extends BotCommand<MessageEmbed, SlashCommandInteractionEvent> {
public ExampleCommand() {
super(
new BotCommandOptions()
.setName("example")
.setDescription("An example command")
.setOnlyEmbed(true) // Must match with the generic type (e.g., true if MessageEmbed, false if String)
);
}
@Override
@NonNull
public CommandResponse<MessageEmbed> runCommand(long userId, @NonNull SlashCommandInteractionEvent event) {
EmbedBuilder builder = new EmbedBuilder();
builder.setTitle("Example Command");
builder.setDescription("This is an example command!");
return new CommandResponse<>(true, builder.build());
}
}
To add buttons, you can use the addButton(...)
method. When adding buttons, you must provide a unique name/key for the
button, a ButtonStyle
, a label, and whether the button is disabled. Optionally, there's a fifth parameter that allows
you to provide an Emoji
.
Check out an example here
public class ExampleCommand extends ButtonCommand<MessageEmbed, SlashCommandInteractionEvent> {
public ExampleCommand() {
super(
// set your BotCommandOptions
);
addButton("primary", ButtonStyle.PRIMARY, "Primary", false);
addButton("secondary", ButtonStyle.SECONDARY, "Secondary", false);
addButton("danger", ButtonStyle.DANGER, "Danger", false);
}
@Override
@NonNull
public CommandResponse<MessageEmbed> runCommand(long userId, @NonNull SlashCommandInteractionEvent event) {
// Run stuff here
}
@Override
public void runButtonInteraction(@NonNull ButtonInteractionEvent event) {
String key = convertComponentIdToKey(event.getComponentId());
// Do stuff here based on the key
}
@Override
@NonNull
public Collection<ItemComponent> addButtonsToMessage(@NonNull GenericCommandInteractionEvent event) {
return Arrays.asList(new ItemComponent[]{
getButton("primary"),
getButton("secondary"),
getButton("danger")
});
}
}
To be written...