Giter Site home page Giter Site logo

freya022 / botcommands Goto Github PK

View Code? Open in Web Editor NEW
55.0 2.0 5.0 6.38 MB

A JDA command framework (& much more) which helps to develop your bots faster

Home Page: https://freya022.github.io/BotCommands/

License: Mozilla Public License 2.0

Java 10.30% Kotlin 89.70%
jda discord bot framework java slash-commands commands eventwaiter button discord-api discord-bot command-api jda-command-api annotations autocomplete modal components kotlin pagination

botcommands's Introduction

BotCommands logo

BotCommands version JDA version Snapshots

Discord invite Wiki home

BotCommands

A Kotlin-first (and Java) framework that makes creating Discord bots a piece of cake, using the JDA library.

Features

The framework being built around events and dependency injection, your project can take advantage of that and avoid passing objects around, while also easily being able to use services provided by the framework.

Commands

  • Automatic registration of commands, resolvers, services, etc... with full dependency injection
  • Text commands (annotated or manually declared), either with:
    • Automatic token parsing into your parameters
      • Suppose the prefix is ! and the command is ban
        @JDATextCommandVariation(name = "ban")
        fun onTextBan(event: BaseCommandEvent,
                      @TextOption user: User,
                      @TextOption timeframe: Long,
                      @TextOption unit: TimeUnit, // A resolver is used here
                      @TextOption reason: String) {
            //Ban the user
        }
      • Which can be used as: !ban @freya02 7 days Get banned
    • Manual token consumption
  • Application commands (annotated or DSL-declared)
    • Slash commands with automatic & customizable argument parsing
      • Supports choices, min/max values/length, channel types and autocomplete
      • Options can be grouped into objects
    • Context menu commands (User / Message)
    • Automatic, smart application commands registration

Components and modals

  • Unlimited data storage for components, with persistent and ephemeral storage
  • Both modals and persistent components have a way to pass data

Event handlers

  • Custom (annotated) event handlers, with priorities and async

Localization

  • Entirely localizable, from the command declaration to the bot responses

Dependency injection

  • Loads everything and passes objects automatically
  • Can create custom conditions to disable services/commands at startup
  • Can be replaced with Spring IoC

Utilities

  • A PostgreSQL (and H2) database abstraction, with logged queries
  • An event waiter with (multiple) preconditions, timeouts and consumers for every completion state
  • Message parsers (tokenizers, see RichTextParser) and emoji resolvers (turning :joy: into ๐Ÿ˜‚)
  • Paginators and menus of different types (using components!)

And way more features!

Getting Started

You are strongly recommended to have some experience with Kotlin (or Java), OOP, JDA and Dependency Injection basics before you start using this library.

