Skip to content

Releases: freya022/BotCommands

v3.1.0 | Checkboxes, radio groups and checkbox groups

29 Mar 19:50
af3d5da

Choose a tag to compare

JDA

Updated to JDA 6.4.0 and added support for checkboxes, radio groups and checkbox groups.


Checkboxes, checkbox groups and radio groups (#253)

This adds support for reading values in modal handlers, and Kotlin extensions + DSL builders for the new modals components.

Values of those new components can now be read as:

  • Checkbox -> Boolean
  • CheckboxGroup -> List<String>, String for single values (can be null)
  • RadioGroup -> String (can be null)
Example command
private const val MODAL_NAME = "SlashModal: modal"
private const val CHECKBOX_ID = "checkbox-id"
private const val RADIO_GROUP_ID = "radio_group-id"
private const val CHECKBOX_GROUP_ID = "checkbox_group-id"

@Command
class SlashModal(private val modals: Modals) {
    @JDASlashCommand(name = "modal", description = "Test new modal features!")
    fun onSlashModal(event: GuildSlashEvent) {
        val modal = modals.create("Modal") {
            label("I like checking boxes") {
                child = Checkbox(CHECKBOX_ID, isDefault = true)
            }

            label("Which Discord client do you use?") {
                child = RadioGroup(RADIO_GROUP_ID) {
                    option("Discord (Stable)", "stable", "The vanilla option", default = true)
                    option("Discord PTB", "ptb", "A peek into the future")
                    option("Discord Canary", "canary", "Living on the edge")
                }
            }

            label("Which modal components do you use?") {
                child = CheckboxGroup(CHECKBOX_GROUP_ID) {
                    option("Text Inputs", "textinputs")
                    option("Select Menus", "selectmenus")
                    option("File Uploads", "fileuploads")
                    option("Checkbox groups", "checkboxgroups", default = true)
                }
            }

            bindTo(MODAL_NAME)
        }

        event.replyModal(modal).queue()
    }

    @ModalHandler(MODAL_NAME)
    fun onModal(
        event: ModalEvent,
        @ModalInput(CHECKBOX_ID) doTheyLikeCheckingBoxes: Boolean,
        @ModalInput(RADIO_GROUP_ID) client: String,
        @ModalInput(CHECKBOX_GROUP_ID) features: List<String>,
    ) {
        event.reply("""
            Do you like checking boxes? $doTheyLikeCheckingBoxes
            On what client? $client
            Using what features? $features
        """.trimIndent())
            .setEphemeral(true)
            .queue()
    }
}

JDA PR: discord-jda/JDA#3010


New feature

jda-ktx

  • Added RestActionReasonContext and withRestActionReasonContext
    • Coroutine support for JDA's ThreadLocalReason

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0...v3.1.0


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.1.0")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.1.0</version>
</dependency>

v3.0.0

17 Mar 15:32
c890f70

Choose a tag to compare

JDA

It's finally here, after almost 4 years and nearly 2500 commits.

This is quite different from BC v2, so there is no clear migration guide, but I would recommend looking at the setup wiki along with dependency injection.

For those running on v3 pre-release builds, you can upgrade to 3.0.0-beta.10, then do a full build to catch all the deprecations before upgrading.


Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.10...v3.0.0


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0</version>
</dependency>

v3.0.0-beta.10 | Hot restarting module

15 Mar 14:53
24b5b83

Choose a tag to compare

JDA

Overview

This release adds hot restarting and a few fixes. The wiki has also been greatly updated, feedback is welcome.

Added hot restarting (#232)

This new development-only module restarts your app automatically upon build, while keeping the same JVM, leading to much faster restarts, as it doesn't need to recompile most of the code.

Look at the README for more details.


Deprecations

Localization

  • getDiscordLocale of all locale providers (UserLocaleProvider, GuildLocaleProvider, TextCommandLocaleProvider) were deprecated
    • You must implement getLocale instead

Event waiter

  • BConfig#ignoredEventIntents was deprecated
    • This has been replaced by EventWaiterBuilder#ignoreMissingIntents

Changes

  • Updated to JDA 6.3.2
  • Updated to Jackson 2.21.1

Fixes

Database

  • Fixed schema not being reset-ed correctly when returning to the connection pool in some cases

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.9...v3.0.0-beta.10


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.10")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.10</version>
</dependency>

v3.0.0-beta.9

28 Feb 21:16
5f88f76

Choose a tag to compare

JDA

Important

JDA is no longer included as a transitive dependency, you will need to include it in your project.

Preparation for configuration of modules (#254)

In newer 3.X modules, and for most, if not all features in 4.X, each feature/module added by the user will contain their own configuration.

Each configuration is registered on the main configuration, Kotlin users are able to use an extension.

Registering the module's configuration means enabling the feature.

Changes

  • Added methods to get/add configurations:
    • getConfigOrNull (on the built root configuration)
    • registerModule (on the root configuration builder)

Added shutdown functions (#255)

Changes

  • Added isDaemon to namedDefaultScope
  • Added new statuses
  • Added shutdown functions
  • Added functions to await shutdown
  • Added shutdown hooks, enabled by default

Migration from DiscordLocale to Locale in localization (#260)

As mapping Locale between DiscordLocale is not perfect, and the underlying localization is using Locale, getting messages should be using Locale. Implicit convertions should be avoided, so methods using DiscordLocale are deprecated.

If you wish to continue using DiscordLocale, you will have to use toLocale().

Commands are still localized using DiscordLocale, any feature that is limited to the locales Discord supports, should use DiscordLocale.

Warning

Breaking changes

  • AppLocalizationContext.userLocale now returns Locale
  • TextLocalizationContext.guildLocale now returns Locale
  • LocalizationContext.effectiveLocale now returns Locale

Deprecations

  • getDiscordLocale was deprecated in all locale providers (UserLocaleProvider, GuildLocaleProvider, TextCommandLocaleProvider)
  • Deprecated all reply/edit methods accepting DiscordLocale

Additions

  • Added new overloads accepting Locale

Warning

Breaking changes

Components

  • Exceptions changed when awaiting on a component:
    • ComponentTimeoutException is thrown when the timeout is reached while awaiting
    • RemovedComponentException is thrown when a component is removed while awaiting

Modals

  • Exceptions changed when awaiting on a modal:
    • ModalTimeoutException is thrown when the timeout is reached while awaiting

Misc

  • Removed dependency on kotlinx.datetime
    • All kotlinx.datetime imports were replaced by kotlin.time

New features

Typesafe messages

  • Added more create overloads in IMessageSourceFactory
    • To create message sources from message events (text commands) and arbitrary locales

Kotlin extensions

  • Added TimeFormat.atInstant with kotlin.time.Instant

Deprecations

Application commands

  • Deprecated configuration property slashGuildIds, renamed as guildsToUpdate

Localization

LocalizationContext factories are deprecated and were replaced by a builder (LocalizationContext.builder)


Changes

Dependencies

  • Updated to Kotlin 2.3.10

Modals

  • You can now have @ModalInput refer to an input absent from the submitted modal, if the parameter is nullable or optional
  • String parameters (from string selects) and Message.Attachment parameters (from file uploads) are now supported in modal handlers
  • Modal#await() now throws ModalTimeoutException instead of TimeoutCancellationException

Components

  • await() now throws ComponentTimeoutException instead of TimeoutCancellationException
  • await() throws RemovedComponentException when the component is removed while it is awaited

Method accessors

  • BotCommands#preferClassFileAccessors was moved to MethodAccessorsConfig

Localization

  • Locales are evaluated lazily

Fixes

Components

  • Fixed checking PostgreSQL driver version

Application commands

  • Fixed global commands sometimes unnecessarily updating when using database-backed cache

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.8...v3.0.0-beta.9


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.9")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.9</version>
</dependency>

v3.0.0-beta.8 | Safe localization module, command improvements and fixes

22 Jan 18:31
3e12892

Choose a tag to compare

JDA

Overview

Added a safer localization module, removed superclass requirements of annotated commands and fixed stuff.

New module with much safer localization (#237)

A new incubating module has been added to enable you more pre-emptive checks for your localization needs!

It allows you to define interfaces to retrieve your messages, meaning cleaner commands, less chance to misspell something, and much, much earlier error messages if something isn't configured correctly.

See the README for more details.

Split and deprecate ApplicationCommand and TextCommand (#252)

This removes the requirement of extending ApplicationCommand/TextCommand by splitting them in optional interfaces for each feature.

Deprecations

  • Deprecated ApplicationCommand and TextCommand

Changes

  • Split ApplicationCommand into optional interfaces
    • SlashOptionChoiceProvider
    • ApplicationGeneratedValueSupplierProvider
  • Split TextCommand into optional interfaces
    • TextCommandHelpConsumer
    • TextGeneratedValueSupplierProvider

New features

Introspection

  • Added method, declaringKClass and declaringClass to Executable

Event listeners

  • Added support for lists and lazy services in event listener parameters

Misc

  • Added support for Kotlin 2.3.0
    • Haven't updated to it yet because of some (rare) reflection bugs

Deprecations

Text commands

  • Deprecated and split HelpBuilderConsumer#accept into two methods
    • acceptGlobal
    • acceptCommand

Changes

Dependencies

  • Updated to JDA 6.3.0
  • Updated to Caffeine 3.2.3
  • Updated to ClassGraph 4.8.184
  • Updated to JEmoji 1.7.5
  • Updated to Spring Boot 3.5.8 and Spring Framework 6.2.14
    • It will likely not get updated to Spring Boot 4, however, this library is compatible with it, you can upgrade it on your project with no issue

Built-in DI

  • @Dependencies, @ConditionalService and custom @Condition annotations are now searched on supplied services
    • Supplied services are those added at runtime, will not affect anyone

Annotated commands

  • Removed exception thrown when both @TopLevelSlashCommandData and @SlashCommandData had a description (on a top-level command)
    • @TopLevelSlashCommandData will get prioritized instead

Interactions

  • Events of external components and modals are now logged on the DEBUG level

Interaction filters

  • Filters that do not acknowledge the interaction are now logged on the WARN level

Fixes

Annotated application commands

  • Fixed @DeclarationFilter being applied incorrectly

Built-in DI

  • Fixed initialization exceptions not interrupting program startup when using ClassFile-based method accessors

Misc

  • Fixed building message with pre-CV2 content when the Components V2 flag is enabled by default

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.7...v3.0.0-beta.8


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.8")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.8</version>
</dependency>

v3.0.0-beta.7 | Modal file uploads

18 Oct 20:35
eaabac3

Choose a tag to compare

JDA

Overview

This release primarily adds support for file uploads in modals.

Creating a Modal accepting file uploads

Kotlin
modals.create("modal-id") {
    label("Banner image") {
        child = AttachmentUpload("banner-file")
    }
}
Java
modals.create("modal-id")
  .addComponents(Label.of("Banner Image", AttachmentUpload.of("banner-file")))
  .build()

Using the uploaded file

If you use @ModalHandler, you can add a @ModalInput parameter with a List<Message.Attachment> type.

@ModalHandler(name = "modal-id")
fun onModal(event: ModalEvent, @ModalInput("banner-file") bannerAttachments: List<Message.Attachment>) { ... }

If you use coroutines, you can use modalEvent[attachmentUpload] instead.

val bannerFileComponent = AttachmentUpload("banner-file")

val modal = modals.create("modal-id") {
    label("Banner image") {
        child = bannerFileComponent
    }
}

// Reply with the modal 

val event = modal.await()
val bannerFile = event[bannerFileComponent].asAttachmentList.single()

Changes

Dependencies

  • Updated to JDA 6.1.0
  • Updated to Kotlin 2.2.20

jda-ktx

  • Added customId to [Type]SelectMenu and TextInput DSLs

Fixes

jda-ktx

  • Fixed Label DSL not checking if a label was set

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.6...v3.0.0-beta.7


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.7")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.7</version>
</dependency>

v3.0.0-beta.6 | Components V2 and new modal components

16 Sep 11:59
35feea1

Choose a tag to compare

JDA

Overview

This release updates to JDA 6 and adds support for Components V2 as well as new modal components such as text displays, labels and select menus.

Components V2 (#233)

Please refer to the JDA 6.0.0-rc.1 release for details on this feature.

Deprecations

  • UsedComponentSet#setComponents(Iterable) was deprecated
    • Replaced by setComponents(ComponentTree)

New features

  • Added deleteTree in services which can create components (Buttons/SelectMenus)

Kotlin extensions

Several factory functions were added:

  • ActionRow
  • Container
  • FileDisplay
  • MediaGallery
  • MediaGalleryItem
  • Section
  • Separator
  • TextDisplay
  • Thumbnail

Additionally, functions were added in inline builders to directly insert components where they can:

  • actionRow
    • linkButton
  • container
  • fileDisplay
  • mediaGallery
    • item
  • section
  • separator
  • text

For example,

val message = MessageCreate {
    components += Container { /* */ }
}

can also be written as

val message = MessageCreate {
    container { /* */ }
}

Note: These functions are available only in components which accept multiple child components (ActionRow, Container, Section content), for fields such as the accessory of Section, you will need to set the component manually.


Labels and string select menus in modals (#242)

Alongside with the new JDA additions, instead of having "input names" to match with your handler's @ModalInput, you can now use the native custom ID, note that it must be unique per modal.

Adding a text input, a label or a string select menu, now only uses the native JDA components.

See the JDA 6.0.0-rc.4 release for more details.

Example changes:

@Command
public class SlashFormat extends ApplicationCommand {

    private static final String MODAL_NAME = "SlashFormat: formatModal";
-   private static final String CODE_INPUT_NAME = "SlashFormat: formatModal codeInput";
+   private static final String CODE_INPUT_ID = "SlashFormat: formatModal codeInput";

    private final Modals modals;

    public SlashFormat(Modals modals) {
        this.modals = modals;
    }

    @JDASlashCommand(name = "format")
    public void onSlashFormat(GuildSlashEvent event) {
        Modal modal = modals.create("Format your code")
                .bindTo(MODAL_NAME)
                .addComponents(
-                       modals.createTextInput(CODE_INPUT_NAME, "Code", TextInputStyle.SHORT)
+                       Label.of(
+                               "Code",
+                               TextInput.create(CODE_INPUT_ID, TextInputStyle.SHORT).build()
+                       )
                )
                .build();

        event.replyModal(modal).queue();
    }

    @ModalHandler(MODAL_NAME)
-   public void onFormatModal(ModalEvent event, @ModalInput(CODE_INPUT_NAME) String code) {
+   public void onFormatModal(ModalEvent event, @ModalInput(CODE_INPUT_ID) String code) {
        // ...
    }
}

You can see a more complete example in the "Entity select menus and text displays in modals" section.

Breaking changes

  • (Kotlin only) name of @ModalInput has been updated to customId
  • Removed custom TextInputBuilder
    • Use TextInput.create (Java) or TextInput(...) { ... } (Kotlin) instead
    • The given custom ID will be used to match against @ModalInput parameters

New features

  • @ModalInput(...) List<String> parameters can now be resolved
  • Added Kotlin DSLs:
    • Modals (Modals#create(...) { ... })
    • Labels (Label(...) { ... })
    • Text inputs (TextInput(...) { ... })
    • String select menus (StringSelectMenu(...) { ... })

Entity select menus and text displays in modals

Similarly to string select menus, entity select menus can now be added to modals using the native JDA component, the same can be said for text displays.

Please see the JDA 6.0.0-rc.5 release for more details.

Here is an example modal using text inputs, text displays, labels, string select menus and entity select menus:

Modal example
Kotlin example
private const val MODAL_NAME = "request role"
private const val INPUT_REASON = "reason"
private const val INPUT_ROLE = "role"
private const val INPUT_DETAILS = "details"

@Command
class SlashRequestRole(private val modals: Modals) {

    @JDASlashCommand(name = "request_role", description = "Request a role")
    fun onSlashRequestRole(event: GuildSlashEvent) {
        val modal = modals.create("Role Request Form") {
            text(
                """
                    ### Welcome!
                    Please read the following before continuing:
                    1. Select the role you wish to get
                    2. Select the reason why you want this role
                    3. (Optional) Add any detail about your request
                    
                    -# Abuse of this system may result in penalties
                """.trimIndent()
            )

            label("Role") {
                child = EntitySelectMenu(INPUT_ROLE, SelectTarget.ROLE)
            }

            label("Reason") {
                child = StringSelectMenu(INPUT_REASON) {
                    option("It looks cool!", "cool")
                    option("I like the color", "color")
                    option("I am interested in the relevant discussions", "discussions")
                }
            }

            label("Details") {
                child = TextInput(INPUT_DETAILS, TextInputStyle.PARAGRAPH, isRequired = false)
            }

            bindTo(MODAL_NAME)
        }

        event.replyModal(modal).queue()
    }

    @ModalHandler(MODAL_NAME)
    fun onRequestRoleModal(
        event: ModalEvent,
        @ModalInput(INPUT_REASON) reason: List<String>,
        @ModalInput(INPUT_ROLE) roles: List<Role>,
        @ModalInput(INPUT_DETAILS) details: String,
    ) {
        event.reply("Your request has been submitted!")
            .setEphemeral(true)
            .queue()
    }
}
Java example
@Command
public class SlashRequestRole extends ApplicationCommand {

    private static final String MODAL_NAME = "request role";
    private static final String INPUT_ROLE = "role";
    private static final String INPUT_REASON = "reason";
    private static final String INPUT_DETAILS = "details";

    private final Modals modals;

    public SlashRequestRole(Modals modals) {
        this.modals = modals;
    }

    @JDASlashCommand(name = "request_role", description = "Request a role")
    public void onSlashRequestRole(GuildSlashEvent event) {
        var modal = modals.create("Role Request Form")
                .addComponents(
                        TextDisplay.of("""
                                ### Welcome!
                                Please read the following before continuing:
                                1. Select the role you wish to get
                                2. Select the reason why you want this role
                                3. (Optional) Add any detail about your request
                                
                                -# Abuse of this system may result in penalties
                                """),
                        Label.of(
                                "Role",
                                EntitySelectMenu.create(INPUT_ROLE, SelectTarget.ROLE).build()
                        ),
                        Label.of(
                                "Reason",
                                StringSelectMenu.create(INPUT_REASON)
                                        .addOption("It looks cool!", "cool")
                                        .addOption("I like the color", "color")
                                        .addOption("I am interested in the relevant discussions", "discussions")
                                        .build()
                        ),
                        Label.of(
                                "Details",
                                TextInput.create(INPUT_DETAILS, TextInputStyle.PARAGRAPH)
                                        .setRequired(false)
                                        .build()
                        )
                )
                .bindTo(MODAL_NAME)
                .build();

        event.replyModal(modal).queue();
    }

    @ModalHandler(MODAL_NAME)
    public void onRequestRoleModal(
            ModalEvent event,
            @ModalInput(INPUT_ROLE) List<Role> roles,
            @ModalInput(INPUT_REASON) List<String> reason,
            @ModalInput(INPUT_DETAILS) String details
    ) {
        event.reply("Your request has been submitted!")
                .setEphemeral(true)
                .queue();
    }
}

New features

  • @ModalInput parameters can now resolve Mentions and T/List<T> where T is one of: IMentionable, Role, User, InputUser, Member, GuildChannel
  • Added Kotlin DSLs:
    • text(...) in InlineModal
    • EntitySelectMenu(...) { ... } factory

Breaking changes

  • Updated to JDA 6.0.0-rc.5

New features

  • Added Mentions.inputUsers
    • Ret...
Read more

v3.0.0-beta.5

03 Sep 10:04
91eb5dc

Choose a tag to compare

JDA

Bug fix release, please refer to previous release for the changelog.


Changes

  • Removed BotCommands-method-accessor-classfile
    • Can now be optionally included

Bug fixes

  • Fixed assignment of parameters
  • Fixed handling of value class return types

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.4...v3.0.0-beta.5


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.5")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.5</version>
</dependency>

v3.0.0-beta.4

02 Sep 18:39
ef70908

Choose a tag to compare

JDA

Replaced jda-ktx with a new module (#239)

Removes jda-ktx and introduces a new BotCommands-jda-ktx module, this is done for a few reasons:

  1. A significant part of it is unused, because the framework already provides the functionality in a similar way, such as creating commands, components and modals
  2. It depends on JDA, meaning we can't upgrade to a new major JDA version without also updating jda-ktx, and in some cases it forces us to use Jitpack for it, we don't want that
  3. Along with the previous point, adding utilities is faster if we maintain it ourselves

This will no longer include jda-ktx transitively, you are recommended to migrate, but if you choose to add it back, be aware that functions relying on CoroutineEventManager, such as JDA#await/listen will no longer work.

Please look at the README for more details.

Differences with jda-ktx

Changes to the CoroutineEventManager

The core module includes its own event manager, you can configure its default timeout at BEventManagerConfig#defaultTimeout, and the CoroutineScope in BCoroutineScopesConfig#eventManagerScope.

As a result, extensions from jda-ktx relying on its CoroutineEventManager no longer work, but you can fix this by importing the extension from this module.

You can still register CoroutineEventListeners (the one from BotCommands-core, not jda-ktx!) if required.

Changed functionalities

If you decide to switch, some functions have replacements:

  • awaitMessage must now be used on an EventWaiter instance
  • awaitButton is now Button#await (the framework's Button class)
  • jda-ktx's Paginator is replaced by the core Paginators

Incompatible functionalities

If you keep using jda-ktx, some functions will not work or behave unexpectedly:

  • scope on JDA/ShardManager
  • Any function related to build JDA or shard managers, it is recommended you use the helper functions in JDAService.

Missing functionalities

Additionally, jda-ktx has additional extensions that were not ported:

  • String#toEmoji()
  • String#toCustomEmoji()
  • String#toUnicodeEmoji()
    • It is recommended to use jda-emojis's UnicodeEmojis class (included by default)
  • getDefaultScope
    • Replaced with namedDefaultScope
  • All extensions already handled by the framework, such as creating/listening to commands, components and modals
  • The WebhookAppender
  • named, String#invoke and some into extensions from messages/utils.kt
  • OkHttp's Call extensions awaitWith and await
  • SLF4J logger delegation (private val logger by SLF4J)
    • I recommend using kotlin-logging instead (private val logger = KotlinLogging.logger { })
    • The Logging class may also be of interest
  • ref extensions on entities
    • I don't recommend using them because while they keep entities up to date between reconnects, they don't prevent you from sending requests to deleted entities

Please open an issue if you feel like one of these extensions are worth porting, an alternative is to port them locally.

Migrating

You can apply an OpenRewrite recipe to change all relevant imports, note that this could still require you to do some changes after it.

Before migrating, your codebase must compile, so you must not update any versions yet.

Make sure you have committed your current changes, or make a back-up of your project.

Registering the recipe

Note

This will log warnings for Kotlin sources, but the recipes still work fine.

(Kotlin) Gradle
plugins {
    // ...
    id("org.openrewrite.rewrite") version "7.11.0"
}

repositories {
    // ...
    maven("https://jitpack.io")
}

dependencies {
    // Existing dependencies, DO NOT UPDATE THEM YET
    // ...

    rewrite("io.github.freya022:BotCommands-jda-ktx:{{NEW_VERSION}}")
    rewrite("org.openrewrite.recipe:rewrite-java-dependencies:1.37.0")
}

rewrite {
    // Use 'dev.freya02.MigrateToBcJdaKtx' if you want to migrate from jda-ktx (recommended)
    // Use 'dev.freya02.MigrateFromBcCoreToBcJdaKtx' if you want to keep using jda-ktx
    activeRecipe("dev.freya02.MigrateToBcJdaKtx")
}

Checking changes (dry run)

Run the rewriteDryRun task, this can be done by pressing CTRL twice on IntelliJ then running gradle rewriteDryRun.
This will generate a diff file at build/reports/rewrite/rewrite.patch, you can check the possible changes there.

Applying changes

Run the rewriteRun task.

Maven
  1. Add the following repository:
<repository>
    <id>jitpack</id>
    <url>https://jitpack.io</url>
</repository>
  1. Add the following plugin:
<plugin>
  <groupId>org.openrewrite.maven</groupId>
  <artifactId>rewrite-maven-plugin</artifactId>
  <version>6.13.0</version>
  <configuration>
    <activeRecipes>
      <!-- Use 'dev.freya02.MigrateToBcJdaKtx' if you want to migrate from jda-ktx (recommended) -->
      <!-- Use 'dev.freya02.MigrateFromBcCoreToBcJdaKtx' if you want to keep using jda-ktx -->
      <recipe>dev.freya02.MigrateToBcJdaKtx</recipe>
    </activeRecipes>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.openrewrite.recipe</groupId>
      <artifactId>rewrite-java-dependencies</artifactId>
      <version>1.37.0</version>
    </dependency>
    <dependency>
      <groupId>io.github.freya022</groupId>
      <artifactId>BotCommands-jda-ktx</artifactId>
      <version>{{NEW_VERSION}}</version>
    </dependency>
  </dependencies>
</plugin>

Checking changes (dry run)

Run the rewrite:dryRun goal, this can be done by pressing CTRL twice on IntelliJ then running mvn rewrite:dryRun.
This will generate a diff file at target/site/rewrite/rewrite.patch, you can check the possible changes there.

Applying changes

Run the rewrite:run goal.

You can then update BotCommands-core and add BotCommands-jda-ktx, if you do use it.

It is recommended to optimize imports (Code | Optimize imports in IntelliJ) after migrating.

Notes

Breaking changes

  • Removed ICoroutineEventManagerSupplier
    • If you want to configure the default timeout, set BEventManagerConfig#defaultTimeout
    • If you want to configure the coroutine scope, set BCoroutineScopesConfig#eventManagerScope
  • Removed the jda-ktx api dependency
    • You can add it back if you want, but I'd recommend migrating to BotCommands-jda-ktx

New Features

  • Added CoroutineEventListener
  • Ported part of jda-ktx to BotCommands-jda-ktx
  • Added more extensions, see the readme

Changes

  • Moved JDA extensions from the core modules to BotCommands-jda-ktx
    • Deprecated accessors were made to help migrate
  • Extensions for RestAction, RestResult and related, which have vararg parameters, now require at least 1 argument

Added generate method accessors (#241)

For Java 24+ users, this feature allows using improved method calls (event listeners, commands and service initialization),
reducing the size of stack traces in exceptions and in your debugger, as well as slightly improved performance.

More technical details are in the README.

New features

  • Added BotCommand.preferClassFileAccessors()

Breaking changes

  • Replaced jda-ktx with a new module (#239)

New features

  • Added generate method accessors (#241)

Changes

  • Added missing static methods for function and properties in objects
  • Added missing overloads using Java reflection (instead of Kotlin reflect)
  • Added missing overloads using Java durations (instead of Kotlin durations)
  • Removed data modifier from TimeoutInfo

Bug fixes

  • BCServiceContainer can now be injected
  • Unknown event types no longer log twice per function

Don't hesitate to check out the examples and the wiki.

Full Changelog: https://github.com/freya022/BotComm...

Read more

v3.0.0-beta.3

22 Jul 15:46
21a46a6

Choose a tag to compare

JDA

Added BotCommandsMessages and PermissionLocalization (#236)

DefaultMessages and DefaultMessagesFactory are deprecated in favor of:

  • BotCommandsMessages for the messages used by the framework
  • PermissionLocalization for DefaultMessage#getPermission

Deprecation process

If a non-default configuration of DefaultMessages is detected, the auto-configured BotCommandsMessagesFactory instance will delegate to it instead, and you will see a warning about the deprecation.

Differences

BotCommandsMessages is similar to DefaultMessages, however:

  • The template keys have been changed as to allow nesting in some cases
  • Each method returns a MessageCreateData instead of a String, allowing you to fully customize the responses (such as by using Components V2 👀)
  • The method names were shortened

The default strings were unchanged.

Migrating

If you made DefaultMessages[language].json files, you will need to replace DefaultMessages by BotCommandsMessages, then migrate the keys to the new ones found in BotCommandsMessages-default.json.


Breaking changes

Modules

  • Spring support was moved to a separate BotCommands-spring artifact

Dependencies

  • Some compile dependencies are no longer included transitively:

    You do not need to depend on them unless your code compiles against them in your project

  • Optional dependencies are no longer in the published POM, this does not affect your project at all

Rate limiting

  • Generics were removed from RateLimitHandler methods

Deprecations

Default DI

  • Deprecated DefaultServiceContainer, renamed to BCServiceContainer

Changes

Modules

  • The BotCommands artifact will be split in more submodules, those new modules will still be included transitively

Slash commands

  • Allows vararg parameters to be received with 0 required options (#234)

Text commands

  • Enforce at least 1 required option when using varargs (#234)

Core configuration

  • JDAService#getDefaultRestConfig() now appends a link to itself in the HTTP User-Agent

Extensions

  • Some extensions had a wrong contract with the block specified as being called EXACTLY_ONCE, this has been corrected to AT_MOST_ONCE

    • runCatchingResponse
    • runIgnoringResponse
    • runIgnoringResponseOrNull
    • runCatchingRest

    See c4deec1152 for more details

Dependencies

  • Updated Kotlin to 2.2.0
  • Updated JDA to 5.6.1
  • Updated Jackson to 2.19.1

New features

Components

  • Added ButtonFactory#toLabelButton() (e.g. buttons.primary("Page 1/5").toLabelButton())
    • Allows creating disabled buttons for display purposes

Default DI

  • Added @ConditionalOnMissingService

Reflection

  • Added ClassGraphProcessorProvider
    • This is an SPI returning ClassGraphProcessor instances at startup, mainly used by other modules
    • Is opt-in via @ExperimentalReflectionApi

Bug fixes

Default DI

  • Fix BServiceConfig#serviceSupplier not being used
  • Fix supplied services being unable to be retrieved by their primary type

Database

  • Fix DBResult's iterator not fetching values when hasNext() was not called

Rate limiting

  • Don't attempt to delete rate limit message if the channel was deleted

Don't hesitate to check out the examples and the wiki.

Full Changelog: v3.0.0-beta.2...v3.0.0-beta.3


Installation

As a reminder, the minimum Java version supported is Java 17.

Kotlin Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.freya022:BotCommands:3.0.0-beta.3")
}

Maven

<dependency>
    <groupId>io.github.freya022</groupId>
    <artifactId>BotCommands</artifactId>
    <version>3.0.0-beta.3</version>
</dependency>