Skip to content
This repository was archived by the owner on Jun 7, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Report a bug here to receive help and to help me improve the framework

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. …
2. ….
3. …..

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots/Code**
If applicable, add screenshots to help explain your problem.
Also, add the part of the code that doesn't work.

**System information**
- JDK/JVM version
- CommandAPI version
- JDA version
- (Other dependencies)

**Additional context**
Add any other context about the problem here.
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
54 changes: 34 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# discord-api-command
**A simple Command API for the JDA**
(An API that is not an API but a framework)

CURRENT VERSION: **3.2** <p>
Other versions: **3.1**, **3.0_3**, **3.0_2**, **3.0_1**, **3.0** <p>
CURRENT VERSION: **3.2_01** <p>
Other versions: **3.2**, **3.1**, **3.0_3**, **3.0_2**, **3.0_1**, **3.0** <p>
**[Changelog](https://github.com/JohnnyJayJay/discord-api-command/blob/master/changelog.md)**<br>
**[Documentation](http://docs.johnnyjayjay.me)**

Expand All @@ -17,6 +18,10 @@ Other versions: **3.1**, **3.0_3**, **3.0_2**, **3.0_1**, **3.0** <p>
- prevention of exceptions and errors by substantial validation and exception handling
- error transparency through `CommandSetException`

## Important
This library **requires** an SLF4J implementation and does not provide an own implementation like JDA. Without it, you will not get any logging messages, including
stack traces, information about CommandSettings, warnings and much more.

## On how to add this to your project
### Adding as a library
You can download the .jar-file in [this directory](https://github.com/JohnnyJayJay/discord-api-command/tree/master/builds) and add it to the project
Expand All @@ -26,16 +31,24 @@ You can download the .jar-file in [this directory](https://github.com/JohnnyJayJ
3. Eclipse: Right-click the jar: `Build Path -> Add To Build Path` <p> IntelliJ: Right-click the jar: `Add As Library`
4. Done. You can now use it.

### Adding Dependency in pom
If you use Maven, you can add this library even less complicated: Just add the following dependency in your `pom.xml`:
### Adding Dependency (Maven & Gradle)
For Maven, add this to your `pom.xml`:
```xml
<dependency>
<groupId>com.github.johnnyjayjay</groupId>
<artifactId>CommandAPI</artifactId>
<version>VERSION</version>
</dependency>
<dependencies>
<dependency>
<groupId>com.github.johnnyjayjay</groupId>
<artifactId>CommandAPI</artifactId>
<version>VERSION</version>
</dependency>
</dependencies>
```

For Gradle, add this to your `build.gradle`:
```gradle
dependencies {
compile "com.github.johnnyjayjay:CommandAPI:VERSION"
}
```
And that's it!

## Getting started
### Wrting Commands
Expand Down Expand Up @@ -108,17 +121,17 @@ public class ReportCommand extends AbstractCommand {
// Error message
}

@SubCommand(args = {this.MEMBER_MENTION}, moreArgs = true) // moreArgs: means that there has to be at least one more argument than specified. Useful for the report reason.
@SubCommand(args = {Regex.MEMBER_MENTION}, moreArgs = true) // moreArgs: means that there can be more arguments than specified. Useful for the report reason.
public void onReport(CommandEvent event, Member member, TextChannel channel, String[] args) {
// report the mentioned member
}

@SubCommand(args = {"get", this.MEMBER_MENTION})
@SubCommand(args = {"get", Regex.MEMBER_MENTION})
public void onReportsGet(CommandEvent event, Member member, TextChannel channel, String[] args) {
// get the reports of the mentioned member
}

@SubCommand(args = {"remove", this.MEMBER_MENTION})
@SubCommand(args = {"remove", Regex.MEMBER_MENTION})
public void onReportsRemove(CommandEvent event, Member member, TextChannel channel, String[] args) {
// remove the reports from the mentioned member
}
Expand Down Expand Up @@ -189,6 +202,7 @@ There are a few more features to `CommandSettings`, such as:
- Setting a message that is displayed in case of an unknown command
- Setting a command cooldown (and specifying whether the cooldown should be reset on each execution attempt)
- Setting a Color for `DefaultHelpCommand`
- Adding listeners for Exceptions and unknown commands

### Exceptions
This API should only throw one kind of exception, `CommandSetException` (except for explicitly thrown `IllegalArgumentException`s).
Expand All @@ -197,24 +211,24 @@ If this is **NOT** the case and you get another exception thrown by anything ins
`CommandSetException` is a sub class of `RuntimeException`, meaning that they don't have to be caught and they don't terminate the program.

A `CommandSetException` is thrown if:
- a label or a prefix does not match the requirements, i.e. the regex defined in `CommandSettings.VALID_PREFIX` and `CommandSettings.VALID_LABEL`. This includes:
- prefixes that contain one or more of the characters `\+*^|$?` or are just an empty String
- a label or a prefix does not match the requirements. This includes:
- prefixes that are empty
- labels that contain any kind of blank spaces or are just an empty String
- an instance of `CommandSettings` is activated or deactivated twice (which is not possible)
- any other settings input for `CommandSettings` is invalid

If you don't want to have any exceptions concerning prefixes and labels, it is recommended to check whether they match `CommandSettings.VALID_PREFIX`
or `CommandSettings.VALID_LABEL`.
If you don't want to have any exceptions concerning prefixes and labels, you should check for the prefix not to be empty and for the label to match `Util.VALID_LABEL`.
`com.github.johnnyjayjay.discord.commandapi.Util` is a class that contains some regular expressions as `public static final String`s.

```java
String prefix = // user input or something else you can't verify directly
if (prefix.matches(CommandSettings.VALID_PREFIX)) {
String label = // user input or something else you can't verify directly
if (label.matches(Util.VALID_LABEL)) {
// ...
} else {
// Tell the user
}
```
With sub commands, you can even set `CommandSettings.VALID_PREFIX`/`CommandSettings.VALID_LABEL` as an argument regular expression.
With sub commands, you can even set `CommandSettings.VALID_LABEL` as an argument regular expression (if it ever comes to that).

## Contributing
If you think this framework is missing a feature and you think you're able to write it yourself, fork this repository and go for it.
Expand Down
17 changes: 17 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

### 3.2_01
- Increased performance of CommandListener slightly
- Added configurable Predicate to `CommandSettings` which tests an event before execution. This may be useful for own checks that are not provided by this framework
- Added "listeners" for unknown commands (`CommandSettings#onUnknownCommand(Consumer<CommandEvent>)`) and Throwables (`CommandSettings#onException(BiConsumer<CommandEvent, Throwable>)`)
- Added possibility to configure a custom thread pool (`CommandSettings#useMultiThreading(ExecutorService)`)
- Added configurable messages that are sent in case someone is on cooldown or a command is unknown
- Added possibility to deactivate Exception logging (`CommandSettings#setLogExceptions(boolean)`)
- Added Regex util class (mainly for `AbstractCommand`)
- Added `CommandEvent.Command#getPrefix()` to get the prefix used in a command
- Finally fixed invalid prefixes; any String that is not empty can be a prefix now
- Changed Command parsing
- Adjusted `AbstractCommand`'s code - made it more stream-like
- Fixed bug in `DefaultHelpCommand` that prevented the general help message from working
- Corrected mistake in documentation of `SubCommand#moreArgs()`
- Updated JDA version to 3.8.0_433
- Updated readme

### 3.2
- Updated to JDA version 3.7.1_387
- Adjusted cooldown system: it is now configurable whether the cooldown will reset for each command execution attempt
Expand Down
8 changes: 5 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<groupId>com.github.johnnyjayjay</groupId>
<artifactId>CommandAPI</artifactId>
<packaging>jar</packaging>
<version>3.2</version>
<version>3.2_01-3-SNAPSHOT</version>

<build>
<plugins>
Expand Down Expand Up @@ -56,6 +56,7 @@
<executions>
<execution>
<id>attach-javadocs</id>
<phase>deploy</phase>
<goals>
<goal>jar</goal>
</goals>
Expand Down Expand Up @@ -132,13 +133,14 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>3.7.1_387</version>
<version>3.8.0_433</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
19 changes: 6 additions & 13 deletions src/examples/java/CustomPrefixCommand.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import com.github.johnnyjayjay.discord.commandapi.AbstractCommand;
import com.github.johnnyjayjay.discord.commandapi.CommandEvent;
import com.github.johnnyjayjay.discord.commandapi.CommandSettings;
import com.github.johnnyjayjay.discord.commandapi.SubCommand;
import com.github.johnnyjayjay.discord.commandapi.*;
import net.dv8tion.jda.core.Permission;
import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.TextChannel;
Expand All @@ -14,8 +11,7 @@ public class CustomPrefixCommand extends AbstractCommand {

@SubCommand(isDefault = true, botPerms = {Permission.MESSAGE_WRITE})
public void everythingElse(CommandEvent event, Member member, TextChannel channel, String[] args) {
event.respond("Correct usage: `" + event.getCommandSettings().getPrefix(event.getGuild().getIdLong()) + "prefix [get|set] <custom|default> <prefix>`\n" +
"If you set a new prefix, it has to be valid, i.e. match this regex: " + CommandSettings.VALID_PREFIX);
event.respond("Correct usage: `" + event.getCommandSettings().getPrefix(event.getGuild().getIdLong()) + "prefix [get|set] <custom|default> <prefix>`");
}

@SubCommand(args = {"get"}, botPerms = {Permission.MESSAGE_WRITE})
Expand All @@ -24,16 +20,13 @@ public void getPrefix(CommandEvent event, Member member, TextChannel channel, St
event.respond("The prefix for this guild is: `" + settings.getPrefix(event.getGuild().getIdLong()) + "`\nThe default prefix is: `" + settings.getPrefix() + "`");
}

@SubCommand(args = {"set", "custom", CommandSettings.VALID_PREFIX}, botPerms = {Permission.MESSAGE_WRITE})
@SubCommand(args = {"set", "custom", ".*"}, moreArgs = true, botPerms = {Permission.MESSAGE_WRITE})
public void setCustomPrefix(CommandEvent event, Member member, TextChannel channel, String[] args) {
if (args[2].matches(CommandSettings.VALID_PREFIX)) {
event.getCommandSettings().setCustomPrefix(event.getGuild().getIdLong(), args[2]);
event.respond("Successfully set prefix for this guild to `" + args[2] + "`!");
} else
event.respond("You need to specify a valid prefix as the third argument!");
event.getCommandSettings().setCustomPrefix(event.getGuild().getIdLong(), args[2]);
event.respond("Successfully set prefix for this guild to `" + args[2] + "`!");
}

@SubCommand(args = {"set", "default", CommandSettings.VALID_PREFIX}, botPerms = {Permission.MESSAGE_WRITE})
@SubCommand(args = {"set", "default", ".*"}, moreArgs = true, botPerms = {Permission.MESSAGE_WRITE})
public void setDefaultPrefix(CommandEvent event, Member member, TextChannel channel, String[] args) {
event.getCommandSettings().setDefaultPrefix(args[2]);
event.respond("Successfully set default prefix to `" + args[2] + "`!");
Expand Down
3 changes: 2 additions & 1 deletion src/examples/java/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public class Main {

public static void main(String[] args) throws LoginException, InterruptedException {
JDA jda = new JDABuilder(AccountType.BOT).setToken(Secrets.TOKEN).buildBlocking();
// default prefix shall be "!" and we want the labels to be case insensitive.
// default prefix shall be "!!" and we want the labels to be case insensitive.
new CommandSettings("!!", jda, true).setCooldown(3000) // commands can only be executed every 3 seconds now
.put(new PingCommand(), "ping", "p")
.put(new DefaultHelpCommand(), "help") // registering help command
.put(new CustomPrefixCommand(), "prefix")
.activate(); // Activating! Very important!
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,6 @@
*/
public abstract class AbstractCommand implements ICommand {

/**
* A regex to match member mentions.
*/
protected final String MEMBER_MENTION = "<@!?\\d+>";
/**
* A regex to match role mentions.
*/
protected final String ROLE_MENTION = "<&\\d+>";
/**
* A regex to match text channel mentions.
*/
protected final String CHANNEL_MENTION = "<#\\d+>";

private final Map<SubCommand, Method> subCommands;

/**
Expand Down Expand Up @@ -68,7 +55,7 @@ protected AbstractCommand() {
@Override
public final void onCommand(CommandEvent event, Member member, TextChannel channel, String[] args) {
CommandSettings settings = event.getCommandSettings();
Optional<SubCommand> matchesArgs = subCommands.keySet().stream()
subCommands.keySet().stream()
.filter((sub) -> !sub.isDefault())
.filter((sub) -> sub.args().length == args.length || (sub.moreArgs() && args.length > sub.args().length))
.filter((sub) -> {
Expand All @@ -80,23 +67,30 @@ public final void onCommand(CommandEvent event, Member member, TextChannel chann
}
return true;
})
.filter((sub) -> event.checkBotPermissions(sub.botPerms())).findFirst();
if (matchesArgs.isPresent()) {
.filter((sub) -> event.checkBotPermissions(sub.botPerms())).findFirst().map(Optional::of)
.orElseGet(() -> subCommands.keySet().stream().filter(SubCommand::isDefault).filter((sub) -> event.checkBotPermissions(sub.botPerms())).findFirst())
.map(subCommands::get).ifPresent((method) -> this.invokeMethod(method, event, member, channel, args));
/*if (matchesArgs.isPresent()) {
this.invokeMethod(subCommands.get(matchesArgs.get()), event, member, channel, args);
} else {
subCommands.keySet().stream().filter((sub) -> event.checkBotPermissions(sub.botPerms()))
.filter(SubCommand::isDefault).findFirst().map(subCommands::get)
subCommands.keySet().stream().filter(SubCommand::isDefault).filter((sub) -> event.checkBotPermissions(sub.botPerms()))
.findFirst().map(subCommands::get)
.ifPresent((method) -> this.invokeMethod(method, event, member, channel, args));
}
}*/
}

private void invokeMethod(Method method, CommandEvent event, Member member, TextChannel channel, String[] args) {
try {
method.invoke(this, event, member, channel, args);
} catch (IllegalAccessException e) {
CommandSettings.LOGGER.error("An Exception occurred while trying to invoke sub command method; Please report this in a github issue. https://github.com/JohnnyJayJay/discord-api-command/issues", e);
CommandSettings.LOGGER.error("An unexpected Exception occurred while trying to invoke sub command method; Please report this in a github issue. https://github.com/JohnnyJayJay/discord-api-command/issues", e);
} catch (InvocationTargetException e) {
CommandSettings.LOGGER.warn("One of the commands had an uncaught exception:", e.getCause());
CommandSettings settings = event.getCommandSettings();
Throwable cause = e.getCause();
if (settings.isLogExceptions()) {
CommandSettings.LOGGER.warn("Command " + event.getCommand().getExecutor().getClass().getName() + " had an uncaught Exception in SubCommand " + method.getName() + ":", cause);
}
settings.onException(event, cause);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* This class implements ICommand, therefore each sub class can be added as a normal command with CommandSettings#put.
* The framework provides a default implementation of this class, DefaultHelpCommand.
* @author JohnnyJayJay
* @version 3.2
* @version 3.2_01
* @since 3.2
* @see DefaultHelpCommand
*/
Expand Down
Loading