Coder Social home page Coder Social logo

koply / kcommando Goto Github PK

View Code? Open in Web Editor NEW
48.0 3.0 7.0 331 KB

Annotation-based multifunctional command handler framework for JDA & Javacord.

License: GNU General Public License v3.0

Java 100.00%
command-handler jda-bot jda-discord-bot jda-utilities javacord-api java discord-bot discord-api javacord jda

kcommando's Introduction

Language grade: Java Build Status jitpack-version LICENSE

Annotation-based multifunctional command handler framework for JDA & Javacord. KCommando has a external plugin system.

Features

All these features have a modular structure and you can edit all of these modules and integrate them for your projects.

  1. Integrations
  2. Creating Slash Command
  3. Handling Buttons
  4. Creating Classic Commands
  5. Parameterized Constructors
  6. Command Features
  7. Cool Features
  8. How To Install
  9. Example Projects

KCommando Integrations

Integration Usage For JDA

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.

How To Create A Slash Command

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();
        
    }
}

How To Handle Buttons

package com.example.mybot.buttons;

public class Hello {
    
    @HandleButton("buttonHello")
    public void helloButton(ButtonInteractionEvent e) {
        // ...
    }
    
    @HandleButton("processData")
    public void processor(ButtonInteractionEvent e) {
        // ...
    }
    
}

How To Create A Classic Command

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"}

How To Use Parameterized Constructor

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); // <--------
    }
}

Command Features

Possible Command Methods

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)

Properties of the args and prefix parameters

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: "!"

Cool Features

How To Use Suggested Commands

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();
    }

}

How To Use Custom Prefixes

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.

Cron Service

KCommando has a minute-based async CronService and you can use it.

CronService.getInstance().addRunnable(() -> {
	// do stuff
}, 5); /* every 5 minutes */

How To Install

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.

With Maven:

<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>

With Gradle:

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.

Example Repositories

| Rae Discord Bot

Don't be afraid to contribute!

kcommando's People

Contributors

koply avatar megacrafter avatar reina-39 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

Watchers

 avatar  avatar  avatar

kcommando's Issues

Option throws error when not a string type

Describe the bug
When you make an option other than type string, it will throw an error