Prerequisites

  • An OpenJDK 17+ installation
  • A competent IDE (I recommend IntelliJ IDEA, you can't go wrong with it in Java & Kotlin, + Live Templates)
  • (Recommended, only Java) Enable method parameters names, please refer to the wiki page
  • (Recommended) Use HotswapAgent in development, to avoid restarting too often
  • (Recommended) Use stacktrace-decoroutinator, to get clearer stack traces in suspending code
    • Each bot template has it enabled in their main class

You can then head over to the wiki to get started either using a bot template, or from a new project.

Getting the library

BotCommands on maven central

Maven

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

Gradle

repositories {
    mavenCentral()
}

dependencies {
    implementation 'io.github.freya022:BotCommands:VERSION'
}

Alternatively, you can use Jitpack to use snapshot versions, you can refer to the JDA wiki for more information.

Sample usage

Here is how you would create a slash command that sends a message in a specified channel.

Kotlin
@Command
@RequiresComponents // Disables the command if components are not enabled
class SlashSay(private val buttons: Buttons) : ApplicationCommand() {
    @JDASlashCommand(name = "say", description = "Sends a message in a channel")
    suspend fun onSlashSay(
        event: GuildSlashEvent,
        @SlashOption(description = "Channel to send the message in") channel: TextChannel,
        @SlashOption(description = "What to say") content: String
    ) {
        event.reply_("Done!", ephemeral = true)
            .deleteDelayed(event.hook, 5.seconds)
            .queue()
        channel.sendMessage(content)
            .addActionRow(buttons.danger(EmojiUtils.resolveJDAEmoji("wastebasket")).ephemeral {
                bindTo { buttonEvent ->
                    buttonEvent.deferEdit().queue()
                    buttonEvent.hook.deleteOriginal().await()
                }
            })
            .await()
    }
}
Kotlin (DSL)
@Command
@RequiresComponents // Disables the command if components are not enabled
class SlashSay(private val buttons: Buttons) : GlobalApplicationCommandProvider {
    suspend fun onSlashSay(event: GuildSlashEvent, channel: TextChannel, content: String) {
        event.reply_("Done!", ephemeral = true)
            .deleteDelayed(event.hook, 5.seconds)
            .queue()
        channel.sendMessage(content)
            .addActionRow(buttons.danger(EmojiUtils.resolveJDAEmoji("wastebasket")).ephemeral {
                bindTo { buttonEvent ->
                    buttonEvent.deferEdit().queue()
                    buttonEvent.hook.deleteOriginal().await()
                }
            })
            .await()
    }

    override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
        manager.slashCommand("say", function = ::onSlashSay) {
            description = "Sends a message in a channel"

            option("channel") {
                description = "Channel to send the message in"
            }

            option("content") {
                description = "What to say"
            }
        }
    }
}
Java
@Command
@RequiresComponents // Disables the command if components are not enabled
public class SlashSay extends ApplicationCommand {
    private final Buttons buttons;
  
    public SlashSay(Buttons buttons) {
        this.buttons = buttons;
    }

    @JDASlashCommand(name = "say", description = "Sends a message in a channel")
    public void onSlashSay(
            GuildSlashEvent event,
            @SlashOption(description = "Channel to send the message in") TextChannel channel,
            @SlashOption(description = "What to say") String content
    ) {
        event.reply("Done!")
                .setEphemeral(true)
                .delay(Duration.ofSeconds(5))
                .flatMap(InteractionHook::deleteOriginal)
                .queue();

        final Button deleteButton = buttons.danger(EmojiUtils.resolveJDAEmoji("wastebasket")).ephemeral()
                .bindTo(buttonEvent -> {
                    buttonEvent.deferEdit().queue();
                    buttonEvent.getHook().deleteOriginal().queue();
                })
                .build();
        channel.sendMessage(content)
                .addActionRow(deleteButton)
                .queue();
    }
}

Examples

You can find a number of feature demonstrations in the examples.

Debugging tips

  • Enable the debug/trace logs in your logback.xml file, for a logging tutorial you can look at the wiki's logging page
  • Look at the switches in BDebugConfig

Live templates

IntelliJ IDEA users can use live templates provided in this zip file, helping you make commands and other handlers with predefined templates, for both Kotlin and Java, keeping a consistent naming scheme and acting as a cheatsheet.

For example, if you type slashCommand in your class, this will generate a slash command and guide you through the declaration.

A list of live template can be found in Settings > Editor > Live Templates, in the BotCommands 3.X - [Language] group.

For an installation guide, you can follow this guide from JetBrains.

Support

Don't hesitate to join the support server if you have any question!

Contributing

If you want to contribute, make sure to base your branch on 3.X, and create your PR from it.

It would be appreciated to focus on improving the documentation, such as the wiki, the library documentation, or by creating examples.
Maintainers will focus on bug reports and feature requests, which you can create issues for.

Read the contributing guide for more details.

botcommands's People

Contributors

dependabot[bot] avatar freya022 avatar oxkitsune avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

botcommands's Issues

Add target-specific filters for text/application/component interactions

Extend command filters, to allow applying them on specific commands.

Global filters must be sorted by their service priority.
Global filters cannot be referenced.

Command DSLs would allow for complex filters using filters += (filter<AdminOnly>() or (filter<ModOnly>() and filter<OwnerOnly>())) and filter<InVoiceChannel>() for example

Annotation would be @Filter(classes) with the services implementing the filters

Components have the same usage as with command DSLs, but requires storing the filters FQCN in the database

