From de696c0e120ea9ff22416c03732ff78f3b0300ab Mon Sep 17 00:00:00 2001 From: Arnold Alejo Nunag Date: Thu, 3 Sep 2020 02:43:37 +0800 Subject: [PATCH] Move to using Brigadier for bot commands Brigadier is a command parsing and execution library made by Mojang for their game Minecraft. Licensed under MIT license. --- build.gradle | 5 ++ gradle.properties | 1 + .../janitor/commands/BaseCommand.java | 14 ++++- .../janitor/commands/CommandRegistry.java | 53 ++++++++++++------- .../sciwhiz12/janitor/commands/OKCommand.java | 14 ----- .../janitor/commands/PingCommand.java | 17 ------ .../janitor/commands/ShutdownCommand.java | 22 -------- .../janitor/commands/bot/ShutdownCommand.java | 42 +++++++++++++++ .../janitor/commands/misc/OKCommand.java | 39 ++++++++++++++ .../janitor/commands/misc/PingCommand.java | 41 ++++++++++++++ .../janitor/utils/CommandHelper.java | 10 ++++ 11 files changed, 184 insertions(+), 74 deletions(-) delete mode 100644 src/main/java/sciwhiz12/janitor/commands/OKCommand.java delete mode 100644 src/main/java/sciwhiz12/janitor/commands/PingCommand.java delete mode 100644 src/main/java/sciwhiz12/janitor/commands/ShutdownCommand.java create mode 100644 src/main/java/sciwhiz12/janitor/commands/bot/ShutdownCommand.java create mode 100644 src/main/java/sciwhiz12/janitor/commands/misc/OKCommand.java create mode 100644 src/main/java/sciwhiz12/janitor/commands/misc/PingCommand.java create mode 100644 src/main/java/sciwhiz12/janitor/utils/CommandHelper.java diff --git a/build.gradle b/build.gradle index 828a2a1..e557df9 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,10 @@ buildscript { repositories { mavenCentral() jcenter() + maven { + name = "Minecraft Libraries" + url = "https://libraries.minecraft.net" + } } apply plugin: 'com.github.johnrengelman.shadow' @@ -33,6 +37,7 @@ dependencies { implementation "com.google.guava:guava:${guava_version}" implementation "com.google.code.gson:gson:${gson_version}" implementation "ch.qos.logback:logback-classic:${logback_version}" + implementation "com.mojang:brigadier:${brigadier_version}" testImplementation "junit:junit:${junit_version}" } diff --git a/gradle.properties b/gradle.properties index b077903..31b7b6a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,4 +7,5 @@ jopt_version=6.0-alpha-3 guava_version=29.0-jre gson_version=2.8.6 logback_version=1.3.0-alpha5 +brigadier_version=1.0.17 junit_version=4.13 diff --git a/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java b/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java index c1ff37d..e953bac 100644 --- a/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java +++ b/src/main/java/sciwhiz12/janitor/commands/BaseCommand.java @@ -1,13 +1,23 @@ package sciwhiz12.janitor.commands; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import sciwhiz12.janitor.JanitorBot; public abstract class BaseCommand { - protected final CommandRegistry registry; + private final CommandRegistry registry; public BaseCommand(CommandRegistry registry) { this.registry = registry; } - public abstract void onCommand(MessageReceivedEvent event); + public CommandRegistry getRegistry() { + return registry; + } + + public JanitorBot getBot() { + return registry.getBot(); + } + + public abstract LiteralArgumentBuilder getNode(); } diff --git a/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java b/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java index 51efe1f..9f46e15 100644 --- a/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java +++ b/src/main/java/sciwhiz12/janitor/commands/CommandRegistry.java @@ -1,14 +1,20 @@ package sciwhiz12.janitor.commands; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.jetbrains.annotations.NotNull; import sciwhiz12.janitor.JanitorBot; +import sciwhiz12.janitor.commands.bot.ShutdownCommand; +import sciwhiz12.janitor.commands.misc.OKCommand; +import sciwhiz12.janitor.commands.misc.PingCommand; import sciwhiz12.janitor.listeners.BaseListener; import sciwhiz12.janitor.utils.Util; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; import static sciwhiz12.janitor.Logging.COMMANDS; @@ -16,44 +22,53 @@ import static sciwhiz12.janitor.Logging.JANITOR; public class CommandRegistry extends BaseListener { private final Pattern pattern; + private final String prefix; private final Map registry = new HashMap<>(); + private final CommandDispatcher dispatcher; public CommandRegistry(JanitorBot bot, String prefix) { super(bot); this.pattern = Pattern.compile("^" + prefix + "([A-Za-z0-9]+).*$"); + this.prefix = prefix; + this.dispatcher = new CommandDispatcher<>(); - addCommand("ping", new PingCommand(this, "Pong!")); - addCommand("pong", new PingCommand(this, "Ping!")); - addCommand("ok", new OKCommand(this)); + addCommand(new PingCommand(this, "ping", "Pong!")); + addCommand(new PingCommand(this, "pong", "Ping!")); + addCommand(new OKCommand(this)); if (bot.getConfig().getOwnerID().isPresent()) { - addCommand("shutdown", new ShutdownCommand(this, bot.getConfig().getOwnerID().get())); + addCommand(new ShutdownCommand(this, bot.getConfig().getOwnerID().get())); } + + } + + public CommandDispatcher getDispatcher() { + return this.dispatcher; } public JanitorBot getBot() { return this.bot; } - public void addCommand(String cmd, BaseCommand instance) { - registry.put(cmd, instance); + public void addCommand(BaseCommand instance) { + dispatcher.register(instance.getNode()); } @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { + String msg = event.getMessage().getContentDisplay(); + if (!msg.startsWith(this.prefix)) return; try { - String msg = event.getMessage().getContentDisplay(); - Matcher matcher = pattern.matcher(msg); - if (matcher.matches()) { - String cmd = matcher.group(1); - if (registry.containsKey(cmd)) { - JANITOR.debug(COMMANDS, "Received command: {}; author: {}, full message: {}", cmd, - Util.toString(event.getAuthor()), msg); - registry.get(cmd).onCommand(event); - } + StringReader command = new StringReader(msg.substring(this.prefix.length())); + ParseResults parseResults = this.dispatcher.parse(command, event); + if (parseResults.getReader().canRead()) { + // Parsing did not succeed, i.e. command not found + // TODO: add separate code path when insufficient permissions / requires fails + return; } - } catch (Exception e) { - JANITOR.error(COMMANDS, "Error while parsing message: {}", - event.getMessage().getContentStripped(), e); + JANITOR.debug(COMMANDS, "Received command and executing. Author: {}, full message: {}", Util.toString(event.getAuthor()), msg); + dispatcher.execute(parseResults); + } catch (CommandSyntaxException ex) { + JANITOR.error(COMMANDS, "Error while parsing message and executing command", ex); } } } diff --git a/src/main/java/sciwhiz12/janitor/commands/OKCommand.java b/src/main/java/sciwhiz12/janitor/commands/OKCommand.java deleted file mode 100644 index 80c8402..0000000 --- a/src/main/java/sciwhiz12/janitor/commands/OKCommand.java +++ /dev/null @@ -1,14 +0,0 @@ -package sciwhiz12.janitor.commands; - -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; - -public class OKCommand extends BaseCommand { - public OKCommand(CommandRegistry registry) { - super(registry); - } - - @Override - public void onCommand(MessageReceivedEvent event) { - event.getMessage().addReaction("\uD83D\uDC4C").queue(); - } -} diff --git a/src/main/java/sciwhiz12/janitor/commands/PingCommand.java b/src/main/java/sciwhiz12/janitor/commands/PingCommand.java deleted file mode 100644 index 0124a56..0000000 --- a/src/main/java/sciwhiz12/janitor/commands/PingCommand.java +++ /dev/null @@ -1,17 +0,0 @@ -package sciwhiz12.janitor.commands; - -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; - -public class PingCommand extends BaseCommand { - private final String message; - - public PingCommand(CommandRegistry registry, String message) { - super(registry); - this.message = message; - } - - @Override - public void onCommand(MessageReceivedEvent event) { - event.getMessage().getChannel().sendMessage(message).queue(); - } -} diff --git a/src/main/java/sciwhiz12/janitor/commands/ShutdownCommand.java b/src/main/java/sciwhiz12/janitor/commands/ShutdownCommand.java deleted file mode 100644 index 9637217..0000000 --- a/src/main/java/sciwhiz12/janitor/commands/ShutdownCommand.java +++ /dev/null @@ -1,22 +0,0 @@ -package sciwhiz12.janitor.commands; - -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; - -public class ShutdownCommand extends BaseCommand { - private final long ownerID; - - public ShutdownCommand(CommandRegistry registry, long ownerID) { - super(registry); - this.ownerID = ownerID; - } - - @Override - public void onCommand(MessageReceivedEvent event) { - if (event.getAuthor().getIdLong() == ownerID) { - event.getMessage().getChannel() - .sendMessage("Shutting down, in accordance with the owner's command. Goodbye all!") - .complete(); - registry.getBot().shutdown(); - } - } -} diff --git a/src/main/java/sciwhiz12/janitor/commands/bot/ShutdownCommand.java b/src/main/java/sciwhiz12/janitor/commands/bot/ShutdownCommand.java new file mode 100644 index 0000000..f19ff61 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/commands/bot/ShutdownCommand.java @@ -0,0 +1,42 @@ +package sciwhiz12.janitor.commands.bot; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import sciwhiz12.janitor.commands.BaseCommand; +import sciwhiz12.janitor.commands.CommandRegistry; +import sciwhiz12.janitor.utils.Util; + +import static sciwhiz12.janitor.Logging.JANITOR; +import static sciwhiz12.janitor.utils.CommandHelper.literal; + +public class ShutdownCommand extends BaseCommand { + private final long ownerID; + + public ShutdownCommand(CommandRegistry registry, long ownerID) { + super(registry); + this.ownerID = ownerID; + } + + @Override + public LiteralArgumentBuilder getNode() { + return literal("shutdown") + .requires(ctx -> ctx.getAuthor().getIdLong() == ownerID) + .executes(this::run); + } + + int run(final CommandContext ctx) { + ctx.getSource() + .getMessage() + .getChannel() + .sendMessage("Shutting down, in accordance with the owner's command. Goodbye all!") + .submit() + .whenComplete(Util.handle( + success -> JANITOR.debug("Sent shutdown message to channel {}", Util.toString(ctx.getSource().getAuthor())), + err -> JANITOR.error("Error while sending ping message to bot owner {}", Util.toString(ctx.getSource().getAuthor())) + ) + ).join(); + getBot().shutdown(); + return 1; + } +} diff --git a/src/main/java/sciwhiz12/janitor/commands/misc/OKCommand.java b/src/main/java/sciwhiz12/janitor/commands/misc/OKCommand.java new file mode 100644 index 0000000..7a99a6d --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/commands/misc/OKCommand.java @@ -0,0 +1,39 @@ +package sciwhiz12.janitor.commands.misc; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import sciwhiz12.janitor.commands.BaseCommand; +import sciwhiz12.janitor.commands.CommandRegistry; +import sciwhiz12.janitor.utils.Util; + +import static sciwhiz12.janitor.Logging.JANITOR; +import static sciwhiz12.janitor.utils.CommandHelper.literal; + +public class OKCommand extends BaseCommand { + public OKCommand(CommandRegistry registry) { + super(registry); + } + + public LiteralArgumentBuilder getNode() { + return literal("ok") + .executes(this::run); + } + + int run(final CommandContext ctx) { + ctx.getSource() + .getMessage() + .addReaction("\uD83D\uDC4C") + .submit() + .whenComplete(Util.handle( + success -> JANITOR.debug("Reacted :ok_hand: to {}'s message", Util.toString(ctx.getSource().getAuthor())), + err -> JANITOR.error("Error while reacting :ok_hand: to {}'s message", Util.toString(ctx.getSource().getAuthor())) + ) + ); + return 1; + } + + public void onCommand(MessageReceivedEvent event) { + event.getMessage().addReaction("\uD83D\uDC4C").queue(); + } +} diff --git a/src/main/java/sciwhiz12/janitor/commands/misc/PingCommand.java b/src/main/java/sciwhiz12/janitor/commands/misc/PingCommand.java new file mode 100644 index 0000000..11032fe --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/commands/misc/PingCommand.java @@ -0,0 +1,41 @@ +package sciwhiz12.janitor.commands.misc; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import sciwhiz12.janitor.commands.BaseCommand; +import sciwhiz12.janitor.commands.CommandRegistry; +import sciwhiz12.janitor.utils.Util; + +import static sciwhiz12.janitor.Logging.JANITOR; +import static sciwhiz12.janitor.utils.CommandHelper.literal; + +public class PingCommand extends BaseCommand { + private final String command; + private final String reply; + + public PingCommand(CommandRegistry registry, String command, String reply) { + super(registry); + this.command = command; + this.reply = reply; + } + + public LiteralArgumentBuilder getNode() { + return literal(command) + .executes(this::run); + } + + int run(final CommandContext ctx) { + ctx.getSource() + .getMessage() + .getChannel() + .sendMessage(reply) + .submit() + .whenComplete(Util.handle( + success -> JANITOR.debug("Sent ping message to {}: {}", Util.toString(ctx.getSource().getAuthor()), reply), + err -> JANITOR.error("Error while sending ping message to {}", Util.toString(ctx.getSource().getAuthor())) + ) + ); + return 1; + } +} diff --git a/src/main/java/sciwhiz12/janitor/utils/CommandHelper.java b/src/main/java/sciwhiz12/janitor/utils/CommandHelper.java new file mode 100644 index 0000000..f7ebc97 --- /dev/null +++ b/src/main/java/sciwhiz12/janitor/utils/CommandHelper.java @@ -0,0 +1,10 @@ +package sciwhiz12.janitor.utils; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +public class CommandHelper { + public static LiteralArgumentBuilder literal(String command) { + return LiteralArgumentBuilder.literal(command); + } +}