To Reproduce
Add an option to any slash command with type User or Integer (didn't test other ones)

Expected behavior
Not throw an error and proceed on initialization

Screenshots

Exception in thread "main" java.lang.IllegalArgumentException: Cannot add string choice for OptionType.USER
        at net.dv8tion.jda.api.interactions.commands.build.OptionData.addChoice(OptionData.java:926)
        at me.koply.kcommando.integration.impl.jda.JDAIntegration.registerSlashCommand(JDAIntegration.java:90)
        at me.koply.kcommando.boot.KInitializer.registerSlashBox(KInitializer.java:77)
        at me.koply.kcommando.boot.KInitializer.registerBoxWithInstance(KInitializer.java:124)
        at me.koply.kcommando.boot.KInitializer.registerBox(KInitializer.java:146)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
        at me.koply.kcommando.boot.KInitializer.build(KInitializer.java:52)
        at me.koply.kcommando.KCommando.build(KCommando.java:52)
        at dev.tiertests.Main.main(Main.java:91)

Versions
JDA: 5.0.0-beta.21
Reflections8: 0.11.5
KCommando: 5.1.0

Additional context

Verbose logging triggers wrongly

Describe the bug
Verbose logging fires incorrectly and logs messages about methods not being annotated, even though they are annotated.

To Reproduce
Steps to reproduce the behavior:

  1. Create a slash command class
public class Ping {
    @HandleSlash(name = "ping", desc = "Ping the bot")
    public static void pingCommand(SlashCommandCreateEvent event) {
        event
            .getSlashCommandInteraction()
            .createImmediateResponder()
            .setContent("Pong!")
            .respond();
    }
}
  1. Enable verbose logging in KCommando configuration.
  2. Annotate with HandleSlash
  3. Execute the project
  4. See The skipped methods at bot_test.commands.slash.Ping: (They don't have any appropriate annotation)

Expected behavior
It shouldn't log this message unless it is wrong. (Not annotated)

Versions
Your current JDA, Reflections8 and KCommando versions.
Javacord 3.8.0
KCommando 5.1.0
Reflections8: N/A

Button only for one user.

Is your feature request related to a problem? Please describe.
No

Describe the solution you'd like
I would like to handle buttons only for the person for whom the button was created.

Additional context
Easiest I think will be to solve it like this @HandleButton(customButtonId, userId)

Case Sensivity Issue

Describe the bug
Commands with camel case aliases doesn't work.

To Reproduce
Steps to reproduce the behavior:

  1. Create a command with aliases "embedTest" or something like that
  2. Use command as "embedTest", it won't work. It will work as "embedtest".

Expected behavior
Command should work with both usages.

Screenshots
image

Versions
JDA 4.2.0 227, KCommando 4.2.6

Guild-Prefix preservence

Hey you got a really nice and intressting project here.

Since i don't find a discord or anything else to ask you i am using this.

When using your libary, with Integration#addCustomPrefix(), will it saved preserved or do i need to store the prefixes somewhere and on Application Boot, set the Prefixes myself?

TODO

Main based case sensivity command usage.
Command based case sensivity command usage.
Command description label in CommandUtils for every single commands.
Get membersFromMessage util method for CommandUtils.

Ability to create subcommands

Is your feature request related to a problem? Please describe.
Not able to create subcommands like you are in JDA. For example:

GuildUtils.getGuild().upsertCommand("manage", "Manage settings")
                .addSubcommands(
                        new SubcommandData("cooldown", "Manage user cooldowns")
                                .addOptions(
                                        new OptionData(OptionType.STRING, "gamemode", "The game mode you want to test the user in", true)
                                                .addChoices(Constants.ALL_GAMEMODE_CHOICES)
                                )
                                .addOptions(new OptionData(OptionType.USER, "user", "The user you want to manage", true))
                                .addOptions(new OptionData(OptionType.STRING, "action", "The action you want to perform", true)
                                        .addChoices(
                                                new Command.Choice("Terminate", "terminate"),
                                                new Command.Choice("Shorten", "Shorten"),
                                                new Command.Choice("Lengthen", "lengthen")
                                        )
                                )
                                .addOptions(new OptionData(OptionType.INTEGER, "amount", "The amount you want to shorten or lengthen the cooldown by", false))
                )

Describe the solution you'd like
Creating a command group on the initialization of the integration, like:

JDAIntegration commandIntegration = new JDAIntegration(jda);
KCommando commando = new KCommando(commandIntegration)
        ......
        .addCommandGroup(new CommandGroup("group 1", "desc for group 1"))

**Describe alternatives you've considered**
Using plain JDA

**Additional context**
None

`HandleSlash` annotation handling contradicts README

Describe the bug

You don't have to identify the guildId. If you don't, it will be a global command.

Contrary to what is stated, the framework logs The Slash Command named as ping is not global. At the same time it doesn't have guildId. This command cannot be register to Discord.
To Reproduce
Steps to reproduce the behavior:

  1. Create a slash command
public class Ping {
    @HandleSlash(name = "ping", desc = "Ping the bot")
    public static void pingCommand(SlashCommandCreateEvent event) {
        event
            .getSlashCommandInteraction()
            .createImmediateResponder()
            .setContent("Pong!")
            .respond();
    }
}
  1. Enable verbose logging
  2. Execute project
  3. See error.

Expected behavior
According to the README, it should automatically register globally since there is no guildId passed into HandleSlash

Versions
Your current JDA, Reflections8 and KCommando versions.
Javacord 3.8.0
KCommando 5.1.0
Reflections8: N/A

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.