1
0
mirror of https://github.com/sciwhiz12/Janitor.git synced 2024-11-10 02:21:25 +00:00

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.
This commit is contained in:
Arnold Alejo Nunag 2020-09-03 02:43:37 +08:00
parent 6f901aab26
commit de696c0e12
Signed by: sciwhiz12
GPG Key ID: 622CF446534317E1
11 changed files with 184 additions and 74 deletions

View File

@ -12,6 +12,10 @@ buildscript {
repositories { repositories {
mavenCentral() mavenCentral()
jcenter() jcenter()
maven {
name = "Minecraft Libraries"
url = "https://libraries.minecraft.net"
}
} }
apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.github.johnrengelman.shadow'
@ -33,6 +37,7 @@ dependencies {
implementation "com.google.guava:guava:${guava_version}" implementation "com.google.guava:guava:${guava_version}"
implementation "com.google.code.gson:gson:${gson_version}" implementation "com.google.code.gson:gson:${gson_version}"
implementation "ch.qos.logback:logback-classic:${logback_version}" implementation "ch.qos.logback:logback-classic:${logback_version}"
implementation "com.mojang:brigadier:${brigadier_version}"
testImplementation "junit:junit:${junit_version}" testImplementation "junit:junit:${junit_version}"
} }

View File

@ -7,4 +7,5 @@ jopt_version=6.0-alpha-3
guava_version=29.0-jre guava_version=29.0-jre
gson_version=2.8.6 gson_version=2.8.6
logback_version=1.3.0-alpha5 logback_version=1.3.0-alpha5
brigadier_version=1.0.17
junit_version=4.13 junit_version=4.13

View File

@ -1,13 +1,23 @@
package sciwhiz12.janitor.commands; package sciwhiz12.janitor.commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import sciwhiz12.janitor.JanitorBot;
public abstract class BaseCommand { public abstract class BaseCommand {
protected final CommandRegistry registry; private final CommandRegistry registry;
public BaseCommand(CommandRegistry registry) { public BaseCommand(CommandRegistry registry) {
this.registry = registry; this.registry = registry;
} }
public abstract void onCommand(MessageReceivedEvent event); public CommandRegistry getRegistry() {
return registry;
}
public JanitorBot getBot() {
return registry.getBot();
}
public abstract LiteralArgumentBuilder<MessageReceivedEvent> getNode();
} }

View File

@ -1,14 +1,20 @@
package sciwhiz12.janitor.commands; 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 net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import sciwhiz12.janitor.JanitorBot; 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.listeners.BaseListener;
import sciwhiz12.janitor.utils.Util; import sciwhiz12.janitor.utils.Util;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static sciwhiz12.janitor.Logging.COMMANDS; import static sciwhiz12.janitor.Logging.COMMANDS;
@ -16,44 +22,53 @@ import static sciwhiz12.janitor.Logging.JANITOR;
public class CommandRegistry extends BaseListener { public class CommandRegistry extends BaseListener {
private final Pattern pattern; private final Pattern pattern;
private final String prefix;
private final Map<String, BaseCommand> registry = new HashMap<>(); private final Map<String, BaseCommand> registry = new HashMap<>();
private final CommandDispatcher<MessageReceivedEvent> dispatcher;
public CommandRegistry(JanitorBot bot, String prefix) { public CommandRegistry(JanitorBot bot, String prefix) {
super(bot); super(bot);
this.pattern = Pattern.compile("^" + prefix + "([A-Za-z0-9]+).*$"); this.pattern = Pattern.compile("^" + prefix + "([A-Za-z0-9]+).*$");
this.prefix = prefix;
this.dispatcher = new CommandDispatcher<>();
addCommand("ping", new PingCommand(this, "Pong!")); addCommand(new PingCommand(this, "ping", "Pong!"));
addCommand("pong", new PingCommand(this, "Ping!")); addCommand(new PingCommand(this, "pong", "Ping!"));
addCommand("ok", new OKCommand(this)); addCommand(new OKCommand(this));
if (bot.getConfig().getOwnerID().isPresent()) { if (bot.getConfig().getOwnerID().isPresent()) {
addCommand("shutdown", new ShutdownCommand(this, bot.getConfig().getOwnerID().get())); addCommand(new ShutdownCommand(this, bot.getConfig().getOwnerID().get()));
} }
}
public CommandDispatcher<MessageReceivedEvent> getDispatcher() {
return this.dispatcher;
} }
public JanitorBot getBot() { public JanitorBot getBot() {
return this.bot; return this.bot;
} }
public void addCommand(String cmd, BaseCommand instance) { public void addCommand(BaseCommand instance) {
registry.put(cmd, instance); dispatcher.register(instance.getNode());
} }
@Override @Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) { public void onMessageReceived(@NotNull MessageReceivedEvent event) {
String msg = event.getMessage().getContentDisplay();
if (!msg.startsWith(this.prefix)) return;
try { try {
String msg = event.getMessage().getContentDisplay(); StringReader command = new StringReader(msg.substring(this.prefix.length()));
Matcher matcher = pattern.matcher(msg); ParseResults<MessageReceivedEvent> parseResults = this.dispatcher.parse(command, event);
if (matcher.matches()) { if (parseResults.getReader().canRead()) {
String cmd = matcher.group(1); // Parsing did not succeed, i.e. command not found
if (registry.containsKey(cmd)) { // TODO: add separate code path when insufficient permissions / requires fails
JANITOR.debug(COMMANDS, "Received command: {}; author: {}, full message: {}", cmd, return;
Util.toString(event.getAuthor()), msg);
registry.get(cmd).onCommand(event);
}
} }
} catch (Exception e) { JANITOR.debug(COMMANDS, "Received command and executing. Author: {}, full message: {}", Util.toString(event.getAuthor()), msg);
JANITOR.error(COMMANDS, "Error while parsing message: {}", dispatcher.execute(parseResults);
event.getMessage().getContentStripped(), e); } catch (CommandSyntaxException ex) {
JANITOR.error(COMMANDS, "Error while parsing message and executing command", ex);
} }
} }
} }

View File

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

View File

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

View File

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

View File

@ -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<MessageReceivedEvent> getNode() {
return literal("shutdown")
.requires(ctx -> ctx.getAuthor().getIdLong() == ownerID)
.executes(this::run);
}
int run(final CommandContext<MessageReceivedEvent> 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;
}
}

View File

@ -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<MessageReceivedEvent> getNode() {
return literal("ok")
.executes(this::run);
}
int run(final CommandContext<MessageReceivedEvent> 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();
}
}

View File

@ -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<MessageReceivedEvent> getNode() {
return literal(command)
.executes(this::run);
}
int run(final CommandContext<MessageReceivedEvent> 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;
}
}

View File

@ -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<MessageReceivedEvent> literal(String command) {
return LiteralArgumentBuilder.literal(command);
}
}