diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index a67d2dc7..7c12385b 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -12,6 +12,7 @@
+
@@ -24,6 +25,7 @@
+
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index de06282c..94b979d5 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -6,6 +6,7 @@
+
diff --git a/jda/pom.xml b/jda/pom.xml
new file mode 100644
index 00000000..8b40cf40
--- /dev/null
+++ b/jda/pom.xml
@@ -0,0 +1,93 @@
+
+
+
+
+ 4.0.0
+
+
+ co.aikar
+ acf-parent
+ 0.5.0-SNAPSHOT
+ ../pom.xml
+
+
+ acf-jda
+ 0.5.0-SNAPSHOT
+
+ ACF (JDA)
+
+
+
+ jcenter
+ jcenter-bintray
+ http://jcenter.bintray.com
+
+
+
+
+
+ co.aikar
+ acf-core
+ 0.5.0-SNAPSHOT
+ compile
+
+
+ net.dv8tion
+ JDA
+ 3.5.0_327
+ provided
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.4.3
+
+
+ package
+
+ shade
+
+
+
+
+ ${project.build.directory}/dependency-reduced-pom.xml
+
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/jda/src/main/java/co/aikar/commands/CommandEvent.java b/jda/src/main/java/co/aikar/commands/CommandEvent.java
new file mode 100644
index 00000000..ce351c19
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/CommandEvent.java
@@ -0,0 +1,50 @@
+package co.aikar.commands;
+
+import net.dv8tion.jda.core.entities.Message;
+import net.dv8tion.jda.core.entities.MessageEmbed;
+import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
+
+public class CommandEvent implements CommandIssuer {
+
+ private MessageReceivedEvent event;
+ private JDACommandManager manager;
+
+ public CommandEvent(JDACommandManager manager, MessageReceivedEvent event) {
+
+ this.manager = manager;
+ this.event = event;
+ }
+
+ @Override
+ public MessageReceivedEvent getIssuer() {
+ return event;
+ }
+
+ @Override
+ public CommandManager getManager() {
+ return this.manager;
+ }
+
+ @Override
+ public boolean isPlayer() {
+ return false;
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ // TODO: Permission Resolving
+ return false;
+ }
+
+ @Override
+ public void sendMessageInternal(String message) {
+ this.event.getChannel().sendMessage(message).queue();
+ }
+
+ public void sendMessage(Message message) {
+ this.event.getChannel().sendMessage(message).queue();
+ }
+ public void sendMessage(MessageEmbed message) {
+ this.event.getChannel().sendMessage(message).queue();
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDACommandCompletions.java b/jda/src/main/java/co/aikar/commands/JDACommandCompletions.java
new file mode 100644
index 00000000..23bf2663
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDACommandCompletions.java
@@ -0,0 +1,41 @@
+package co.aikar.commands;
+
+import com.google.common.collect.ImmutableList;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class JDACommandCompletions extends CommandCompletions> {
+ private boolean initialized;
+ public JDACommandCompletions(CommandManager manager) {
+ super(manager);
+ this.initialized = true;
+ }
+
+ @Override
+ public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler> handler) {
+ if (initialized) {
+ throw new UnsupportedOperationException("JDA Doesn't support Command Completions");
+ }
+ return null;
+ }
+
+ @Override
+ public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler> handler) {
+ if (initialized) {
+ throw new UnsupportedOperationException("JDA Doesn't support Command Completions");
+ }
+ return null;
+ }
+
+ @NotNull
+ @Override
+ List of(RegisteredCommand command, CommandIssuer sender, String[] completionInfo, String[] args, boolean isAsync) {
+ return ImmutableList.of();
+ }
+
+ @Override
+ List getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {
+ return ImmutableList.of();
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDACommandContexts.java b/jda/src/main/java/co/aikar/commands/JDACommandContexts.java
new file mode 100644
index 00000000..a745bff8
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDACommandContexts.java
@@ -0,0 +1,7 @@
+package co.aikar.commands;
+
+public class JDACommandContexts extends CommandContexts {
+ JDACommandContexts(CommandManager manager) {
+ super(manager);
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDACommandExecutionContext.java b/jda/src/main/java/co/aikar/commands/JDACommandExecutionContext.java
new file mode 100644
index 00000000..41c6cdfd
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDACommandExecutionContext.java
@@ -0,0 +1,11 @@
+package co.aikar.commands;
+
+import java.lang.reflect.Parameter;
+import java.util.List;
+import java.util.Map;
+
+public class JDACommandExecutionContext extends CommandExecutionContext {
+ JDACommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandEvent sender, List args, int index, Map passedArgs) {
+ super(cmd, param, sender, args, index, passedArgs);
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDACommandManager.java b/jda/src/main/java/co/aikar/commands/JDACommandManager.java
new file mode 100644
index 00000000..a4773a0b
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDACommandManager.java
@@ -0,0 +1,170 @@
+package co.aikar.commands;
+
+import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil;
+import com.google.common.collect.Maps;
+import jdk.nashorn.internal.ir.IfNode;
+import net.dv8tion.jda.core.JDA;
+import net.dv8tion.jda.core.entities.Message;
+import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
+
+import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JDACommandManager extends CommandManager<
+ MessageReceivedEvent,
+ CommandEvent,
+ String,
+ MessageFormatter,
+ JDACommandExecutionContext,
+ JDAConditionContext
+ > {
+
+ private final JDA jda;
+ private String startsWith;
+ private Logger logger;
+ protected JDACommandCompletions completions;
+ protected JDACommandContexts contexts;
+ protected JDALocales locales;
+
+ protected Map commands = Maps.newHashMap();
+
+ public JDACommandManager(JDA jda) {
+ this(jda, "!");
+ }
+ public JDACommandManager(JDA jda, String startsWith) {
+ this.jda = jda;
+ jda.addEventListener(new JDAListener(this));
+ this.startsWith = startsWith;
+ this.completions = new JDACommandCompletions(this);
+ this.logger = Logger.getLogger(this.getClass().getSimpleName());
+ }
+
+ public JDA getJDA() {
+ return jda;
+ }
+
+ public Logger getLogger() {
+ return logger;
+ }
+
+ public void setLogger(Logger logger) {
+ this.logger = logger;
+ }
+
+ public String getStartsWith() {
+ return startsWith;
+ }
+
+ public void setStartsWith(String startsWith) {
+ this.startsWith = startsWith;
+ }
+
+ @Override
+ public CommandContexts> getCommandContexts() {
+ if (this.contexts == null) {
+ this.contexts = new JDACommandContexts(this);
+ }
+ return null;
+ }
+
+ @Override
+ public CommandCompletions> getCommandCompletions() {
+ return this.completions;
+ }
+
+ @Override
+ public void registerCommand(BaseCommand command) {
+ for (Map.Entry entry : command.registeredCommands.entrySet()) {
+ String commandName = entry.getKey().toLowerCase();
+ JDARootCommand cmd = (JDARootCommand) entry.getValue();
+ if (!cmd.isRegistered) {
+ cmd.isRegistered = true;
+ commands.put(commandName, cmd);
+ }
+ }
+ }
+
+ @Override
+ public boolean hasRegisteredCommands() {
+ return !this.commands.isEmpty();
+ }
+
+ @Override
+ public boolean isCommandIssuer(Class> type) {
+ return CommandEvent.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public CommandEvent getCommandIssuer(Object issuer) {
+ if (!(issuer instanceof MessageReceivedEvent)) {
+ throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Message Received Event.");
+ }
+ return new CommandEvent(this, (MessageReceivedEvent) issuer);
+ }
+
+ @Override
+ public RootCommand createRootCommand(String cmd) {
+ return new JDARootCommand(this, cmd);
+ }
+
+ @Override
+ public Locales getLocales() {
+ if (this.locales == null) {
+ this.locales = new JDALocales(this);
+ this.locales.loadLanguages();
+ }
+ return null;
+ }
+
+ @Override
+ public CommandExecutionContext createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) {
+ return new JDACommandExecutionContext(command, parameter, (CommandEvent) sender, args, i, passedArgs);
+ }
+
+ @Override
+ public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
+ // Not really going to be used;
+ //noinspection unchecked
+ return new CommandCompletionContext(command, sender, input, config, args);
+ }
+
+ @Override
+ public void log(LogLevel level, String message, Throwable throwable) {
+ Level logLevel = level == LogLevel.INFO ? Level.INFO : Level.SEVERE;
+ logger.log(logLevel, LogLevel.LOG_PREFIX + message);
+ if (throwable != null) {
+ for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
+ logger.log(logLevel, LogLevel.LOG_PREFIX + line);
+ }
+ }
+ }
+
+ void dispatchEvent(MessageReceivedEvent event) {
+ Message message = event.getMessage();
+ String msg = message.getContentDisplay();
+
+ if (!msg.startsWith(this.startsWith)) {
+ return;
+ }
+
+ String[] args = ACFPatterns.SPACE.split(msg.substring(1), -1);
+ if (args.length == 0) {
+ return;
+ }
+ String cmd = args[0].toLowerCase();
+ JDARootCommand rootCommand = this.commands.get(cmd);
+ if (rootCommand == null) {
+ return;
+ }
+ if (args.length > 1) {
+ args = Arrays.copyOfRange(args, 1, args.length);
+ } else {
+ args = new String[0];
+ }
+ rootCommand.execute(this.getCommandIssuer(event), cmd, args);
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDAConditionContext.java b/jda/src/main/java/co/aikar/commands/JDAConditionContext.java
new file mode 100644
index 00000000..154e3c5c
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDAConditionContext.java
@@ -0,0 +1,7 @@
+package co.aikar.commands;
+
+public class JDAConditionContext extends ConditionContext {
+ JDAConditionContext(CommandEvent issuer, String config) {
+ super(issuer, config);
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDAListener.java b/jda/src/main/java/co/aikar/commands/JDAListener.java
new file mode 100644
index 00000000..4b1ea349
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDAListener.java
@@ -0,0 +1,33 @@
+package co.aikar.commands;
+
+import net.dv8tion.jda.core.entities.ChannelType;
+import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent;
+import net.dv8tion.jda.core.events.message.priv.PrivateMessageReceivedEvent;
+import net.dv8tion.jda.core.hooks.ListenerAdapter;
+
+public class JDAListener extends ListenerAdapter {
+
+ private final JDACommandManager manager;
+
+ JDAListener(JDACommandManager manager) {
+
+ this.manager = manager;
+ }
+ @Override
+ public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
+ super.onGuildMessageReceived(event);
+ }
+
+ @Override
+ public void onPrivateMessageReceived(PrivateMessageReceivedEvent event) {
+ super.onPrivateMessageReceived(event);
+ }
+
+ @Override
+ public void onMessageReceived(MessageReceivedEvent event) {
+ if (event.isFromType(ChannelType.TEXT) || event.isFromType(ChannelType.PRIVATE)) {
+ this.manager.dispatchEvent(event);
+ }
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDALocales.java b/jda/src/main/java/co/aikar/commands/JDALocales.java
new file mode 100644
index 00000000..84898f4d
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDALocales.java
@@ -0,0 +1,7 @@
+package co.aikar.commands;
+
+public class JDALocales extends Locales {
+ public JDALocales(CommandManager manager) {
+ super(manager);
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDAMessageFormatter.java b/jda/src/main/java/co/aikar/commands/JDAMessageFormatter.java
new file mode 100644
index 00000000..21d24d79
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDAMessageFormatter.java
@@ -0,0 +1,8 @@
+package co.aikar.commands;
+
+public class JDAMessageFormatter extends MessageFormatter {
+ @Override
+ String format(String color, String message) {
+ return message;
+ }
+}
diff --git a/jda/src/main/java/co/aikar/commands/JDARootCommand.java b/jda/src/main/java/co/aikar/commands/JDARootCommand.java
new file mode 100644
index 00000000..aa000d65
--- /dev/null
+++ b/jda/src/main/java/co/aikar/commands/JDARootCommand.java
@@ -0,0 +1,51 @@
+package co.aikar.commands;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JDARootCommand implements RootCommand {
+
+ private JDACommandManager manager;
+ private final String name;
+ private BaseCommand defCommand;
+ private SetMultimap subCommands = HashMultimap.create();
+ private List children = new ArrayList<>();
+ boolean isRegistered = false;
+
+ JDARootCommand(JDACommandManager manager, String name) {
+ this.manager = manager;
+ this.name = name;
+ }
+
+ @Override
+
+ public void addChild(BaseCommand command) {
+ if (this.defCommand == null || !command.subCommands.get(BaseCommand.DEFAULT).isEmpty()) {
+ this.defCommand = command;
+ }
+ addChildShared(this.children, this.subCommands, command);
+ }
+
+ @Override
+ public CommandManager getManager() {
+ return this.manager;
+ }
+
+ @Override
+ public SetMultimap getSubCommands() {
+ return this.subCommands;
+ }
+
+ @Override
+ public List getChildren() {
+ return this.children;
+ }
+
+ @Override
+ public String getCommandName() {
+ return this.name;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 6d82931e..f15df29f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -147,5 +147,6 @@
paper
bungee
sponge
+ jda