Messages containing only the mention-as-prefix should be ignored

java.lang.IllegalArgumentException: Path component must match regex ^[\w-]+$. Provided: "<@921044182552969246>"
    at net.dv8tion.jda.internal.utils.Checks.check(Checks.java:69)
    at net.dv8tion.jda.internal.utils.Checks.matches(Checks.java:181)
    at com.freya02.botcommands.api.commands.CommandPath.of(CommandPath.java:34)
    at com.freya02.botcommands.internal.commands.prefixed.TextCommandsListener$onMessageReceived$3.invokeSuspend(TextCommandsListener.kt:72)
    at dev.reformator.stacktracedecoroutinator.stdlib.StdlibKt.decoroutinatorResumeWith$lambda$1(stdlib.kt:36)
    at dev.reformator.stacktracedecoroutinator.stdlib.StdlibKt.decoroutinatorResumeWith(stdlib.kt:127)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
    at java.base/java.lang.Thread.run(Thread.java:1623)

Add `runCatchingResponse`

This should allow users to run code which throws certain error responses

The top level function should return Result<Unit> as we cannot recover any data, extensions to Result<Unit> will "recover" the Result (suppress the exception), while still wanting to use Result#getOrThrow to notify the caller of unrelated exceptions

The goal would be to somewhat replicate JDA's ErrorHandler, typical use case is sending a DM, while handling/ignoring only CANNOT_SEND_TO_USER and rethrowing other exceptions/error responses

Separate Java and Kotlin bot templates

Careful to give links to Java variants in READMEs

Environment#folder should be the current working directory

While the examples will remain in Kotlin, examples used in the Wiki should be in Java too

Mentions in Arguments return as U:Name(ID)

When I was setting up a command to work with mentions the arguments return the mention as U:MistyyBoi(635005205104164875) which makes it hard to use the ID to find the member in the guild.
image

DefaultComponentManager with MariaDB

i test it with PostgresSQL and it's working, but when i use MariaDB (with HikariCP) i got error message and stopping when generating table "version"

java.sql.SQLSyntaxErrorException: (conn=31) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'drop sequence if exists group_seq cascade;

create table if not exists Versio...' at line 2
        at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:282)
        at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:370)
        at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:134)
        at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:883)
        at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:822)
        at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:741)
        at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:665)
        at org.mariadb.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:92)
        at org.mariadb.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:271)
        at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
        at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
        at com.freya02.botcommands.api.components.DefaultComponentManager.resetTables(DefaultComponentManager.java:467)
        at com.freya02.botcommands.api.components.DefaultComponentManager.setupTables(DefaultComponentManager.java:431)
        at com.freya02.botcommands.api.components.DefaultComponentManager.<init>(DefaultComponentManager.java:56)
        at saha.Main.main(Main.java:45)

Update live templates

Live templates:

  • autocomplete: Annotated autocomplete method
  • buttonListener: Annotated listener method
  • selectListener: Annotated listener method
  • eventListener: Annotated listener method
  • logger: Uses Logging for Java, KotlinLogger for Kotlin

File templates:

  • Service (Java/Kotlin)
  • Condition annotations (Java/Kotlin)
  • Text command (Java/Kotlin/DSL)
  • Slash/user/message command (Java/Kotlin/DSL)

Add builder pattern for components

Delegated interfaces could have an instance property of type T

Delegates do not have access to the implementation as the delegates are in their own world

Kotlin does not support this in super constructors or in delegates, so we can use a class which holds our instance, the implementation's init block sets the instance, so it is accessible when the user actually gets its hands on the builder

How do you customize the help command?

How do you customize the help command, I've read over the docs several and I might've missed if it was documented, but if it isn't, is there a supported way to edit the help command or do I need to fork the repo and make changes?

Add a way to get a list of mentions from a STRING option

Slash parameter resolvers for IMentionable as well as their subtypes would be required

An annotation could be used, so the resolvers (existing ones transformed to resolver factories) can read the annotation and return the appropriate OptionType (STRING instead of [entity type])

Note: this does not require varargs, but the parameter type might need not to be List as it could be confusing and be considered as a vararg. Needs to be checked

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.