From 605c3365cc5cc2e73c7035a89275e0296830b3fe Mon Sep 17 00:00:00 2001 From: Alex 'mcmonkey' Goodwin Date: Mon, 30 Nov 2020 12:43:53 -0800 Subject: [PATCH] add 'discordreact' command, fixes #19 --- .../ddiscordbot/DenizenDiscordBot.java | 2 + .../commands/DiscordReactCommand.java | 204 ++++++++++++++++++ .../objects/DiscordReactionTag.java | 2 +- 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/denizenscript/ddiscordbot/commands/DiscordReactCommand.java diff --git a/src/main/java/com/denizenscript/ddiscordbot/DenizenDiscordBot.java b/src/main/java/com/denizenscript/ddiscordbot/DenizenDiscordBot.java index 14c949d..f7054cd 100644 --- a/src/main/java/com/denizenscript/ddiscordbot/DenizenDiscordBot.java +++ b/src/main/java/com/denizenscript/ddiscordbot/DenizenDiscordBot.java @@ -1,6 +1,7 @@ package com.denizenscript.ddiscordbot; import com.denizenscript.ddiscordbot.commands.DiscordCommand; +import com.denizenscript.ddiscordbot.commands.DiscordReactCommand; import com.denizenscript.ddiscordbot.events.*; import com.denizenscript.ddiscordbot.objects.*; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -28,6 +29,7 @@ public void onEnable() { instance = this; try { DenizenCore.getCommandRegistry().registerCommand(DiscordCommand.class); + DenizenCore.getCommandRegistry().registerCommand(DiscordReactCommand.class); ScriptEvent.registerScriptEvent(DiscordMessageDeletedScriptEvent.instance = new DiscordMessageDeletedScriptEvent()); ScriptEvent.registerScriptEvent(DiscordMessageModifiedScriptEvent.instance = new DiscordMessageModifiedScriptEvent()); ScriptEvent.registerScriptEvent(DiscordMessageReactionAddScriptEvent.instance = new DiscordMessageReactionAddScriptEvent()); diff --git a/src/main/java/com/denizenscript/ddiscordbot/commands/DiscordReactCommand.java b/src/main/java/com/denizenscript/ddiscordbot/commands/DiscordReactCommand.java new file mode 100644 index 0000000..d6bddc4 --- /dev/null +++ b/src/main/java/com/denizenscript/ddiscordbot/commands/DiscordReactCommand.java @@ -0,0 +1,204 @@ +package com.denizenscript.ddiscordbot.commands; + +import com.denizenscript.ddiscordbot.DenizenDiscordBot; +import com.denizenscript.ddiscordbot.objects.*; +import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; +import com.denizenscript.denizencore.objects.Argument; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.scripts.commands.Holdable; +import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.debugging.Debug; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.requests.RestAction; +import org.bukkit.Bukkit; + +import java.util.List; + +public class DiscordReactCommand extends AbstractCommand implements Holdable { + + public DiscordReactCommand() { + setName("discordreact"); + setSyntax("discordreact [id:] [message:] [add/remove/clear] [reaction:/all]"); + setRequiredArguments(4, 5); + } + // <--[command] + // @Name discordreact + // @Syntax discordreact [id:] (channel:) [message:] [add/remove/clear] [reaction:/all] + // @Required 4 + // @Maximum 5 + // @Short Manages message reactions on Discord. + // @Plugin dDiscordBot + // @Group external + // + // @Description + // Manages message reactions on Discord. + // + // The message can be a <@link language DiscordMessageTag>, or just the message ID, with a channel ID also given. + // + // You can add or remove reactions from the bot, or clear all reactions of a specific ID, or clear all reactions from a message entirely. + // + // Reactions can be unicode symbols, or custom emoji IDs. + // + // 'Add' requires basic add-reaction permissions. + // 'Clear' requires 'manage messages' permission. + // + // @Tags + // + // + // @Usage + // Use to react to a previously sent message. + // - ~discordreact id:mybot message:<[some_message]> add reaction:<[my_emoji_id]> + // + // @Usage + // Use to remove a reaction from a previously sent message. + // - ~discordreact id:mybot message:<[some_message]> remove reaction:middle_finger + // + // + // @Usage + // Use to clear all reactions from a message. + // - ~discordreact id:mybot message:<[some_message]> clear reaction:all + // + // --> + + public enum DiscordReactInstruction { ADD, REMOVE, CLEAR } + + @Override + public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { + for (Argument arg : scriptEntry.getProcessedArgs()) { + if (!scriptEntry.hasObject("id") + && arg.matchesPrefix("id")) { + scriptEntry.addObject("id", new ElementTag(CoreUtilities.toLowerCase(arg.getValue()))); + } + else if (!scriptEntry.hasObject("instruction") + && arg.matchesEnum(DiscordReactInstruction.values())) { + scriptEntry.addObject("instruction", arg.asElement()); + } + else if (!scriptEntry.hasObject("channel") + && arg.matchesPrefix("channel") + && arg.matchesArgumentType(DiscordChannelTag.class)) { + scriptEntry.addObject("channel", arg.asType(DiscordChannelTag.class)); + } + else if (!scriptEntry.hasObject("message") + && arg.matchesPrefix("message") + && arg.matchesArgumentType(DiscordMessageTag.class)) { + scriptEntry.addObject("message", arg.asType(DiscordMessageTag.class)); + } + else if (!scriptEntry.hasObject("reaction") + && arg.matchesPrefix("reaction")) { + scriptEntry.addObject("reaction", arg.asElement()); + } + else { + arg.reportUnhandled(); + } + } + if (!scriptEntry.hasObject("id")) { + throw new InvalidArgumentsException("Must have an ID!"); + } + if (!scriptEntry.hasObject("instruction")) { + throw new InvalidArgumentsException("Must have an instruction!"); + } + if (!scriptEntry.hasObject("message")) { + throw new InvalidArgumentsException("Must have a message!"); + } + if (!scriptEntry.hasObject("reaction")) { + throw new InvalidArgumentsException("Must have a reaction!"); + } + } + + @Override + public void execute(ScriptEntry scriptEntry) { + ElementTag id = scriptEntry.getElement("id"); + ElementTag instruction = scriptEntry.getElement("instruction"); + DiscordChannelTag channel = scriptEntry.getObjectTag("channel"); + DiscordMessageTag message = scriptEntry.getObjectTag("message"); + ElementTag reaction = scriptEntry.getElement("reaction"); + if (scriptEntry.dbCallShouldDebug()) { + Debug.report(scriptEntry, getName(), id.debug() + + instruction.debug() + + (channel != null ? channel.debug() : "") + + message.debug() + + reaction.debug()); + } + JDA client = DenizenDiscordBot.instance.connections.get(id.asString()).client; + if (message.channel_id == 0) { + if (channel != null) { + message.channel_id = channel.channel_id; + } + else { + Debug.echoError("Must specify a channel!"); + scriptEntry.setFinished(true); + return; + } + } + message.bot = id.asString(); + Message msg = message.getMessage(); + if (msg == null) { + Debug.echoError("Unknown message, cannot add reaction."); + scriptEntry.setFinished(true); + return; + } + Emote emote = null; + if (reaction.isInt()) { + emote = client.getEmoteById(reaction.asLong()); + } + else { + List emotesPossible = client.getEmotesByName(reaction.asString(), true); + if (!emotesPossible.isEmpty()) { + emote = emotesPossible.get(0); + } + } + RestAction action; + switch (DiscordReactInstruction.valueOf(instruction.asString().toUpperCase())) { + case ADD: { + if (emote != null) { + action = msg.addReaction(emote); + } + else { + action = msg.addReaction(reaction.asString()); + } + break; + } + case REMOVE: { + if (emote != null) { + action = msg.removeReaction(emote); + } + else { + action = msg.removeReaction(reaction.asString()); + } + break; + } + case CLEAR: { + if (CoreUtilities.toLowerCase(reaction.asString()).equals("all")) { + action = msg.clearReactions(); + } + else { + if (emote != null) { + action = msg.clearReactions(emote); + } + else { + action = msg.clearReactions(reaction.asString()); + } + } + break; + } + default: { + return; // Not possible, but required to prevent compiler error + } + } + final RestAction actWait = action; + Bukkit.getScheduler().runTaskAsynchronously(DenizenDiscordBot.instance, () -> { + actWait.onErrorMap(t -> { + Bukkit.getScheduler().runTask(DenizenDiscordBot.instance, () -> { + Debug.echoError(t); + }); + return null; + }); + actWait.complete(); + scriptEntry.setFinished(true); + }); + } +} diff --git a/src/main/java/com/denizenscript/ddiscordbot/objects/DiscordReactionTag.java b/src/main/java/com/denizenscript/ddiscordbot/objects/DiscordReactionTag.java index 6ec305b..8b137bc 100644 --- a/src/main/java/com/denizenscript/ddiscordbot/objects/DiscordReactionTag.java +++ b/src/main/java/com/denizenscript/ddiscordbot/objects/DiscordReactionTag.java @@ -212,7 +212,7 @@ public static void registerTags() { // @returns ElementTag // @plugin dDiscordBot // @description - // Returns the amount of the emoji reacted. + // Returns the name of the emoji. // --> registerTag("name", (attribute, object) -> { return new ElementTag(object.emote.getName());