From d2aea8559ab5177fd285de7d14eda54c5070a30f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 10 Apr 2019 13:50:26 +0200 Subject: [PATCH 01/24] Server ready conf, doc --- pom.xml | 9 +++++ .../announcer/AnnouncerModule.java | 5 ++- .../discordplugin/fun/FunModule.java | 36 ++++++++++--------- .../mcchat/MinecraftChatModule.java | 8 ++--- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index 270da7f..c2d74d7 100755 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,14 @@ 1.8 1.8 + + @@ -96,6 +104,7 @@ --> maven-surefire-plugin + 2.4.2 false diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index c434dce..a0c11a0 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -20,6 +20,9 @@ import java.io.File; import java.util.List; public class AnnouncerModule extends Component { + /** + * Channel to post new posts. + */ public ConfigData channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } @@ -29,7 +32,7 @@ public class AnnouncerModule extends Component { } /** - * Set to 0 or >50 to disable + * Automatically unpins all messages except the last few. Set to 0 or >50 to disable */ public ConfigData keepPinned() { return getConfig().getData("keepPinned", (short) 40); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index f5adf0d..e5faead 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -40,19 +40,23 @@ public class FunModule extends Component implements Listener { "When will *you* be open?" // Ali }; - private ConfigData serverReady() { - return getConfig().getData("serverReady", true); + /** + * Questions that the bot will choose a random answer to give to. + */ + private ConfigData serverReadyQuestions() { + return getConfig().getData("serverReady", ()->new String[]{"when will the server be open", + "when will the server be ready", "when will the server be done", "when will the server be complete", + "when will the server be finished", "when's the server ready", "when's the server open", + "Vhen vill ze server be open?"}); } + /** + * Answers for a recognized question. Selected randomly. + */ private ConfigData> serverReadyAnswers() { return getConfig().getData("serverReadyAnswers", () -> Lists.newArrayList(serverReadyStrings)); //TODO: Test } - private static final String[] serverReadyQuestions = new String[]{"when will the server be open", - "when will the server be ready", "when will the server be done", "when will the server be complete", - "when will the server be finished", "when's the server ready", "when's the server open", - "Vhen vill ze server be open?"}; - private static final Random serverReadyRandom = new Random(); private static final ArrayList usableServerReadyStrings = new ArrayList<>(0); @@ -93,16 +97,14 @@ public class FunModule extends Component implements Listener { return true; //Handled } lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle - if (fm.serverReady().get()) { - if (!TBMCCoreAPI.IsTestServer() - && Arrays.stream(serverReadyQuestions).anyMatch(msglowercased::contains)) { - int next; - if (usableServerReadyStrings.size() == 0) - fm.createUsableServerReadyStrings(); - next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); - DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]); - return false; //Still process it as a command/mcchat if needed - } + if (!TBMCCoreAPI.IsTestServer() + && Arrays.stream(fm.serverReadyQuestions().get()).anyMatch(msglowercased::contains)) { + int next; + if (usableServerReadyStrings.size() == 0) + fm.createUsableServerReadyStrings(); + next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); + DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]); + return false; //Still process it as a command/mcchat if needed } return false; } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 509ea66..94ef49d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -25,9 +25,9 @@ import java.util.stream.Collectors; public class MinecraftChatModule extends Component { private @Getter MCChatListener listener; - public MCChatListener getListener() { //It doesn't want to generate - return listener; - } + /*public MCChatListener getListener() { //It doesn't want to generate + return listener; - And now ButtonProcessor didn't look beyond this - return instead of continue... + }*/ /** * A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command! @@ -52,7 +52,7 @@ public class MinecraftChatModule extends Component { } /** - * 0 * The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here + * The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here */ public ConfigData excludedPlugins() { return getConfig().getData("excludedPlugins", new String[]{"ProtocolLib", "LibsDisguises", "JourneyMapServer"}); From 55c61cef98e6bf23a4fe53883f35145a5e247e7c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 15 Apr 2019 15:36:48 +0200 Subject: [PATCH 02/24] New command sys for /discord & inv link --- .../discordplugin/DiscordPlugin.java | 10 +- .../mccommands/AcceptMCCommand.java | 44 ------ .../mccommands/DeclineMCCommand.java | 32 ----- .../mccommands/DiscordMCCommand.java | 127 ++++++++++++++++++ .../mccommands/ReloadMCCommand.java | 26 ---- .../mccommands/ResetMCCommand.java | 35 ----- .../mccommands/VersionMCCommand.java | 20 --- 7 files changed, 132 insertions(+), 162 deletions(-) delete mode 100755 src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java delete mode 100755 src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java create mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java delete mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java delete mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java delete mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 6d71070..572e52d 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -10,8 +10,8 @@ import buttondevteam.discordplugin.listeners.MCListener; import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.mccommands.DiscordMCCommand; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; -import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.discordplugin.role.GameRoleModule; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; @@ -160,7 +160,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener getManager().registerCommand(new HelpCommand()); getManager().registerCommand(new DebugCommand()); getManager().registerCommand(new ConnectCommand()); - if (ResetMCCommand.resetting) //These will only execute if the chat is enabled + if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) .withTitle("Discord plugin restarted - chat connected.").build(), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm else if (getConfig().getBoolean("serverup", false)) { @@ -174,7 +174,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN) .withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART); - ResetMCCommand.resetting = false; //This is the last event handling this flag + DiscordMCCommand.resetting = false; //This is the last event handling this flag getConfig().set("serverup", true); saveConfig(); @@ -193,7 +193,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener for (IListener listener : CommonListeners.getListeners()) dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); - TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); + getCommand2MC().registerCommand(new DiscordMCCommand()); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase ? ((DiscordSenderBase) sender).getChromaUser() : null)); @@ -212,7 +212,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load EmbedObject embed; - if (ResetMCCommand.resetting) + if (DiscordMCCommand.resetting) embed = new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build(); else embed = new EmbedBuilder().withColor(Restart ? Color.ORANGE : Color.RED) diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java deleted file mode 100755 index 29ed176..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.DPUtils; -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.commands.ConnectCommand; -import buttondevteam.discordplugin.mcchat.MCChatUtils; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; -import org.bukkit.entity.Player; - -@CommandClass(modOnly = false, path = "accept") -public class AcceptMCCommand extends DiscordMCCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { // - "§6---- Accept Discord connection ----", // - "Accept a pending connection between your Discord and Minecraft account.", // - "To start the connection process, do §b/connect §r in the " + DPUtils.botmention() + " channel on Discord", // - "Usage: /" + alias + " accept" // - }; - } - - @Override - public boolean OnCommand(Player player, String alias, String[] args) { - String did = ConnectCommand.WaitingToConnect.get(player.getName()); - if (did == null) { - player.sendMessage("§cYou don't have a pending connection to Discord."); - return true; - } - DiscordPlayer dp = ChromaGamerBase.getUser(did, DiscordPlayer.class); - TBMCPlayer mcp = TBMCPlayerBase.getPlayer(player.getUniqueId(), TBMCPlayer.class); - dp.connectWith(mcp); - dp.save(); - mcp.save(); - ConnectCommand.WaitingToConnect.remove(player.getName()); - MCChatUtils.UnconnectedSenders.remove(did); //Remove all unconnected, will be recreated where needed - player.sendMessage("§bAccounts connected."); - return true; - } - -} diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java deleted file mode 100755 index 813d6b9..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java +++ /dev/null @@ -1,32 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.DPUtils; -import buttondevteam.discordplugin.commands.ConnectCommand; -import buttondevteam.lib.chat.CommandClass; -import org.bukkit.entity.Player; - -@CommandClass(modOnly = false, path = "decline") -public class DeclineMCCommand extends DiscordMCCommandBase { - - @Override - public String[] GetHelpText(String alias) { - return new String[] { // - "§6---- Decline Discord connection ----", // - "Decline a pending connection between your Discord and Minecraft account.", // - "To start the connection process, do §b/connect §r in the " + DPUtils.botmention() + " channel on Discord", // - "Usage: /" + alias + " decline" // - }; - } - - @Override - public boolean OnCommand(Player player, String alias, String[] args) { - String did = ConnectCommand.WaitingToConnect.remove(player.getName()); - if (did == null) { - player.sendMessage("§cYou don't have a pending connection to Discord."); - return true; - } - player.sendMessage("§bPending connection declined."); - return true; - } - -} diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java new file mode 100644 index 0000000..7fa76d0 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -0,0 +1,127 @@ +package buttondevteam.discordplugin.mccommands; + +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.discordplugin.commands.VersionCommand; +import buttondevteam.discordplugin.mcchat.MCChatUtils; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.Command2MCSender; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2MC; +import buttondevteam.lib.player.ChromaGamerBase; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerBase; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.lang.reflect.Method; + +@CommandClass(path = "discord", helpText = { + "Discord", + "This command allows performing Discord-related actions." +}) +public class DiscordMCCommand extends ICommand2MC { + @Command2.Subcommand + public boolean accept(Player player) { + String did = ConnectCommand.WaitingToConnect.get(player.getName()); + if (did == null) { + player.sendMessage("§cYou don't have a pending connection to Discord."); + return true; + } + DiscordPlayer dp = ChromaGamerBase.getUser(did, DiscordPlayer.class); + TBMCPlayer mcp = TBMCPlayerBase.getPlayer(player.getUniqueId(), TBMCPlayer.class); + dp.connectWith(mcp); + dp.save(); + mcp.save(); + ConnectCommand.WaitingToConnect.remove(player.getName()); + MCChatUtils.UnconnectedSenders.remove(did); //Remove all unconnected, will be recreated where needed + player.sendMessage("§bAccounts connected."); + return true; + } + + @Command2.Subcommand + public boolean decline(Player player) { + String did = ConnectCommand.WaitingToConnect.remove(player.getName()); + if (did == null) { + player.sendMessage("§cYou don't have a pending connection to Discord."); + return true; + } + player.sendMessage("§bPending connection declined."); + return true; + } + + @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = { + "Reload Discord plugin", + "Reloads the config. To apply some changes, you may need to also run /discord reset." + }) + public void reload(CommandSender sender) { + if (DiscordPlugin.plugin.tryReloadConfig()) + sender.sendMessage("§bConfig reloaded."); + else + sender.sendMessage("§cFailed to reload config."); + } + + public static boolean resetting = false; + + @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = { + "Reset ChromaBot", // + "This command disables and then enables the plugin." // + }) + public void reset(CommandSender sender) { + Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { + resetting = true; //Turned off after sending enable message (ReadyEvent) + sender.sendMessage("§bDisabling DiscordPlugin..."); + Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); + if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors + sender.sendMessage("§bEnabling DiscordPlugin..."); + Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin); + if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors + sender.sendMessage("§bReset finished!"); + }); + } + + @Command2.Subcommand(helpText = { + "Version command", + "Prints the plugin version" + }) + public void version(CommandSender sender) { + sender.sendMessage(VersionCommand.getVersion()); + } + + @Command2.Subcommand(helpText = { + "Invite", + "Shows an invite link to the server" + }) + public void invite(CommandSender sender) { + val inv=DiscordPlugin.mainServer.getExtendedInvites().stream().findAny(); //TODO: Needs manage server perms + if (!inv.isPresent()) + sender.sendMessage("§cNo invites found for the server."); + else + sender.sendMessage("§bInvite link: https://discord.gg/"+inv.get().getCode()); + } + + @Override + public String[] getHelpText(Method method, Command2.Subcommand ann) { + switch (method.getName()) { + case "accept": + return new String[]{ // + "Accept Discord connection", // + "Accept a pending connection between your Discord and Minecraft account.", // + "To start the connection process, do §b/connect §r in the " + DPUtils.botmention() + " channel on Discord", // + }; + case "decline": + return new String[]{ // + "Decline Discord connection", // + "Decline a pending connection between your Discord and Minecraft account.", // + "To start the connection process, do §b/connect §r in the " + DPUtils.botmention() + " channel on Discord", // + }; + default: + return super.getHelpText(method, ann); + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java deleted file mode 100644 index 01433c9..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; -import org.bukkit.command.CommandSender; - -@CommandClass(path = "discord reload") -public class ReloadMCCommand extends TBMCCommandBase { - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - if (DiscordPlugin.plugin.tryReloadConfig()) - sender.sendMessage("§bConfig reloaded."); //TODO: Convert to new command system - else - sender.sendMessage("§cFailed to reload config."); - return true; - } - - @Override - public String[] GetHelpText(String alias) { - return new String[]{ - "Reload", - "Reloads the config. To apply some changes, you may need to also run /discord reset." - }; - } -} diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java deleted file mode 100644 index 1f4855f..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java +++ /dev/null @@ -1,35 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.DiscordSenderBase; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; - -@CommandClass(path = "discord reset", modOnly = true) -public class ResetMCCommand extends TBMCCommandBase { //Not player-only, so not using DiscordMCCommandBase - public static boolean resetting = false; - @Override - public boolean OnCommand(CommandSender sender, String s, String[] strings) { - Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { - resetting = true; //Turned off after sending enable message (ReadyEvent) - sender.sendMessage("§bDisabling DiscordPlugin..."); - Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); - if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors - sender.sendMessage("§bEnabling DiscordPlugin..."); - Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin); - if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors - sender.sendMessage("§bReset finished!"); - }); - return true; - } - - @Override - public String[] GetHelpText(String s) { - return new String[]{ // - "§6---- Reset ChromaBot ----", // - "This command disables and then enables the plugin." // - }; - } -} diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java deleted file mode 100644 index a2cacba..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.commands.VersionCommand; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; -import org.bukkit.command.CommandSender; - -@CommandClass(path = "discord version") -public class VersionMCCommand extends TBMCCommandBase { - @Override - public boolean OnCommand(CommandSender commandSender, String s, String[] strings) { - commandSender.sendMessage(VersionCommand.getVersion()); - return true; - } - - @Override - public String[] GetHelpText(String s) { - return VersionCommand.getVersion(); //Heh - } -} From d8d75c063b0cf07d8dd115d8eba8c56ca95aa94e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 13:52:01 +0200 Subject: [PATCH 03/24] Started converting to new D4J #93 --- pom.xml | 4 +- .../discordplugin/ChromaBot.java | 106 +---- .../buttondevteam/discordplugin/DPUtils.java | 80 +--- .../discordplugin/DiscordPlugin.java | 446 ++++++++---------- .../discordplugin/mcchat/MCChatUtils.java | 77 ++- 5 files changed, 249 insertions(+), 464 deletions(-) diff --git a/pom.xml b/pom.xml index 1007123..7a38cc9 100755 --- a/pom.xml +++ b/pom.xml @@ -173,8 +173,8 @@ com.discord4j - Discord4J - 2.10.1 + discord4j-core + 3.0.2 diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index 56a6fb9..81a43d1 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -1,15 +1,14 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MCChatUtils; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; import lombok.Getter; -import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; -import sx.blah.discord.api.internal.json.objects.EmbedObject; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.util.EmbedBuilder; +import reactor.core.publisher.Mono; import javax.annotation.Nullable; -import java.awt.*; +import java.util.function.Function; public class ChromaBot { /** @@ -33,113 +32,26 @@ public class ChromaBot { instance = null; } - /** - * Send a message to the chat channel and private chats. - * - * @param message - * The message to send, duh - */ - public void sendMessage(String message) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message)); - } - /** * Send a message to the chat channels and private chats. * * @param message - * The message to send, duh - * @param embed - * Custom fancy stuff, use {@link EmbedBuilder} to create one + * The message to send, duh (use {@link MessageChannel#createMessage(String)}) */ - public void sendMessage(String message, EmbedObject embed) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); + public void sendMessage(Function> message) { + MCChatUtils.forAllMCChat(ch -> message.apply(ch).subscribe()); } /** * Send a message to the chat channels, private chats and custom chats. * * @param message The message to send, duh - * @param embed Custom fancy stuff, use {@link EmbedBuilder} to create one * @param toggle The toggle type for channelcon */ - public void sendMessageCustomAsWell(String message, EmbedObject embed, @Nullable ChannelconBroadcast toggle) { - MCChatUtils.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed), toggle, false); + public void sendMessageCustomAsWell(Function> message, @Nullable ChannelconBroadcast toggle) { + MCChatUtils.forCustomAndAllMCChat(ch -> message.apply(ch).subscribe(), toggle, false); } - /** - * Send a message to an arbitrary channel. This will not send it to the private chats. - * - * @param channel - * The channel to send to, use the channel variables in {@link DiscordPlugin} - * @param message - * The message to send, duh - * @param embed - * Custom fancy stuff, use {@link EmbedBuilder} to create one - */ - public void sendMessage(IChannel channel, String message, EmbedObject embed) { - DiscordPlugin.sendMessageToChannel(channel, message, embed); - } - - /** - * Send a fancy message to the chat channels. This will show a bold text with a colored line. - * - * @param message - * The message to send, duh - * @param color - * The color of the line before the text - */ - public void sendMessage(String message, Color color) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, - new EmbedBuilder().withTitle(message).withColor(color).build())); - } - - /** - * Send a fancy message to the chat channels. This will show a bold text with a colored line. - * - * @param message - * The message to send, duh - * @param color - * The color of the line before the text - * @param mcauthor - * The name of the Minecraft player who is the author of this message - */ - public void sendMessage(String message, Color color, String mcauthor) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, - DPUtils.embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), mcauthor).build())); - } - - /** - * Send a fancy message to the chat channels. This will show a bold text with a colored line. - * - * @param message - * The message to send, duh - * @param color - * The color of the line before the text - * @param authorname - * The name of the author of this message - * @param authorimg - * The URL of the avatar image for this message's author - */ - public void sendMessage(String message, Color color, String authorname, String authorimg) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, new EmbedBuilder() - .withTitle(message).withColor(color).withAuthorName(authorname).withAuthorIcon(authorimg).build())); - } - - /** - * Send a message to the chat channels. This will show a bold text with a colored line. - * - * @param message - * The message to send, duh - * @param color - * The color of the line before the text - * @param sender - * The player who sends this message - */ - public void sendMessage(String message, Color color, Player sender) { - MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, DPUtils - .embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), sender.getName()).build())); - } - public void updatePlayerList() { MCChatUtils.updatePlayerList(); } diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index c21cceb..4b40968 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -4,20 +4,14 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; +import discord4j.core.object.entity.Channel; +import discord4j.core.object.entity.Guild; +import discord4j.core.object.entity.Role; +import discord4j.core.object.util.Snowflake; import lombok.val; -import org.bukkit.Bukkit; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IGuild; -import sx.blah.discord.handle.obj.IIDLinkedObject; -import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.util.EmbedBuilder; -import sx.blah.discord.util.RequestBuffer; -import sx.blah.discord.util.RequestBuffer.IRequest; -import sx.blah.discord.util.RequestBuffer.IVoidRequest; import javax.annotation.Nullable; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -53,55 +47,6 @@ public final class DPUtils { return sanitizedString; } - /** - * Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode. - */ - @Nullable - public static T perform(IRequest action, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { - if (DiscordPlugin.SafeMode) - return null; - if (Bukkit.isPrimaryThread()) // TODO: Ignore shutdown message <-- - // throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag."); - getLogger().warning("Waiting for a Discord request on the main thread!"); - return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this - } - - /** - * Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode. - */ - @Nullable - public static T perform(IRequest action) { - if (DiscordPlugin.SafeMode) - return null; - if (Bukkit.isPrimaryThread()) // TODO: Ignore shutdown message <-- - // throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag."); - getLogger().warning("Waiting for a Discord request on the main thread!"); - return RequestBuffer.request(action).get(); // Let the pros handle this - } - - /** - * Performs Discord actions, retrying when ratelimited. - */ - public static Void perform(IVoidRequest action) { - if (DiscordPlugin.SafeMode) - return null; - if (Bukkit.isPrimaryThread()) - throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag."); - return RequestBuffer.request(action).get(); // Let the pros handle this - } - - public static void performNoWait(IVoidRequest action) { - if (DiscordPlugin.SafeMode) - return; - RequestBuffer.request(action); - } - - public static void performNoWait(IRequest action) { - if (DiscordPlugin.SafeMode) - return; - RequestBuffer.request(action); - } - public static String escape(String message) { return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\")+"$1"); } @@ -112,20 +57,19 @@ public final class DPUtils { return DiscordPlugin.plugin.getLogger(); } - public static ConfigData channelData(IHaveConfig config, String key, long defID) { - return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getChannelByID((long) id), IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer) + public static ConfigData channelData(IHaveConfig config, String key, long defID) { + return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).block(), ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer) } - public static ConfigData roleData(IHaveConfig config, String key, String defName) { + public static ConfigData roleData(IHaveConfig config, String key, String defName) { return roleData(config, key, defName, DiscordPlugin.mainServer); } - public static ConfigData roleData(IHaveConfig config, String key, String defName, IGuild guild) { + public static ConfigData roleData(IHaveConfig config, String key, String defName, Guild guild) { return config.getDataPrimDef(key, defName, name -> { if (!(name instanceof String)) return null; - val roles = guild.getRolesByName((String) name); - return roles.size() > 0 ? roles.get(0) : null; - }, IIDLinkedObject::getLongID); + return guild.getRoles().filter(r -> r.getName().equals(name)).blockFirst(); + }, r -> r.getId().asLong()); } /** @@ -134,10 +78,10 @@ public final class DPUtils { * @return The string for mentioning the channel */ public static String botmention() { - IChannel channel; + Channel channel; if (DiscordPlugin.plugin == null || (channel = DiscordPlugin.plugin.CommandChannel().get()) == null) return "#bot"; - return channel.mention(); + return channel.getMention(); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 572e52d..cb73ea1 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -11,15 +11,23 @@ import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommand; -import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.role.GameRoleModule; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; +import discord4j.core.DiscordClient; +import discord4j.core.DiscordClientBuilder; +import discord4j.core.event.domain.lifecycle.ReadyEvent; +import discord4j.core.object.entity.Channel; +import discord4j.core.object.entity.Guild; +import discord4j.core.object.entity.Role; +import discord4j.core.object.presence.Activity; +import discord4j.core.object.presence.Presence; +import discord4j.core.object.reaction.ReactionEmoji; +import discord4j.core.object.util.Snowflake; import lombok.Getter; import lombok.val; import net.milkbowl.vault.permission.Permission; @@ -28,212 +36,194 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.scheduler.BukkitTask; -import sx.blah.discord.api.ClientBuilder; -import sx.blah.discord.api.IDiscordClient; -import sx.blah.discord.api.events.IListener; -import sx.blah.discord.api.internal.json.objects.EmbedObject; -import sx.blah.discord.handle.impl.events.ReadyEvent; -import sx.blah.discord.handle.impl.obj.ReactionEmoji; -import sx.blah.discord.handle.obj.*; -import sx.blah.discord.util.EmbedBuilder; -import sx.blah.discord.util.RequestBuffer; import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -public class DiscordPlugin extends ButtonPlugin implements IListener { - public static IDiscordClient dc; - public static DiscordPlugin plugin; - public static boolean SafeMode = true; +public class DiscordPlugin extends ButtonPlugin { + public static DiscordClient dc; + public static DiscordPlugin plugin; + public static boolean SafeMode = true; @Getter private Command2DC manager; public ConfigData Prefix() { - return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); - } - - public static char getPrefix() { - if (plugin == null) return '/'; - return plugin.Prefix().get(); - } - - public ConfigData MainServer() { - return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildByID((long) id), IIDLinkedObject::getLongID); + return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); } - public ConfigData CommandChannel() { + public static char getPrefix() { + if (plugin == null) return '/'; + return plugin.Prefix().get(); + } + + public ConfigData MainServer() { + return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); + } + + public ConfigData CommandChannel() { return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); } - public ConfigData ModRole() { + public ConfigData ModRole() { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); } - @Override - public void pluginEnable() { - try { - getLogger().info("Initializing..."); - plugin = this; - manager = new Command2DC(); - ClientBuilder cb = new ClientBuilder(); - File tokenFile = new File("TBMC", "Token.txt"); - if (tokenFile.exists()) //Legacy support - //noinspection UnstableApiUsage - cb.withToken(Files.readFirstLine(tokenFile, StandardCharsets.UTF_8)); - else { - File privateFile = new File(getDataFolder(), "private.yml"); - val conf = YamlConfiguration.loadConfiguration(privateFile); - String token = conf.getString("token"); - if (token == null) { - conf.set("token", "Token goes here"); - conf.save(privateFile); + @Override + public void pluginEnable() { + try { + getLogger().info("Initializing..."); + plugin = this; + manager = new Command2DC(); + String token; + File tokenFile = new File("TBMC", "Token.txt"); + if (tokenFile.exists()) //Legacy support + //noinspection UnstableApiUsage + token = Files.readFirstLine(tokenFile, StandardCharsets.UTF_8); + else { + File privateFile = new File(getDataFolder(), "private.yml"); + val conf = YamlConfiguration.loadConfiguration(privateFile); + token = conf.getString("token"); + if (token == null) { + conf.set("token", "Token goes here"); + conf.save(privateFile); - getLogger().severe("Token not found! Set it in private.yml"); - Bukkit.getPluginManager().disablePlugin(this); - return; - } else - cb.withToken(token); - } - dc = cb.login(); - dc.getDispatcher().registerListener(this); - } catch (Exception e) { - e.printStackTrace(); - Bukkit.getPluginManager().disablePlugin(this); - } - } + getLogger().severe("Token not found! Set it in private.yml"); + Bukkit.getPluginManager().disablePlugin(this); + return; + } + } + val cb = new DiscordClientBuilder(token); + dc = cb.build(); + dc.getEventDispatcher().on(ReadyEvent.class).subscribe(this::handleReady); + } catch (Exception e) { + e.printStackTrace(); + Bukkit.getPluginManager().disablePlugin(this); + } + } - public static IGuild mainServer; + public static Guild mainServer; - private static volatile BukkitTask task; - private static volatile boolean sent = false; + private static volatile BukkitTask task; + private static volatile boolean sent = false; - @Override - public void handle(ReadyEvent event) { - try { - dc.changePresence(StatusType.DND, ActivityType.PLAYING, "booting"); - val tries = new AtomicInteger(); - task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { - tries.incrementAndGet(); - if (tries.get() > 10) { //5 seconds - task.cancel(); - getLogger().severe("Main server not found! Invite the bot and do /discord reset"); - //getIConfig().getConfig().set("mainServer", 219529124321034241L); //Needed because it won't save as long as it's null - made it save - saveConfig(); //Put default there - return; - } - mainServer = MainServer().get(); //Shouldn't change afterwards - if (mainServer == null) { - val guilds = dc.getGuilds(); - if (guilds.size() == 0) - return; //If there are no guilds in cache, retry - mainServer = guilds.get(0); - getLogger().warning("Main server set to first one: " + mainServer.getName()); - MainServer().set(mainServer); //Save in config - } - if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Minecraft"); - } else { - dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); - } - SafeMode = false; - if (task != null) - task.cancel(); - if (!sent) { - DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here + public void handleReady(ReadyEvent event) { + try { + dc.updatePresence(Presence.doNotDisturb(Activity.playing("booting"))).subscribe(); + val tries = new AtomicInteger(); + task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { + tries.incrementAndGet(); + if (tries.get() > 10) { //5 seconds + task.cancel(); + getLogger().severe("Main server not found! Invite the bot and do /discord reset"); + //getIConfig().getConfig().set("mainServer", 219529124321034241L); //Needed because it won't save as long as it's null - made it save + saveConfig(); //Put default there + return; + } + mainServer = MainServer().get(); //Shouldn't change afterwards + if (mainServer == null) { + val guilds = dc.getGuilds(); + if (guilds.count().blockOptional().orElse(0L) == 0L) + return; //If there are no guilds in cache, retry + mainServer = guilds.blockFirst(); + if (mainServer == null) return; + getLogger().warning("Main server set to first one: " + mainServer.getName()); + MainServer().set(mainServer); //Save in config + } + if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() + dc.updatePresence(Presence.online(Activity.playing("Minecraft"))); + } else { + dc.updatePresence(Presence.online(Activity.playing("testing"))); + } + SafeMode = false; + if (task != null) + task.cancel(); + if (!sent) { + DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here - Component.registerComponent(this, new GeneralEventBroadcasterModule()); - Component.registerComponent(this, new MinecraftChatModule()); - Component.registerComponent(this, new ExceptionListenerModule()); - Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set - Component.registerComponent(this, new AnnouncerModule()); + Component.registerComponent(this, new GeneralEventBroadcasterModule()); + Component.registerComponent(this, new MinecraftChatModule()); + Component.registerComponent(this, new ExceptionListenerModule()); + Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set + Component.registerComponent(this, new AnnouncerModule()); Component.registerComponent(this, new FunModule()); - new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled + new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled - getManager().registerCommand(new VersionCommand()); - getManager().registerCommand(new UserinfoCommand()); - getManager().registerCommand(new HelpCommand()); - getManager().registerCommand(new DebugCommand()); - getManager().registerCommand(new ConnectCommand()); - if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) - .withTitle("Discord plugin restarted - chat connected.").build(), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm - else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.YELLOW) - .withTitle("Server recovered from a crash - chat connected.").build(), ChannelconBroadcast.RESTART); - val thr = new Throwable( - "The server shut down unexpectedly. See the log of the previous run for more details."); - thr.setStackTrace(new StackTraceElement[0]); - TBMCCoreAPI.SendException("The server crashed!", thr); - } else - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN) - .withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART); + getManager().registerCommand(new VersionCommand()); + getManager().registerCommand(new UserinfoCommand()); + getManager().registerCommand(new HelpCommand()); + getManager().registerCommand(new DebugCommand()); + getManager().registerCommand(new ConnectCommand()); + if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) + .withTitle("Discord plugin restarted - chat connected.").build(), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm + else if (getConfig().getBoolean("serverup", false)) { + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.YELLOW) + .withTitle("Server recovered from a crash - chat connected.").build(), ChannelconBroadcast.RESTART); + val thr = new Throwable( + "The server shut down unexpectedly. See the log of the previous run for more details."); + thr.setStackTrace(new StackTraceElement[0]); + TBMCCoreAPI.SendException("The server crashed!", thr); + } else + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN) + .withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART); - DiscordMCCommand.resetting = false; //This is the last event handling this flag + DiscordMCCommand.resetting = false; //This is the last event handling this flag - getConfig().set("serverup", true); - saveConfig(); - sent = true; - if (TBMCCoreAPI.IsTestServer() && !dc.getOurUser().getName().toLowerCase().contains("test")) { - TBMCCoreAPI.SendException( - "Won't load because we're in testing mode and not using a separate account.", - new Exception( - "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)")); - Bukkit.getPluginManager().disablePlugin(this); - } - TBMCCoreAPI.SendUnsentExceptions(); - TBMCCoreAPI.SendUnsentDebugMessages(); - } - }, 0, 10); - for (IListener listener : CommonListeners.getListeners()) - dc.getDispatcher().registerListener(listener); - TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); - getCommand2MC().registerCommand(new DiscordMCCommand()); - TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase - ? ((DiscordSenderBase) sender).getChromaUser() : null)); - setupProviders(); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); - } - } + getConfig().set("serverup", true); + saveConfig(); + sent = true; + if (TBMCCoreAPI.IsTestServer() && !event.getSelf().getUsername().toLowerCase().contains("test")) { + TBMCCoreAPI.SendException( + "Won't load because we're in testing mode and not using a separate account.", + new Exception( + "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)")); + Bukkit.getPluginManager().disablePlugin(this); + } + TBMCCoreAPI.SendUnsentExceptions(); + TBMCCoreAPI.SendUnsentDebugMessages(); + } + }, 0, 10); + for (IListener listener : CommonListeners.getListeners()) + dc.getDispatcher().registerListener(listener); + TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); + getCommand2MC().registerCommand(new DiscordMCCommand()); + TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); + ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase + ? ((DiscordSenderBase) sender).getChromaUser() : null)); + setupProviders(); + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); + } + } /** - * Always true, except when running "stop" from console - */ - public static boolean Restart; + * Always true, except when running "stop" from console + */ + public static boolean Restart; @Override public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load - EmbedObject embed; - if (DiscordMCCommand.resetting) - embed = new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build(); - else - embed = new EmbedBuilder().withColor(Restart ? Color.ORANGE : Color.RED) - .withTitle(Restart ? "Server restarting" : "Server stopping") - .withDescription( - Bukkit.getOnlinePlayers().size() > 0 - ? (DPUtils - .sanitizeString(Bukkit.getOnlinePlayers().stream() - .map(Player::getDisplayName).collect(Collectors.joining(", "))) - + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") - + "kicked the hell out.") //TODO: Make configurable - : "") //If 'restart' is disabled then this isn't shown even if joinleave is enabled - .build(); - MCChatUtils.forCustomAndAllMCChat(ch -> { - try { - DiscordPlugin.sendMessageToChannelWait(ch, "", - embed, 5, TimeUnit.SECONDS); - } catch (TimeoutException | InterruptedException e) { - e.printStackTrace(); - } - }, ChannelconBroadcast.RESTART, false); + MCChatUtils.forCustomAndAllMCChat(ch -> ch.createEmbed(ecs -> { + if (DiscordMCCommand.resetting) + ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting"); + else + ecs.setColor(Restart ? Color.ORANGE : Color.RED) + .setTitle(Restart ? "Server restarting" : "Server stopping") + .setDescription( + Bukkit.getOnlinePlayers().size() > 0 + ? (DPUtils + .sanitizeString(Bukkit.getOnlinePlayers().stream() + .map(Player::getDisplayName).collect(Collectors.joining(", "))) + + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") + + "kicked the hell out.") //TODO: Make configurable + : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled + }).block(Duration.ofSeconds(5)), ChannelconBroadcast.RESTART, false); ChromaBot.getInstance().updatePlayerList(); } @@ -244,93 +234,33 @@ public class DiscordPlugin extends ButtonPlugin implements IListener if (ChromaBot.getInstance() == null) return; //Failed to load saveConfig(); - try { - SafeMode = true; // Stop interacting with Discord - ChromaBot.delete(); - dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing - dc.logout(); - //Configs are emptied so channels and servers are fetched again - sent = false; - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); - } - } + try { + SafeMode = true; // Stop interacting with Discord + ChromaBot.delete(); + dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing + dc.logout().block(); + //Configs are emptied so channels and servers are fetched again + sent = false; + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); + } + } - public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.of("✅"); + public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.unicode("✅"); - public static void sendMessageToChannel(IChannel channel, String message) { - sendMessageToChannel(channel, message, null); - } + public static Permission perms; - public static void sendMessageToChannel(IChannel channel, String message, EmbedObject embed) { - try { - sendMessageToChannel(channel, message, embed, false); - } catch (TimeoutException | InterruptedException e) { - e.printStackTrace(); //Shouldn't happen, as we're not waiting on the result - } - } + public boolean setupProviders() { + try { + Class.forName("net.milkbowl.vault.permission.Permission"); + Class.forName("net.milkbowl.vault.chat.Chat"); + } catch (ClassNotFoundException e) { + return false; + } - public static IMessage sendMessageToChannelWait(IChannel channel, String message) throws TimeoutException, InterruptedException { - return sendMessageToChannelWait(channel, message, null); - } - - public static IMessage sendMessageToChannelWait(IChannel channel, String message, EmbedObject embed) throws TimeoutException, InterruptedException { - return sendMessageToChannel(channel, message, embed, true); - } - - public static IMessage sendMessageToChannelWait(IChannel channel, String message, EmbedObject embed, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { - return sendMessageToChannel(channel, message, embed, true, timeout, unit); - } - - private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait) throws TimeoutException, InterruptedException { - return sendMessageToChannel(channel, message, embed, wait, -1, null); - } - - private static IMessage sendMessageToChannel(IChannel channel, String message, EmbedObject embed, boolean wait, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { - if (message.length() > 1980) { - message = message.substring(0, 1980); - DPUtils.getLogger() - .warning("Message was too long to send to discord and got truncated. In " + channel.getName()); - } - try { - MCChatUtils.resetLastMessage(channel); // If this is a chat message, it'll be set again - final String content = message; - RequestBuffer.IRequest r = () -> embed == null ? channel.sendMessage(content) - : channel.sendMessage(content, embed, false); - if (wait) { - if (unit != null) - return DPUtils.perform(r, timeout, unit); - else - return DPUtils.perform(r); - } else { - if (unit != null) - plugin.getLogger().warning("Tried to set timeout for non-waiting call."); - else - DPUtils.performNoWait(r); - return null; - } - } catch (TimeoutException | InterruptedException e) { - throw e; - } catch (Exception e) { - DPUtils.getLogger().warning( - "Failed to deliver message to Discord! Channel: " + channel.getName() + " Message: " + message); - throw new RuntimeException(e); - } - } - - public static Permission perms; - - public boolean setupProviders() { - try { - Class.forName("net.milkbowl.vault.permission.Permission"); - Class.forName("net.milkbowl.vault.chat.Chat"); - } catch (ClassNotFoundException e) { - return false; - } - - RegisteredServiceProvider permsProvider = Bukkit.getServer().getServicesManager() - .getRegistration(Permission.class); - perms = permsProvider.getProvider(); - return perms != null; - } + RegisteredServiceProvider permsProvider = Bukkit.getServer().getServicesManager() + .getRegistration(Permission.class); + perms = permsProvider.getProvider(); + return perms != null; + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 3f04e56..6399d90 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -5,6 +5,10 @@ import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCSystemChatEvent; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.TextChannel; +import discord4j.core.object.entity.User; import io.netty.util.collection.LongObjectHashMap; import lombok.RequiredArgsConstructor; import lombok.experimental.var; @@ -16,9 +20,6 @@ import org.bukkit.event.HandlerList; import org.bukkit.plugin.AuthorNagException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; -import sx.blah.discord.handle.obj.IUser; import javax.annotation.Nullable; import java.util.Arrays; @@ -34,23 +35,21 @@ public class MCChatUtils { /** * May contain P<DiscordID> as key for public chat */ - public static final HashMap> UnconnectedSenders = new HashMap<>(); - public static final HashMap> ConnectedSenders = new HashMap<>(); + public static final HashMap> UnconnectedSenders = new HashMap<>(); + public static final HashMap> ConnectedSenders = new HashMap<>(); /** * May contain P<DiscordID> as key for public chat */ - public static final HashMap> OnlineSenders = new HashMap<>(); + public static final HashMap> OnlineSenders = new HashMap<>(); static @Nullable LastMsgData lastmsgdata; - static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks + static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks private static MinecraftChatModule module; public static void updatePlayerList() { if (notEnabled()) return; - DPUtils.performNoWait(() -> { - if (lastmsgdata != null) - updatePL(lastmsgdata); - MCChatCustom.lastmsgCustom.forEach(MCChatUtils::updatePL); - }); + if (lastmsgdata != null) + updatePL(lastmsgdata); + MCChatCustom.lastmsgCustom.forEach(MCChatUtils::updatePL); } private static boolean notEnabled() { @@ -64,8 +63,8 @@ public class MCChatUtils { } private static void updatePL(LastMsgData lmd) { - String topic = lmd.channel.getTopic(); - if (topic == null || topic.length() == 0) + String topic = lmd.channel.getTopic().orElse(""); + if (topic.length() == 0) topic = ".\n----\nMinecraft chat\n----\n."; String[] s = topic.split("\\n----\\n"); if (s.length < 3) @@ -74,16 +73,16 @@ public class MCChatUtils { + " online"; s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream() .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); - lmd.channel.changeTopic(String.join("\n----\n", s)); + lmd.channel.edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } - public static T addSender(HashMap> senders, - IUser user, T sender) { - return addSender(senders, user.getStringID(), sender); + public static T addSender(HashMap> senders, + User user, T sender) { + return addSender(senders, user.getId().asLong(), sender); } - public static T addSender(HashMap> senders, - String did, T sender) { + public static T addSender(HashMap> senders, + long did, T sender) { var map = senders.get(did); if (map == null) map = new HashMap<>(); @@ -92,23 +91,23 @@ public class MCChatUtils { return sender; } - public static T getSender(HashMap> senders, - IChannel channel, IUser user) { - var map = senders.get(user.getStringID()); + public static T getSender(HashMap> senders, + Channel channel, User user) { + var map = senders.get(user.getId().asLong()); if (map != null) return map.get(channel); return null; } - public static T removeSender(HashMap> senders, - IChannel channel, IUser user) { - var map = senders.get(user.getStringID()); + public static T removeSender(HashMap> senders, + Channel channel, User user) { + var map = senders.get(user.getId().asLong()); if (map != null) return map.remove(channel); return null; } - public static void forAllMCChat(Consumer action) { + public static void forAllMCChat(Consumer action) { if (notEnabled()) return; action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) @@ -123,7 +122,7 @@ public class MCChatUtils { * @param toggle The toggle to check * @param hookmsg Whether the message is also sent from the hook */ - public static void forCustomAndAllMCChat(Consumer action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + public static void forCustomAndAllMCChat(Consumer action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (notEnabled()) return; if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); @@ -141,7 +140,7 @@ public class MCChatUtils { * @param sender The sender to check perms of or null to send to all that has it toggled * @param toggle The toggle to check or null to send to all allowed */ - public static void forAllowedCustomMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { + public static void forAllowedCustomMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { if (notEnabled()) return; MCChatCustom.lastmsgCustom.stream().filter(clmd -> { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple @@ -161,19 +160,19 @@ public class MCChatUtils { * @param toggle The toggle to check or null to send to all allowed * @param hookmsg Whether the message is also sent from the hook */ - public static void forAllowedCustomAndAllMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + public static void forAllowedCustomAndAllMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (notEnabled()) return; if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); forAllowedCustomMCChat(action, sender, toggle); } - public static Consumer send(String message) { - return ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(message)); + public static Consumer send(String message) { + return ch -> ch.createMessage(DPUtils.sanitizeString(message)).subscribe(); } - public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { - if (notEnabled()) return; + public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { + if (notEnabled()) return if (event.getChannel().isGlobal()) action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) @@ -189,7 +188,7 @@ public class MCChatUtils { /** * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. */ - static DiscordSenderBase getSender(IChannel channel, final IUser author) { + static DiscordSenderBase getSender(Channel channel, final User author) { //noinspection OptionalGetWithoutIsPresent return Stream.>>of( // https://stackoverflow.com/a/28833677/2703239 () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null @@ -205,7 +204,7 @@ public class MCChatUtils { * * @param channel The channel to reset in - the process is slightly different for the public, private and custom chats */ - public static void resetLastMessage(IChannel channel) { + public static void resetLastMessage(Channel channel) { if (notEnabled()) return; if (channel.getLongID() == module.chatChannel().get().getLongID()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null) @@ -286,11 +285,11 @@ public class MCChatUtils { @RequiredArgsConstructor public static class LastMsgData { - public IMessage message; + public Message message; public long time; public String content; - public final IChannel channel; + public final TextChannel channel; public Channel mcchannel; - public final IUser user; + public final User user; } } From 12ca6fbfb578af189bae6655d3982dc2f013ba6a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 16:51:42 +0200 Subject: [PATCH 04/24] More converting --- .../buttondevteam/discordplugin/DPUtils.java | 74 ++++++++++--------- .../discordplugin/DiscordPlugin.java | 13 ++-- .../listeners/CommonListeners.java | 30 ++++---- .../discordplugin/role/GameRoleModule.java | 51 ++++++++----- 4 files changed, 93 insertions(+), 75 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 4b40968..9130495 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -4,12 +4,10 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; -import discord4j.core.object.entity.Channel; -import discord4j.core.object.entity.Guild; -import discord4j.core.object.entity.Role; +import discord4j.core.object.entity.*; import discord4j.core.object.util.Snowflake; +import discord4j.core.spec.EmbedCreateSpec; import lombok.val; -import sx.blah.discord.util.EmbedBuilder; import javax.annotation.Nullable; import java.util.logging.Logger; @@ -17,39 +15,39 @@ import java.util.regex.Matcher; public final class DPUtils { - public static EmbedBuilder embedWithHead(EmbedBuilder builder, String playername) { - return builder.withAuthorIcon("https://minotar.net/avatar/" + playername + "/32.png"); + public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String playername, String profileUrl) { + return ecs.setAuthor(playername, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png"); } - /** - * Removes §[char] colour codes from strings & escapes them for Discord
- * Ensure that this method only gets called once (escaping) - */ - public static String sanitizeString(String string) { - return escape(sanitizeStringNoEscape(string)); - } + /** + * Removes §[char] colour codes from strings & escapes them for Discord
+ * Ensure that this method only gets called once (escaping) + */ + public static String sanitizeString(String string) { + return escape(sanitizeStringNoEscape(string)); + } - /** - * Removes §[char] colour codes from strings - */ - public static String sanitizeStringNoEscape(String string) { - String sanitizedString = ""; - boolean random = false; - for (int i = 0; i < string.length(); i++) { - if (string.charAt(i) == '§') { - i++;// Skips the data value, the 4 in "§4Alisolarflare" - random = string.charAt(i) == 'k'; - } else { - if (!random) // Skip random/obfuscated characters - sanitizedString += string.charAt(i); - } - } - return sanitizedString; - } + /** + * Removes §[char] colour codes from strings + */ + public static String sanitizeStringNoEscape(String string) { + StringBuilder sanitizedString = new StringBuilder(); + boolean random = false; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) == '§') { + i++;// Skips the data value, the 4 in "§4Alisolarflare" + random = string.charAt(i) == 'k'; + } else { + if (!random) // Skip random/obfuscated characters + sanitizedString.append(string.charAt(i)); + } + } + return sanitizedString.toString(); + } - public static String escape(String message) { - return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\")+"$1"); - } + public static String escape(String message) { + return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\") + "$1"); + } public static Logger getLogger() { if (DiscordPlugin.plugin == null || DiscordPlugin.plugin.getLogger() == null) @@ -57,8 +55,14 @@ public final class DPUtils { return DiscordPlugin.plugin.getLogger(); } - public static ConfigData channelData(IHaveConfig config, String key, long defID) { - return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).block(), ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer) + public static ConfigData channelData(IHaveConfig config, String key, long defID) { + return config.getDataPrimDef(key, defID, id -> { + Channel ch = DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).block(); + if (ch instanceof MessageChannel) + return (MessageChannel) ch; + else + return null; + }, ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer) } public static ConfigData roleData(IHaveConfig config, String key, String defName) { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index cb73ea1..ccde74e 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -111,7 +111,7 @@ public class DiscordPlugin extends ButtonPlugin { private static volatile BukkitTask task; private static volatile boolean sent = false; - public void handleReady(ReadyEvent event) { + private void handleReady(ReadyEvent event) { try { dc.updatePresence(Presence.doNotDisturb(Activity.playing("booting"))).subscribe(); val tries = new AtomicInteger(); @@ -159,11 +159,11 @@ public class DiscordPlugin extends ButtonPlugin { getManager().registerCommand(new DebugCommand()); getManager().registerCommand(new ConnectCommand()); if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) - .withTitle("Discord plugin restarted - chat connected.").build(), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm + ChromaBot.getInstance().sendMessageCustomAsWell(ch->ch.createEmbed(ecs->ecs.setColor(Color.CYAN) + .setTitle("Discord plugin restarted - chat connected.")), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.YELLOW) - .withTitle("Server recovered from a crash - chat connected.").build(), ChannelconBroadcast.RESTART); + ChromaBot.getInstance().sendMessageCustomAsWell(ch->ch.createEmbed(ecs->ecs.setColor(Color.YELLOW) + .setTitle("Server recovered from a crash - chat connected.")), ChannelconBroadcast.RESTART); val thr = new Throwable( "The server shut down unexpectedly. See the log of the previous run for more details."); thr.setStackTrace(new StackTraceElement[0]); @@ -188,8 +188,7 @@ public class DiscordPlugin extends ButtonPlugin { TBMCCoreAPI.SendUnsentDebugMessages(); } }, 0, 10); - for (IListener listener : CommonListeners.getListeners()) - dc.getDispatcher().registerListener(listener); + CommonListeners.register(dc.getEventDispatcher()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); getCommand2MC().registerCommand(new DiscordMCCommand()); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 5350b32..44e0118 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -7,6 +7,12 @@ import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.role.GameRoleModule; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import discord4j.core.event.EventDispatcher; +import discord4j.core.event.domain.PresenceUpdateEvent; +import discord4j.core.event.domain.message.MessageCreateEvent; +import discord4j.core.event.domain.role.RoleCreateEvent; +import discord4j.core.event.domain.role.RoleDeleteEvent; +import discord4j.core.event.domain.role.RoleUpdateEvent; import lombok.val; import sx.blah.discord.api.events.IListener; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; @@ -26,10 +32,8 @@ public class CommonListeners { - Minecraft chat (is enabled in the channel and message isn't [/]mcchat) - CommandListener (with the correct prefix in #bot, or in private) */ - public static IListener[] getListeners() { - return new IListener[]{new IListener() { - @Override - public void handle(MessageReceivedEvent event) { + public static void register(EventDispatcher dispatcher) { + dispatcher.on(MessageCreateEvent.class).subscribe(event->{ if (DiscordPlugin.SafeMode) return; if (event.getMessage().getAuthor().isBot()) @@ -39,8 +43,8 @@ public class CommonListeners { try { boolean handled = false; val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); - if ((commandChannel != null && event.getChannel().getLongID() == commandChannel.getLongID()) //If mentioned, that's higher than chat - || event.getMessage().getContent().contains("channelcon")) //Only 'channelcon' is allowed in other channels + if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.getId().asLong()) //If mentioned, that's higher than chat + || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here if (handled) return; val mcchat = Component.getComponents().get(MinecraftChatModule.class); @@ -51,17 +55,15 @@ public class CommonListeners { } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while handling a message!", e); } - } - }, new IListener() { - @Override - public void handle(PresenceUpdateEvent event) { + }); + dispatcher.on(PresenceUpdateEvent.class).subscribe(event->{ if (DiscordPlugin.SafeMode) return; FunModule.handleFullHouse(event); - } - }, (IListener) GameRoleModule::handleRoleEvent, // - (IListener) GameRoleModule::handleRoleEvent, // - (IListener) GameRoleModule::handleRoleEvent}; + }); + dispatcher.on(RoleCreateEvent.class).subscribe(GameRoleModule::handleRoleEvent); + dispatcher.on(RoleDeleteEvent.class).subscribe(GameRoleModule::handleRoleEvent); + dispatcher.on(RoleUpdateEvent.class).subscribe(GameRoleModule::handleRoleEvent); } private static boolean debug = false; diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 8806647..03056dd 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -5,6 +5,12 @@ import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import discord4j.core.event.domain.role.RoleCreateEvent; +import discord4j.core.event.domain.role.RoleDeleteEvent; +import discord4j.core.event.domain.role.RoleEvent; +import discord4j.core.event.domain.role.RoleUpdateEvent; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.Role; import lombok.val; import org.bukkit.Bukkit; import sx.blah.discord.handle.impl.events.guild.role.RoleCreateEvent; @@ -24,7 +30,7 @@ public class GameRoleModule extends Component { @Override protected void enable() { getPlugin().getManager().registerCommand(new RoleCommand(this)); - GameRoles = DiscordPlugin.mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); + GameRoles = DiscordPlugin.mainServer.getRoles().filter(this::isGameRole).map(Role::getName).collect(Collectors.toList()).block(); } @Override @@ -32,7 +38,7 @@ public class GameRoleModule extends Component { } - private ConfigData logChannel() { + private ConfigData logChannel() { return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L); } @@ -43,41 +49,48 @@ public class GameRoleModule extends Component { val logChannel = grm.logChannel().get(); if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - if (roleEvent.getRole().isDeleted() || !grm.isGameRole(roleEvent.getRole())) + Role role=((RoleCreateEvent) roleEvent).getRole(); + if (!grm.isGameRole(role)) return; //Deleted or not a game role - GameRoles.add(roleEvent.getRole().getName()); + GameRoles.add(role.getName()); if (logChannel != null) - DiscordPlugin.sendMessageToChannel(logChannel, "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + logChannel.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default.").subscribe(); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { - if (GameRoles.remove(roleEvent.getRole().getName()) && logChannel != null) - DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + roleEvent.getRole().getName() + " as a game role."); + Role role=((RoleDeleteEvent) roleEvent).getRole().orElse(null); + if(role==null) return; + if (GameRoles.remove(role.getName()) && logChannel != null) + logChannel, "Removed " + role.getName() + " as a game role."); } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; - if (!grm.isGameRole(event.getNewRole())) { - if (GameRoles.remove(event.getOldRole().getName()) && logChannel != null) - DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + if(!event.getOld().isPresent()) { + DPUtils.getLogger().warning("Old role not stored, cannot update game role!"); + return; + } + Role or=event.getOld().get(); + if (!grm.isGameRole(event.getCurrent())) { + if (GameRoles.remove(or.getName()) && logChannel != null) + logChannel.createMessage("Removed " + or.getName() + " as a game role because it's color changed.").subscribe(); } else { - if (GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + if (GameRoles.contains(or.getName()) && or.getName().equals(event.getCurrent().getName())) return; - boolean removed = GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role - GameRoles.add(event.getNewRole().getName()); //Add it because it has no color + boolean removed = GameRoles.remove(or.getName()); //Regardless of whether it was a game role + GameRoles.add(event.getCurrent().getName()); //Add it because it has no color if (logChannel != null) { if (removed) - DiscordPlugin.sendMessageToChannel(logChannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + logChannel.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + ".").subscribe(); else - DiscordPlugin.sendMessageToChannel(logChannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + logChannel.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color.").subscribe(); } } } } - private boolean isGameRole(IRole r) { - if (r.getGuild().getLongID() != DiscordPlugin.mainServer.getLongID()) + private boolean isGameRole(Role r) { + if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) return false; //Only allow on the main server val rc = new Color(149, 165, 166, 0); return r.getColor().equals(rc) - && DiscordPlugin.dc.getOurUser().getRolesForGuild(DiscordPlugin.mainServer) - .stream().anyMatch(or -> r.getPosition() < or.getPosition()); //Below one of our roles + && DiscordPlugin.dc.getSelf().block().asMember(DiscordPlugin.mainServer.getId()).block().hasHigherRoles(r); //Below one of our roles } } From 95af050517e2a26ce27a986f9fe71d862e54cd16 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 17:54:08 +0200 Subject: [PATCH 05/24] The refactoring continues --- .../discordplugin/DiscordConnectedPlayer.java | 4 +- .../discordplugin/DiscordPlayer.java | 56 +++++++++---------- .../discordplugin/DiscordPlayerSender.java | 4 +- .../discordplugin/DiscordPlugin.java | 15 +++-- .../discordplugin/DiscordRunnable.java | 2 +- .../discordplugin/DiscordSender.java | 6 +- .../discordplugin/DiscordSenderBase.java | 8 +-- .../discordplugin/DiscordSupplier.java | 2 +- .../announcer/AnnouncerModule.java | 37 +++++------- .../commands/Command2DCSender.java | 10 +++- .../commands/UserinfoCommand.java | 4 +- .../exceptions/ExceptionListenerModule.java | 8 +-- .../discordplugin/fun/FunModule.java | 4 +- .../listeners/CommandListener.java | 10 ++-- .../mcchat/ChannelconCommand.java | 4 +- .../discordplugin/mcchat/MCChatCustom.java | 14 ++--- .../discordplugin/mcchat/MCChatListener.java | 10 ++-- .../discordplugin/mcchat/MCChatPrivate.java | 4 +- .../mcchat/MinecraftChatModule.java | 6 +- .../playerfaker/DiscordEntity.java | 4 +- .../playerfaker/DiscordFakePlayer.java | 4 +- .../playerfaker/DiscordHumanEntity.java | 4 +- .../playerfaker/DiscordLivingEntity.java | 4 +- .../discordplugin/role/GameRoleModule.java | 8 +-- 24 files changed, 114 insertions(+), 118 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index f5b779f..ff36dcb 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -3,8 +3,8 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import lombok.Getter; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.UUID; @@ -12,7 +12,7 @@ public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlay private static int nextEntityId = 10000; private @Getter VanillaCommandListener vanillaCmdListener; - public DiscordConnectedPlayer(IUser user, IChannel channel, UUID uuid, String mcname) { + public DiscordConnectedPlayer(IUser user, MessageChannel channel, UUID uuid, String mcname) { super(user, channel, nextEntityId++, uuid, mcname); vanillaCmdListener = new VanillaCommandListener<>(this); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java index 0055792..bbb9a75 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java @@ -1,28 +1,28 @@ -package buttondevteam.discordplugin; - -import buttondevteam.discordplugin.mcchat.MCChatPrivate; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.UserClass; - -@UserClass(foldername = "discord") -public class DiscordPlayer extends ChromaGamerBase { - private String did; - // private @Getter @Setter boolean minecraftChatEnabled; - - public DiscordPlayer() { - } - - public String getDiscordID() { - if (did == null) - did = plugindata.getString(getFolder() + "_id"); - return did; - } - - /** - * Returns true if player has the private Minecraft chat enabled. For setting the value, see - * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)} - */ - public boolean isMinecraftChatEnabled() { - return MCChatPrivate.isMinecraftChatEnabled(this); - } -} +package buttondevteam.discordplugin; + +import buttondevteam.discordplugin.mcchat.MCChatPrivate; +import buttondevteam.lib.player.ChromaGamerBase; +import buttondevteam.lib.player.UserClass; + +@UserClass(foldername = "discord") +public class DiscordPlayer extends ChromaGamerBase { + private String did; + // private @Getter @Setter boolean minecraftChatEnabled; + + public DiscordPlayer() { + } + + public String getDiscordID() { + if (did == null) + did = plugindata.getString(getFolder() + "_id"); + return did; + } + + /** + * Returns true if player has the private Minecraft chat enabled. For setting the value, see + * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.MessageChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)} + */ + public boolean isMinecraftChatEnabled() { + return MCChatPrivate.isMinecraftChatEnabled(this); + } +} diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 2c10314..1f30113 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -26,8 +26,8 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.net.InetSocketAddress; import java.util.*; @@ -38,7 +38,7 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< protected Player player; private @Getter VanillaCommandListener vanillaCmdListener; - public DiscordPlayerSender(IUser user, IChannel channel, Player player) { + public DiscordPlayerSender(IUser user, MessageChannel channel, Player player) { super(user, channel); this.player = player; vanillaCmdListener = new VanillaCommandListener(this); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index ccde74e..7980e37 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -21,8 +21,8 @@ import com.google.common.io.Files; import discord4j.core.DiscordClient; import discord4j.core.DiscordClientBuilder; import discord4j.core.event.domain.lifecycle.ReadyEvent; -import discord4j.core.object.entity.Channel; import discord4j.core.object.entity.Guild; +import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.Role; import discord4j.core.object.presence.Activity; import discord4j.core.object.presence.Presence; @@ -65,7 +65,7 @@ public class DiscordPlugin extends ButtonPlugin { return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); } - public ConfigData CommandChannel() { + public ConfigData CommandChannel() { return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); } @@ -100,6 +100,13 @@ public class DiscordPlugin extends ButtonPlugin { val cb = new DiscordClientBuilder(token); dc = cb.build(); dc.getEventDispatcher().on(ReadyEvent.class).subscribe(this::handleReady); + /*dc.getEventDispatcher().on(ReadyEvent.class) // Listen for ReadyEvent(s) + .map(event -> event.getGuilds().size()) // Get how many guilds the bot is in + .flatMap(size -> dc.getEventDispatcher() + .on(GuildCreateEvent.class) // Listen for GuildCreateEvent(s) + .take(size) // Take only the first `size` GuildCreateEvent(s) to be received + .collectList()) // Take all received GuildCreateEvents and make it a List + .subscribe(events -> /* All guilds have been received, client is fully connected *);*/ //TODO } catch (Exception e) { e.printStackTrace(); Bukkit.getPluginManager().disablePlugin(this); @@ -169,8 +176,8 @@ public class DiscordPlugin extends ButtonPlugin { thr.setStackTrace(new StackTraceElement[0]); TBMCCoreAPI.SendException("The server crashed!", thr); } else - ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN) - .withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART); + ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) + .setTitle("Server started - chat connected.")), ChannelconBroadcast.RESTART); DiscordMCCommand.resetting = false; //This is the last event handling this flag diff --git a/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java b/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java index fb27234..3e8094f 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java @@ -6,5 +6,5 @@ import sx.blah.discord.util.RateLimitException; @FunctionalInterface public interface DiscordRunnable { - public abstract void run() throws DiscordException, RateLimitException, MissingPermissionsException; + void run() throws DiscordException, RateLimitException, MissingPermissionsException; } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index 8ad7445..de1eed9 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -8,8 +8,8 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.Set; @@ -18,12 +18,12 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { private String name; - public DiscordSender(IUser user, IChannel channel) { + public DiscordSender(IUser user, MessageChannel channel) { super(user, channel); name = user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer); } - public DiscordSender(IUser user, IChannel channel, String name) { + public DiscordSender(IUser user, MessageChannel channel, String name) { super(user, channel); this.name = name; } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index 6d4098b..f16e92b 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -4,17 +4,17 @@ import buttondevteam.lib.TBMCCoreAPI; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitTask; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; public abstract class DiscordSenderBase implements CommandSender { /** * May be null. */ protected IUser user; - protected IChannel channel; + protected MessageChannel channel; - protected DiscordSenderBase(IUser user, IChannel channel) { + protected DiscordSenderBase(IUser user, MessageChannel channel) { this.user = user; this.channel = channel; } @@ -31,7 +31,7 @@ public abstract class DiscordSenderBase implements CommandSender { return user; } - public IChannel getChannel() { + public MessageChannel getChannel() { return channel; } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java b/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java index e2fb570..09b730a 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java @@ -7,5 +7,5 @@ import sx.blah.discord.util.RateLimitException; @FunctionalInterface public interface DiscordSupplier> { - public abstract T get() throws DiscordException, RateLimitException, MissingPermissionsException; + T get() throws DiscordException, RateLimitException, MissingPermissionsException; } diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index a0c11a0..690a085 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -11,23 +11,24 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; import lombok.val; import org.bukkit.configuration.file.YamlConfiguration; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; +import reactor.core.publisher.Flux; import java.io.File; -import java.util.List; +import java.util.Objects; public class AnnouncerModule extends Component { /** * Channel to post new posts. */ - public ConfigData channel() { + public ConfigData channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } - public ConfigData modChannel() { + public ConfigData modChannel() { return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L); } @@ -53,19 +54,11 @@ public class AnnouncerModule extends Component { protected void enable() { if (DPUtils.disableIfConfigError(this, channel(), modChannel())) return; stop = false; //If not the first time - DPUtils.performNoWait(() -> { - try { - val keepPinned = keepPinned().get(); - if (keepPinned == 0) return; - val channel = channel().get(); - List msgs = channel.getPinnedMessages(); - for (int i = msgs.size() - 1; i >= keepPinned; i--) { // Unpin all pinned messages except the newest 10 - channel.unpin(msgs.get(i)); - Thread.sleep(10); - } - } catch (InterruptedException ignore) { - } - }); + val keepPinned = keepPinned().get(); + if (keepPinned == 0) return; + val channel = channel().get(); + Flux msgs = channel.getPinnedMessages(); + msgs.subscribe(Message::unpin); val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change if (lastannouncementtime().get() == 0) //Load old data lastannouncementtime().set(yc.getLong("lastannouncementtime")); @@ -125,13 +118,11 @@ public class AnnouncerModule extends Component { } } if (msgsb.length() > 0) - channel().get().pin(DiscordPlugin.sendMessageToChannelWait(channel().get(), msgsb.toString())); + Objects.requireNonNull(channel().get().createMessage(msgsb.toString()).block()).pin().block(); if (modmsgsb.length() > 0) - DiscordPlugin.sendMessageToChannel(modChannel().get(), modmsgsb.toString()); - if (lastannouncementtime().get() != lastanntime) { + modChannel().get().createMessage(modmsgsb.toString()).block(); + if (lastannouncementtime().get() != lastanntime) lastannouncementtime().set(lastanntime); // If sending succeeded - getPlugin().saveConfig(); //TODO: Won't be needed if I implement auto-saving - } } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index bdff52d..831cf6c 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -2,20 +2,24 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DPUtils; import buttondevteam.lib.chat.Command2Sender; +import discord4j.core.object.entity.Message; import lombok.Getter; import lombok.RequiredArgsConstructor; -import sx.blah.discord.handle.obj.IMessage; +import lombok.val; @RequiredArgsConstructor public class Command2DCSender implements Command2Sender { - private final @Getter IMessage message; + private final @Getter + Message message; @Override public void sendMessage(String message) { if (message.length() == 0) return; message = DPUtils.sanitizeString(message); message = Character.toLowerCase(message.charAt(0)) + message.substring(1); - this.message.reply(message); + val msg = message; + this.message.getChannel().flatMap(ch -> ch.createMessage(this.message.getAuthorAsMember().a-> + a.getNicknameMention() + ", " + msg))) } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index 0433c81..0de8121 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -8,8 +8,8 @@ import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; import lombok.val; -import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.Message; import java.util.List; import java.util.Optional; @@ -78,7 +78,7 @@ public class UserinfoCommand extends ICommand2DC { return true; } - private List getUsers(IMessage message, String args) { + private List getUsers(Message message, String args) { final List targets; if (message.getChannel().isPrivate()) targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args)) diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 5d21bb1..f03b67a 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -11,9 +11,9 @@ import org.apache.commons.lang.exception.ExceptionUtils; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IGuild; import sx.blah.discord.handle.obj.IRole; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; import java.util.Arrays; @@ -47,7 +47,7 @@ public class ExceptionListenerModule extends Component implements private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; try { - IChannel channel = getChannel(); + MessageChannel channel = getChannel(); assert channel != null; IRole coderRole = instance.pingRole(channel.getGuild()).get(); StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() @@ -69,12 +69,12 @@ public class ExceptionListenerModule extends Component implements private static ExceptionListenerModule instance; - public static IChannel getChannel() { + public static MessageChannel getChannel() { if (instance != null) return instance.channel().get(); return null; } - private ConfigData channel() { + private ConfigData channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index e5faead..c3c21ad 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -80,7 +80,7 @@ public class FunModule extends Component implements Listener { private static short ListC = 0; - public static boolean executeMemes(IMessage message) { + public static boolean executeMemes(Message message) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return false; String msglowercased = message.getContent().toLowerCase(); @@ -119,7 +119,7 @@ public class FunModule extends Component implements Listener { } - private ConfigData fullHouseChannel() { + private ConfigData fullHouseChannel() { return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 4f99d35..69c27cf 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -3,9 +3,9 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; import buttondevteam.lib.TBMCCoreAPI; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IRole; +import sx.blah.discord.handle.obj.Message; +import sx.blah.discord.handle.obj.MessageChannel; public class CommandListener { /** @@ -15,10 +15,10 @@ public class CommandListener { * @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message * @return Whether it ran the command */ - public static boolean runCommand(IMessage message, boolean mentionedonly) { + public static boolean runCommand(Message message, boolean mentionedonly) { if (message.getContent().length() == 0) return false; //Pin messages and such, let the mcchat listener deal with it - final IChannel channel = message.getChannel(); + final MessageChannel channel = message.getChannel(); if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!message.getChannel().isPrivate() && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() @@ -49,7 +49,7 @@ public class CommandListener { return true; } - private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { + private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, Message message) { if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text if (cmdwithargs.length() > mention.length() + 1) { int i = cmdwithargs.indexOf(" ", mention.length()); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index 2bd2bb6..dba50e5 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -11,7 +11,7 @@ import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.handle.obj.IMessage; +import sx.blah.discord.handle.obj.Message; import sx.blah.discord.handle.obj.Permissions; import sx.blah.discord.util.PermissionUtils; @@ -124,7 +124,7 @@ public class ChannelconCommand extends ICommand2DC { return true; } - private boolean checkPerms(IMessage message) { + private boolean checkPerms(Message message) { if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { message.reply("you need to have manage permissions for this channel!"); return true; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 3d1b52f..8c4b6c2 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -6,8 +6,8 @@ import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.lib.TBMCSystemChatEvent; import lombok.NonNull; import lombok.val; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import javax.annotation.Nullable; import java.util.ArrayList; @@ -21,7 +21,7 @@ public class MCChatCustom { */ static ArrayList lastmsgCustom = new ArrayList<>(); - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { + public static void addCustomChat(MessageChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { if (mcchannel instanceof ChatRoom) { ((ChatRoom) mcchannel).joinRoom(dcp); if (groupid == null) groupid = mcchannel.getGroupID(dcp); @@ -30,16 +30,16 @@ public class MCChatCustom { lastmsgCustom.add(lmd); } - public static boolean hasCustomChat(IChannel channel) { + public static boolean hasCustomChat(MessageChannel channel) { return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID()); } @Nullable - public static CustomLMD getCustomChat(IChannel channel) { + public static CustomLMD getCustomChat(MessageChannel channel) { return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); } - public static boolean removeCustomChat(IChannel channel) { + public static boolean removeCustomChat(MessageChannel channel) { MCChatUtils.lastmsgfromd.remove(channel.getLongID()); return lastmsgCustom.removeIf(lmd -> { if (lmd.channel.getLongID() != channel.getLongID()) @@ -61,8 +61,8 @@ public class MCChatCustom { public int toggles; public Set brtoggles; - private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, - @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { + private CustomLMD(@NonNull MessageChannel channel, @NonNull IUser user, + @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { super(channel, user); groupID = groupid; this.mcchannel = mcchannel; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 5113f3c..ed52108 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -22,9 +22,9 @@ import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.api.internal.json.objects.EmbedObject; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.Message; +import sx.blah.discord.handle.obj.MessageChannel; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.MissingPermissionsException; @@ -121,7 +121,7 @@ public class MCChatListener implements Listener { }; // Checks if the given channel is different than where the message was sent from // Or if it was from MC - Predicate isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) + Predicate isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); if (e.getChannel().isGlobal() @@ -276,7 +276,7 @@ public class MCChatListener implements Listener { final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); } - for (IChannel ch : event.getMessage().getChannelMentions()) { + for (MessageChannel ch : event.getMessage().getChannelMentions()) { dmessage = dmessage.replace(ch.mention(), "#" + ch.getName()); // TODO: IG Formatting } @@ -285,7 +285,7 @@ public class MCChatListener implements Listener { Function getChatMessage = msg -> // msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() - .getAttachments().stream().map(IMessage.Attachment::getUrl).collect(Collectors.joining("\n")) + .getAttachments().stream().map(Message.Attachment::getUrl).collect(Collectors.joining("\n")) : ""); MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel()); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 7d87376..3a2f2f2 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -9,9 +9,9 @@ import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IPrivateChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; @@ -22,7 +22,7 @@ public class MCChatPrivate { */ static ArrayList lastmsgPerUser = new ArrayList<>(); - public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) { + public static boolean privateMCChat(MessageChannel channel, boolean start, IUser user, DiscordPlayer dp) { TBMCPlayer mcp = dp.getAs(TBMCPlayer.class); if (mcp != null) { // If the accounts aren't connected, can't make a connected sender val p = Bukkit.getPlayer(mcp.getUUID()); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 94ef49d..9e8cfe0 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -12,7 +12,7 @@ import com.google.common.collect.Lists; import lombok.Getter; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; import java.util.Objects; @@ -40,14 +40,14 @@ public class MinecraftChatModule extends Component { /** * The channel to use as the public Minecraft chat - everything public gets broadcasted here */ - public ConfigData chatChannel() { + public ConfigData chatChannel() { return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L); } /** * The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute */ - public ConfigData modlogChannel() { + public ConfigData modlogChannel() { return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L); } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java index 6ce85f8..61cfa5e 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java @@ -11,8 +11,8 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.*; @@ -20,7 +20,7 @@ import java.util.*; @Setter @SuppressWarnings("deprecated") public abstract class DiscordEntity extends DiscordSenderBase implements Entity { - protected DiscordEntity(IUser user, IChannel channel, int entityId, UUID uuid) { + protected DiscordEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { super(user, channel); this.entityId = entityId; uniqueId = uuid; diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index a2b4a13..e7d1c74 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -16,15 +16,15 @@ import org.bukkit.map.MapView; import org.bukkit.permissions.PermissibleBase; import org.bukkit.plugin.Plugin; import org.bukkit.scoreboard.Scoreboard; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.net.InetSocketAddress; import java.util.*; @SuppressWarnings("deprecation") public class DiscordFakePlayer extends DiscordHumanEntity implements Player { - protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid, String mcname) { + protected DiscordFakePlayer(IUser user, MessageChannel channel, int entityId, UUID uuid, String mcname) { super(user, channel, entityId, uuid); perm = new PermissibleBase(Bukkit.getOfflinePlayer(uuid)); name = mcname; diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java index c1522f1..f984b6c 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java @@ -8,13 +8,13 @@ import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Villager; import org.bukkit.inventory.*; import org.bukkit.inventory.InventoryView.Property; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.UUID; public abstract class DiscordHumanEntity extends DiscordLivingEntity implements HumanEntity { - protected DiscordHumanEntity(IUser user, IChannel channel, int entityId, UUID uuid) { + protected DiscordHumanEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { super(user, channel, entityId, uuid); } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java index f261de4..876d17e 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java @@ -16,14 +16,14 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.MessageChannel; import java.util.*; public abstract class DiscordLivingEntity extends DiscordEntity implements LivingEntity { - protected DiscordLivingEntity(IUser user, IChannel channel, int entityId, UUID uuid) { + protected DiscordLivingEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { super(user, channel, entityId, uuid); } diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 03056dd..916f116 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -13,12 +13,6 @@ import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.Role; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.handle.impl.events.guild.role.RoleCreateEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleDeleteEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleUpdateEvent; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IRole; import java.awt.*; import java.util.List; @@ -60,7 +54,7 @@ public class GameRoleModule extends Component { Role role=((RoleDeleteEvent) roleEvent).getRole().orElse(null); if(role==null) return; if (GameRoles.remove(role.getName()) && logChannel != null) - logChannel, "Removed " + role.getName() + " as a game role."); + logChannel, "Removed " + role.getName() + " as a game role.") } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; if(!event.getOld().isPresent()) { From 038cb98f1a2cf91ab10e5385708b5c78a3f7944b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 13:29:52 +0200 Subject: [PATCH 06/24] Refactoring & made mcchat teleport config --- .../discordplugin/DiscordConnectedPlayer.java | 9 +- .../discordplugin/DiscordPlayer.java | 2 +- .../discordplugin/DiscordPlayerSender.java | 6 +- .../discordplugin/DiscordSender.java | 6 +- .../discordplugin/DiscordSenderBase.java | 15 +- .../commands/ConnectCommand.java | 10 +- .../commands/UserinfoCommand.java | 20 +- .../discordplugin/fun/FunModule.java | 2 +- .../listeners/CommandListener.java | 30 +- .../discordplugin/listeners/MCListener.java | 6 +- .../mcchat/ChannelconCommand.java | 4 +- .../discordplugin/mcchat/MCChatCommand.java | 2 +- .../discordplugin/mcchat/MCChatCustom.java | 22 +- .../discordplugin/mcchat/MCChatListener.java | 679 +++++++++--------- .../discordplugin/mcchat/MCChatPrivate.java | 10 +- .../discordplugin/mcchat/MCChatUtils.java | 14 +- .../discordplugin/mcchat/MCListener.java | 6 +- .../mcchat/MinecraftChatModule.java | 31 +- .../playerfaker/DiscordEntity.java | 28 +- .../playerfaker/DiscordFakePlayer.java | 13 +- .../playerfaker/DiscordHumanEntity.java | 9 +- .../playerfaker/DiscordLivingEntity.java | 9 +- 22 files changed, 488 insertions(+), 445 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index ff36dcb..de96b18 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -1,10 +1,11 @@ package buttondevteam.discordplugin; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import lombok.Getter; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.UUID; @@ -12,8 +13,8 @@ public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlay private static int nextEntityId = 10000; private @Getter VanillaCommandListener vanillaCmdListener; - public DiscordConnectedPlayer(IUser user, MessageChannel channel, UUID uuid, String mcname) { - super(user, channel, nextEntityId++, uuid, mcname); + public DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { + super(user, channel, nextEntityId++, uuid, mcname ,module); vanillaCmdListener = new VanillaCommandListener<>(this); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java index bbb9a75..d748433 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java @@ -20,7 +20,7 @@ public class DiscordPlayer extends ChromaGamerBase { /** * Returns true if player has the private Minecraft chat enabled. For setting the value, see - * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.MessageChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)} + * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.MessageChannel, boolean, sx.blah.discord.handle.obj.User, DiscordPlayer)} */ public boolean isMinecraftChatEnabled() { return MCChatPrivate.isMinecraftChatEnabled(this); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 1f30113..807abd4 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -1,6 +1,8 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import lombok.Getter; import org.bukkit.*; import org.bukkit.advancement.Advancement; @@ -26,8 +28,6 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.net.InetSocketAddress; import java.util.*; @@ -38,7 +38,7 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< protected Player player; private @Getter VanillaCommandListener vanillaCmdListener; - public DiscordPlayerSender(IUser user, MessageChannel channel, Player player) { + public DiscordPlayerSender(User user, MessageChannel channel, Player player) { super(user, channel); this.player = player; vanillaCmdListener = new VanillaCommandListener(this); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index de1eed9..7b87b5d 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -8,7 +8,7 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; import sx.blah.discord.handle.obj.MessageChannel; import java.util.Set; @@ -18,12 +18,12 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { private String name; - public DiscordSender(IUser user, MessageChannel channel) { + public DiscordSender(User user, MessageChannel channel) { super(user, channel); name = user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer); } - public DiscordSender(IUser user, MessageChannel channel, String name) { + public DiscordSender(User user, MessageChannel channel, String name) { super(user, channel); this.name = name; } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index f16e92b..145a8c0 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -1,20 +1,20 @@ package buttondevteam.discordplugin; import buttondevteam.lib.TBMCCoreAPI; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitTask; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; public abstract class DiscordSenderBase implements CommandSender { /** * May be null. */ - protected IUser user; + protected User user; protected MessageChannel channel; - protected DiscordSenderBase(IUser user, MessageChannel channel) { + protected DiscordSenderBase(User user, MessageChannel channel) { this.user = user; this.channel = channel; } @@ -27,7 +27,7 @@ public abstract class DiscordSenderBase implements CommandSender { * * @return The user or null. */ - public IUser getUser() { + public User getUser() { return user; } @@ -43,7 +43,7 @@ public abstract class DiscordSenderBase implements CommandSender { * @return A Chroma user of Discord or a Discord user of Chroma */ public DiscordPlayer getChromaUser() { - if (chromaUser == null) chromaUser = DiscordPlayer.getUser(user.getStringID(), DiscordPlayer.class); + if (chromaUser == null) chromaUser = DiscordPlayer.getUser(user.getId().asString(), DiscordPlayer.class); return chromaUser; } @@ -58,8 +58,7 @@ public abstract class DiscordSenderBase implements CommandSender { msgtosend += "\n" + sendmsg; if (sendtask == null) sendtask = Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - DiscordPlugin.sendMessageToChannel(channel, - (!broadcast && user != null ? user.mention() + "\n" : "") + msgtosend.trim()); + channel.createMessage((!broadcast && user != null ? user.getMention() + "\n" : "") + msgtosend.trim()); sendtask = null; msgtosend = ""; }, 4); // Waits a 0.2 second to gather all/most of the different messages diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index 4e37e35..a4c829e 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -28,10 +28,10 @@ public class ConnectCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String Minecraftname) { val message = sender.getMessage(); - if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { + if (WaitingToConnect.inverse().containsKey(message.getAuthor().getId().asString())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getStringID()) + " with " + Minecraftname); - WaitingToConnect.inverse().remove(message.getAuthor().getStringID()); + "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getId().asString()) + " with " + Minecraftname); + WaitingToConnect.inverse().remove(message.getAuthor().getId().asString()); } @SuppressWarnings("deprecation") OfflinePlayer p = Bukkit.getOfflinePlayer(Minecraftname); @@ -41,7 +41,7 @@ public class ConnectCommand extends ICommand2DC { } try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { DiscordPlayer dp = pl.getAs(DiscordPlayer.class); - if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) { + if (dp != null && message.getAuthor().getId().asString().equals(dp.getDiscordID())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); return true; } @@ -49,7 +49,7 @@ public class ConnectCommand extends ICommand2DC { TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An internal error occured!\n" + e); } - WaitingToConnect.put(p.getName(), message.getAuthor().getStringID()); + WaitingToConnect.put(p.getName(), message.getAuthor().getId().asString()); DiscordPlugin.sendMessageToChannel(message.getChannel(), "Alright! Now accept the connection in Minecraft from the account " + Minecraftname + " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command."); diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index 0de8121..83242ae 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -8,7 +8,7 @@ import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; import lombok.val; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; import sx.blah.discord.handle.obj.Message; import java.util.List; @@ -24,23 +24,23 @@ public class UserinfoCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, @Command2.OptionalArg @Command2.TextArg String user) { val message = sender.getMessage(); - IUser target = null; + User target = null; if (user == null || user.length() == 0) target = message.getAuthor(); else { - final Optional firstmention = message.getMentions().stream() - .filter(m -> !m.getStringID().equals(DiscordPlugin.dc.getOurUser().getStringID())).findFirst(); + final Optional firstmention = message.getMentions().stream() + .filter(m -> !m.getId().asString().equals(DiscordPlugin.dc.getSelf().getId().asString())).findFirst(); if (firstmention.isPresent()) target = firstmention.get(); else if (user.contains("#")) { String[] targettag = user.split("#"); - final List targets = getUsers(message, targettag[0]); + final List targets = getUsers(message, targettag[0]); if (targets.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The user cannot be found (by name): " + user); return true; } - for (IUser ptarget : targets) { + for (User ptarget : targets) { if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { target = ptarget; break; @@ -53,7 +53,7 @@ public class UserinfoCommand extends ICommand2DC { return true; } } else { - final List targets = getUsers(message, user); + final List targets = getUsers(message, user); if (targets.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The user cannot be found on Discord: " + user); @@ -67,7 +67,7 @@ public class UserinfoCommand extends ICommand2DC { target = targets.get(0); } } - try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getStringID(), DiscordPlayer.class)) { + try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getId().asString(), DiscordPlayer.class)) { StringBuilder uinfo = new StringBuilder("User info for ").append(target.getName()).append(":\n"); uinfo.append(dp.getInfo(InfoTarget.Discord)); DiscordPlugin.sendMessageToChannel(message.getChannel(), uinfo.toString()); @@ -78,8 +78,8 @@ public class UserinfoCommand extends ICommand2DC { return true; } - private List getUsers(Message message, String args) { - final List targets; + private List getUsers(Message message, String args) { + final List targets; if (message.getChannel().isPrivate()) targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args)) .collect(Collectors.toList()); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index c3c21ad..ee72a6a 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -135,7 +135,7 @@ public class FunModule extends Component implements Listener { if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) && event.getUser().getRolesForGuild(channel.getGuild()).stream() - .anyMatch(r -> r.getLongID() == devrole.getLongID()) + .anyMatch(r -> r.getId().asLong() == devrole.getId().asLong()) && channel.getGuild().getUsersByRole(devrole).stream() .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 69c27cf..a12a665 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -3,6 +3,10 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; import buttondevteam.lib.TBMCCoreAPI; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.PrivateChannel; +import lombok.val; import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.Message; import sx.blah.discord.handle.obj.MessageChannel; @@ -16,22 +20,28 @@ public class CommandListener { * @return Whether it ran the command */ public static boolean runCommand(Message message, boolean mentionedonly) { - if (message.getContent().length() == 0) + if (message.getContent().isEmpty()) return false; //Pin messages and such, let the mcchat listener deal with it - final MessageChannel channel = message.getChannel(); + final MessageChannel channel = message.getChannel().block(); + @SuppressWarnings("OptionalGetWithoutIsPresent") val content = message.getContent().get(); + if (channel == null) return false; if (!mentionedonly) { //mentionedonly conditions are in CommonListeners - if (!message.getChannel().isPrivate() - && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() - && channel.getStringID().equals(DiscordPlugin.plugin.CommandChannel().get().getStringID()))) // + if (!(channel instanceof PrivateChannel) + && !(content.charAt(0) == DiscordPlugin.getPrefix() + && channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().getId().asString()))) // return false; - message.getChannel().setTypingStatus(true); // Fun + channel.type().subscribe(); // Fun } - final StringBuilder cmdwithargs = new StringBuilder(message.getContent()); - final String mention = DiscordPlugin.dc.getOurUser().mention(false); - final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); + final StringBuilder cmdwithargs = new StringBuilder(content); + val self=DiscordPlugin.dc.getSelf().block(); + if(self==null) return false; + val member=self.asMember(DiscordPlugin.mainServer.getId()).block(); + if(member==null) return false; + final String mention = self.getMention(); + final String mentionNick = member.getNicknameMention(); boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention; - for (String mentionRole : (Iterable) message.getRoleMentions().stream().filter(r -> DiscordPlugin.dc.getOurUser().hasRole(r)).map(IRole::mention)::iterator) + for (String mentionRole : (Iterable) message.getRoleMentions().filter(r -> member.getRoles().filter(r)).map(IRole::mention)::iterator) //TODO: Remove all that matches gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions if (mentionedonly && !gotmention) { message.getChannel().setTypingStatus(false); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index c23b8fa..e41713c 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -8,13 +8,13 @@ import buttondevteam.lib.player.TBMCPlayerJoinEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.server.ServerCommandEvent; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; public class MCListener implements Listener { @EventHandler public void onPlayerJoin(TBMCPlayerJoinEvent e) { if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { - @SuppressWarnings("ConstantConditions") IUser user = DiscordPlugin.dc + @SuppressWarnings("ConstantConditions") User user = DiscordPlugin.dc .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); e.getPlayer().sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() + " do /discord accept"); @@ -29,7 +29,7 @@ public class MCListener implements Listener { DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class); if (dp == null || dp.getDiscordID() == null || dp.getDiscordID().equals("")) return; - IUser user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); + User user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); e.addInfo("Discord tag: " + user.getName() + "#" + user.getDiscriminator()); e.addInfo(user.getPresence().getStatus().toString()); if (user.getPresence().getActivity().isPresent() && user.getPresence().getText().isPresent()) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index dba50e5..fad76fc 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -95,7 +95,7 @@ public class ChannelconCommand extends ICommand2DC { message.reply("MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /."); return true; } - val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class); + val dp = DiscordPlayer.getUser(message.getAuthor().getId().asString(), DiscordPlayer.class); val chp = dp.getAs(TBMCPlayer.class); if (chp == null) { message.reply("you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect "); @@ -140,7 +140,7 @@ public class ChannelconCommand extends ICommand2DC { "You need to have access to the MC channel and have manage permissions on the Discord channel.", // "You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect .", // "Call this command from the channel you want to use.", // - "Usage: @" + DiscordPlugin.dc.getOurUser().getName() + " channelcon ", // + "Usage: @" + DiscordPlugin.dc.getSelf().getName() + " channelcon ", // "Use the ID (command) of the channel, for example `g` for the global chat.", // "To remove a connection use @ChromaBot channelcon remove in the channel.", // "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", // diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index 23af46f..c579818 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -24,7 +24,7 @@ public class MCChatCommand extends ICommand2DC { message.reply("this command can only be issued in a direct message with the bot."); return true; } - try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) { + try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getId().asString(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); message.reply("Minecraft chat " + (mcchat // diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 8c4b6c2..7302ad6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -4,10 +4,12 @@ import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.ChatRoom; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.lib.TBMCSystemChatEvent; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.TextChannel; +import discord4j.core.object.entity.User; +import discord4j.core.object.util.Snowflake; import lombok.NonNull; import lombok.val; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import javax.annotation.Nullable; import java.util.ArrayList; @@ -21,7 +23,7 @@ public class MCChatCustom { */ static ArrayList lastmsgCustom = new ArrayList<>(); - public static void addCustomChat(MessageChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { + public static void addCustomChat(MessageChannel channel, String groupid, Channel mcchannel, User user, DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { if (mcchannel instanceof ChatRoom) { ((ChatRoom) mcchannel).joinRoom(dcp); if (groupid == null) groupid = mcchannel.getGroupID(dcp); @@ -30,19 +32,19 @@ public class MCChatCustom { lastmsgCustom.add(lmd); } - public static boolean hasCustomChat(MessageChannel channel) { - return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID()); + public static boolean hasCustomChat(Snowflake channel) { + return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getId().asLong() == channel.asLong()); } @Nullable public static CustomLMD getCustomChat(MessageChannel channel) { - return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); + return lastmsgCustom.stream().filter(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()).findAny().orElse(null); } public static boolean removeCustomChat(MessageChannel channel) { - MCChatUtils.lastmsgfromd.remove(channel.getLongID()); + MCChatUtils.lastmsgfromd.remove(channel.getId().asLong()); return lastmsgCustom.removeIf(lmd -> { - if (lmd.channel.getLongID() != channel.getLongID()) + if (lmd.channel.getId().asLong() != channel.getId().asLong()) return false; if (lmd.mcchannel instanceof ChatRoom) ((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp); @@ -61,9 +63,9 @@ public class MCChatCustom { public int toggles; public Set brtoggles; - private CustomLMD(@NonNull MessageChannel channel, @NonNull IUser user, + private CustomLMD(@NonNull MessageChannel channel, @NonNull User user, @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { - super(channel, user); + super((TextChannel) channel, user); groupID = groupid; this.mcchannel = mcchannel; this.dcp = dcp; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index ed52108..ee2a6fb 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -14,6 +14,11 @@ import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; +import discord4j.core.event.domain.message.MessageCreateEvent; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.PrivateChannel; +import discord4j.core.object.entity.TextChannel; +import discord4j.core.spec.EmbedCreateSpec; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -22,7 +27,7 @@ import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.api.internal.json.objects.EmbedObject; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; import sx.blah.discord.handle.obj.Message; import sx.blah.discord.handle.obj.MessageChannel; import sx.blah.discord.util.DiscordException; @@ -41,10 +46,10 @@ import java.util.function.Predicate; import java.util.stream.Collectors; public class MCChatListener implements Listener { - private BukkitTask sendtask; - private LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); - private Runnable sendrunnable; - private static Thread sendthread; + private BukkitTask sendtask; + private LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); + private Runnable sendrunnable; + private static Thread sendthread; private final MinecraftChatModule module; public MCChatListener(MinecraftChatModule minecraftChatModule) { @@ -52,359 +57,361 @@ public class MCChatListener implements Listener { } @EventHandler // Minecraft - public void onMCChat(TBMCChatEvent ev) { - if (!ComponentManager.isEnabled(MinecraftChatModule.class) || ev.isCancelled()) //SafeMode: Needed so it doesn't restart after server shutdown - return; - sendevents.add(new AbstractMap.SimpleEntry<>(ev, Instant.now())); - if (sendtask != null) - return; - sendrunnable = () -> { - sendthread = Thread.currentThread(); - processMCToDiscord(); - if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down - sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); - }; - sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); - } + public void onMCChat(TBMCChatEvent ev) { + if (!ComponentManager.isEnabled(MinecraftChatModule.class) || ev.isCancelled()) //SafeMode: Needed so it doesn't restart after server shutdown + return; + sendevents.add(new AbstractMap.SimpleEntry<>(ev, Instant.now())); + if (sendtask != null) + return; + sendrunnable = () -> { + sendthread = Thread.currentThread(); + processMCToDiscord(); + if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down + sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); + }; + sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); + } - private void processMCToDiscord() { - try { - TBMCChatEvent e; - Instant time; - val se = sendevents.take(); // Wait until an element is available - e = se.getKey(); - time = se.getValue(); + private void processMCToDiscord() { + try { + TBMCChatEvent e; + Instant time; + val se = sendevents.take(); // Wait until an element is available + e = se.getKey(); + time = se.getValue(); - final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName().get()) + "] " // - + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin().substring(0, 1) + "]") // - + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // - ? ((Player) e.getSender()).getDisplayName() // - : e.getSender().getName())); - val color = e.getChannel().Color().get(); - final EmbedBuilder embed = new EmbedBuilder().withAuthorName(authorPlayer) - .withDescription(e.getMessage()).withColor(new Color(color.getRed(), - color.getGreen(), color.getBlue())); - // embed.appendField("Channel", ((e.getSender() instanceof DiscordSenderBase ? "d|" : "") - // + DiscordPlugin.sanitizeString(e.getChannel().DisplayName)), false); - if (e.getSender() instanceof Player) - DPUtils.embedWithHead( - embed.withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=minecraft&id=" - + ((Player) e.getSender()).getUniqueId()), - e.getSender().getName()); - else if (e.getSender() instanceof DiscordSenderBase) - embed.withAuthorIcon(((DiscordSenderBase) e.getSender()).getUser().getAvatarURL()) - .withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=discord&id=" - + ((DiscordSenderBase) e.getSender()).getUser().getStringID()); // TODO: Constant/method to get URLs like this - // embed.withFooterText(e.getChannel().DisplayName); - embed.withTimestamp(time); - final long nanoTime = System.nanoTime(); - InterruptibleConsumer doit = lastmsgdata -> { - final EmbedObject embedObject = embed.build(); - if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() - || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) - || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 - || !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) { - lastmsgdata.message = DiscordPlugin.sendMessageToChannelWait(lastmsgdata.channel, "", - embedObject); // TODO Use ChromaBot API - lastmsgdata.time = nanoTime; - lastmsgdata.mcchannel = e.getChannel(); - lastmsgdata.content = embedObject.description; - } else - try { - lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n" - + embedObject.description;// The message object doesn't get updated - final MCChatUtils.LastMsgData _lastmsgdata = lastmsgdata; - DPUtils.perform(() -> _lastmsgdata.message.edit("", embedObject)); - } catch (MissingPermissionsException | DiscordException e1) { - TBMCCoreAPI.SendException("An error occurred while editing chat message!", e1); - } - }; - // Checks if the given channel is different than where the message was sent from - // Or if it was from MC + final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName().get()) + "] " // + + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin().substring(0, 1) + "]") // + + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // + ? ((Player) e.getSender()).getDisplayName() // + : e.getSender().getName())); + val color = e.getChannel().Color().get(); + final EmbedCreateSpec embed = new EmbedBuilder().withAuthorName(authorPlayer) + .withDescription(e.getMessage()).withColor(new Color(color.getRed(), + color.getGreen(), color.getBlue())); + // embed.appendField("Channel", ((e.getSender() instanceof DiscordSenderBase ? "d|" : "") + // + DiscordPlugin.sanitizeString(e.getChannel().DisplayName)), false); + if (e.getSender() instanceof Player) + DPUtils.embedWithHead( + embed.withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=minecraft&id=" + + ((Player) e.getSender()).getUniqueId()), + e.getSender().getName()); + else if (e.getSender() instanceof DiscordSenderBase) + embed.withAuthorIcon(((DiscordSenderBase) e.getSender()).getUser().getAvatarURL()) + .withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=discord&id=" + + ((DiscordSenderBase) e.getSender()).getUser().getId().asString()); // TODO: Constant/method to get URLs like this + // embed.withFooterText(e.getChannel().DisplayName); + embed.withTimestamp(time); + final long nanoTime = System.nanoTime(); + InterruptibleConsumer doit = lastmsgdata -> { + final EmbedObject embedObject = embed.build(); + if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() + || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) + || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 + || !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) { + lastmsgdata.message = DiscordPlugin.sendMessageToChannelWait(lastmsgdata.channel, "", + embedObject); // TODO Use ChromaBot API + lastmsgdata.time = nanoTime; + lastmsgdata.mcchannel = e.getChannel(); + lastmsgdata.content = embedObject.description; + } else + try { + lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n" + + embedObject.description;// The message object doesn't get updated + lastmsgdata.message.edit(mes -> mes.setEmbed(ecs -> embedObject)).block(); + } catch (MissingPermissionsException | DiscordException e1) { + TBMCCoreAPI.SendException("An error occurred while editing chat message!", e1); + } + }; + // Checks if the given channel is different than where the message was sent from + // Or if it was from MC Predicate isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) - || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); + || ((DiscordSenderBase) e.getSender()).getChannel().getId().asLong() != ch.getId().asLong(); - if (e.getChannel().isGlobal() - && (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get()))) - doit.accept(MCChatUtils.lastmsgdata == null - ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null) - : MCChatUtils.lastmsgdata); + if (e.getChannel().isGlobal() + && (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get()))) + doit.accept(MCChatUtils.lastmsgdata == null + ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData((TextChannel) module.chatChannel().get(), null) + : MCChatUtils.lastmsgdata); - for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { - if ((e.isFromCommand() || isdifferentchannel.test(data.channel)) - && e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user))) - doit.accept(data); - } + for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { + if ((e.isFromCommand() || isdifferentchannel.test(data.channel)) + && e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user))) + doit.accept(data); + } - val iterator = MCChatCustom.lastmsgCustom.iterator(); - while (iterator.hasNext()) { - val lmd = iterator.next(); - if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord - && e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it - && e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58 - if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions - doit.accept(lmd); - else { - iterator.remove(); //If the user no longer has permission, remove the connection - DiscordPlugin.sendMessageToChannel(lmd.channel, "The user no longer has permission to view the channel, connection removed."); - } - } - } - } catch (InterruptedException ex) { //Stop if interrupted anywhere - sendtask.cancel(); - sendtask = null; - } catch (Exception ex) { - TBMCCoreAPI.SendException("Error while sending message to Discord!", ex); - } - } + val iterator = MCChatCustom.lastmsgCustom.iterator(); + while (iterator.hasNext()) { + val lmd = iterator.next(); + if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord + && e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it + && e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58 + if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions + doit.accept(lmd); + else { + iterator.remove(); //If the user no longer has permission, remove the connection + DiscordPlugin.sendMessageToChannel(lmd.channel, "The user no longer has permission to view the channel, connection removed."); + } + } + } + } catch (InterruptedException ex) { //Stop if interrupted anywhere + sendtask.cancel(); + sendtask = null; + } catch (Exception ex) { + TBMCCoreAPI.SendException("Error while sending message to Discord!", ex); + } + } - @EventHandler - public void onChatPreprocess(TBMCChatPreprocessEvent event) { - int start = -1; - while ((start = event.getMessage().indexOf('@', start + 1)) != -1) { - int mid = event.getMessage().indexOf('#', start + 1); - if (mid == -1) - return; - int end_ = event.getMessage().indexOf(' ', mid + 1); - if (end_ == -1) - end_ = event.getMessage().length(); - final int end = end_; - final int startF = start; - DiscordPlugin.dc.getUsersByName(event.getMessage().substring(start + 1, mid)).stream() - .filter(u -> u.getDiscriminator().equals(event.getMessage().substring(mid + 1, end))).findAny() - .ifPresent(user -> event.setMessage(event.getMessage().substring(0, startF) + "@" + user.getName() - + (event.getMessage().length() > end ? event.getMessage().substring(end) : ""))); // TODO: Add formatting - start = end; // Skip any @s inside the mention - } - } + @EventHandler + public void onChatPreprocess(TBMCChatPreprocessEvent event) { + int start = -1; + while ((start = event.getMessage().indexOf('@', start + 1)) != -1) { + int mid = event.getMessage().indexOf('#', start + 1); + if (mid == -1) + return; + int end_ = event.getMessage().indexOf(' ', mid + 1); + if (end_ == -1) + end_ = event.getMessage().length(); + final int end = end_; + final int startF = start; + val user = DiscordPlugin.dc.getUsers().filter(u -> u.getUsername().equals(event.getMessage().substring(startF + 1, mid))) + .filter(u -> u.getDiscriminator().equals(event.getMessage().substring(mid + 1, end))).blockFirst(); + if (user != null) //TODO: Nicknames + event.setMessage(event.getMessage().substring(0, startF) + "@" + user.getUsername() + + (event.getMessage().length() > end ? event.getMessage().substring(end) : "")); // TODO: Add formatting + start = end; // Skip any @s inside the mention + } + } - // ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender - // Offline public chat......x............................................ - // Online public chat.......x...........................................x - // Offline private chat.....x.......................x.................... - // Online private chat......x.......................x...................x - // If online and enabling private chat, don't login - // If leaving the server and private chat is enabled (has ConnectedPlayer), call login in a task on lowest priority - // If private chat is enabled and joining the server, logout the fake player on highest priority - // If online and disabling private chat, don't logout - // The maps may not contain the senders for UnconnectedSenders + // ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender + // Offline public chat......x............................................ + // Online public chat.......x...........................................x + // Offline private chat.....x.......................x.................... + // Online private chat......x.......................x...................x + // If online and enabling private chat, don't login + // If leaving the server and private chat is enabled (has ConnectedPlayer), call login in a task on lowest priority + // If private chat is enabled and joining the server, logout the fake player on highest priority + // If online and disabling private chat, don't logout + // The maps may not contain the senders for UnconnectedSenders - /** - * Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode. - * - * @param wait Wait 5 seconds for the threads to stop - */ - public static void stop(boolean wait) { - if (sendthread != null) sendthread.interrupt(); - if (recthread != null) recthread.interrupt(); - try { - if (sendthread != null) { - sendthread.interrupt(); - if (wait) - sendthread.join(5000); - } - if (recthread != null) { - recthread.interrupt(); - if (wait) - recthread.join(5000); - } - MCChatUtils.lastmsgdata = null; - MCChatPrivate.lastmsgPerUser.clear(); - MCChatCustom.lastmsgCustom.clear(); - MCChatUtils.lastmsgfromd.clear(); - MCChatUtils.ConnectedSenders.clear(); - MCChatUtils.UnconnectedSenders.clear(); - recthread = sendthread = null; - } catch (InterruptedException e) { - e.printStackTrace(); //This thread shouldn't be interrupted - } - } + /** + * Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode. + * + * @param wait Wait 5 seconds for the threads to stop + */ + public static void stop(boolean wait) { + if (sendthread != null) sendthread.interrupt(); + if (recthread != null) recthread.interrupt(); + try { + if (sendthread != null) { + sendthread.interrupt(); + if (wait) + sendthread.join(5000); + } + if (recthread != null) { + recthread.interrupt(); + if (wait) + recthread.join(5000); + } + MCChatUtils.lastmsgdata = null; + MCChatPrivate.lastmsgPerUser.clear(); + MCChatCustom.lastmsgCustom.clear(); + MCChatUtils.lastmsgfromd.clear(); + MCChatUtils.ConnectedSenders.clear(); + MCChatUtils.UnconnectedSenders.clear(); + recthread = sendthread = null; + } catch (InterruptedException e) { + e.printStackTrace(); //This thread shouldn't be interrupted + } + } - private BukkitTask rectask; - private LinkedBlockingQueue recevents = new LinkedBlockingQueue<>(); - private Runnable recrun; - private static Thread recthread; + private BukkitTask rectask; + private LinkedBlockingQueue recevents = new LinkedBlockingQueue<>(); + private Runnable recrun; + private static Thread recthread; // Discord - public boolean handleDiscord(MessageReceivedEvent ev) { - if (!ComponentManager.isEnabled(MinecraftChatModule.class)) - return false; - val author = ev.getMessage().getAuthor(); - final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getChannel()); - if (ev.getMessage().getChannel().getLongID() != module.chatChannel().get().getLongID() - && !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID())) - && !hasCustomChat) + public boolean handleDiscord(MessageCreateEvent ev) { + if (!ComponentManager.isEnabled(MinecraftChatModule.class)) + return false; + val author = ev.getMessage().getAuthor(); + final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); + val channel = ev.getMessage().getChannel().block(); + if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().getId().asLong() + && !(channel instanceof PrivateChannel + && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) + && !hasCustomChat)) return false; //Chat isn't enabled on this channel - if (ev.getMessage().getChannel().isPrivate() //Only in private chat - && ev.getMessage().getContent().length() < "/mcchat<>".length() - && ev.getMessage().getContent().replace("/", "") - .equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat + if (channel instanceof PrivateChannel //Only in private chat + && ev.getMessage().getContent().isPresent() + && ev.getMessage().getContent().get().length() < "/mcchat<>".length() + && ev.getMessage().getContent().get().replace("/", "") + .equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat return false; //Allow disabling the chat if needed - if (CommandListener.runCommand(ev.getMessage(), true)) - return true; //Allow running commands in chat channels - MCChatUtils.resetLastMessage(ev.getChannel()); - recevents.add(ev); - if (rectask != null) - return true; - recrun = () -> { //Don't return in a while loop next time - recthread = Thread.currentThread(); - processDiscordToMC(); - if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down - rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing - }; - rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing + if (CommandListener.runCommand(ev.getMessage(), true)) + return true; //Allow running commands in chat channels + MCChatUtils.resetLastMessage(channel); + recevents.add(ev); + if (rectask != null) + return true; + recrun = () -> { //Don't return in a while loop next time + recthread = Thread.currentThread(); + processDiscordToMC(); + if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down + rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing + }; + rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing return true; - } + } - private void processDiscordToMC() { - @val - sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent event; - try { - event = recevents.take(); - } catch (InterruptedException e1) { - rectask.cancel(); - return; - } - val sender = event.getMessage().getAuthor(); - String dmessage = event.getMessage().getContent(); - try { - final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannel(), sender); - val user = dsender.getChromaUser(); + private void processDiscordToMC() { + @val + sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent event; + try { + event = recevents.take(); + } catch (InterruptedException e1) { + rectask.cancel(); + return; + } + val sender = event.getMessage().getAuthor(); + String dmessage = event.getMessage().getContent(); + try { + final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannel(), sender); + val user = dsender.getChromaUser(); - for (IUser u : event.getMessage().getMentions()) { - dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting - final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); - dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); - } + for (User u : event.getMessage().getMentions()) { + dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting + final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); + dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); + } for (MessageChannel ch : event.getMessage().getChannelMentions()) { - dmessage = dmessage.replace(ch.mention(), "#" + ch.getName()); // TODO: IG Formatting - } + dmessage = dmessage.replace(ch.mention(), "#" + ch.getName()); // TODO: IG Formatting + } - dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?) - dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up + dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?) + dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up - Function getChatMessage = msg -> // - msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() - .getAttachments().stream().map(Message.Attachment::getUrl).collect(Collectors.joining("\n")) - : ""); + Function getChatMessage = msg -> // + msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() + .getAttachments().stream().map(Message.Attachment::getUrl).collect(Collectors.joining("\n")) + : ""); - MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel()); + MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel()); - boolean react = false; + boolean react = false; - if (dmessage.startsWith("/")) { // Ingame command - DPUtils.perform(() -> { - if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) - event.getMessage().delete(); - }); - final String cmd = dmessage.substring(1); - final String cmdlowercased = cmd.toLowerCase(); - if (dsender instanceof DiscordSender && module.whitelistedCommands().get().stream() - .noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) { - // Command not whitelisted - dsender.sendMessage("Sorry, you can only access these commands:\n" - + module.whitelistedCommands().get().stream().map(uc -> "/" + uc) - .collect(Collectors.joining(", ")) - + (user.getConnectedID(TBMCPlayer.class) == null - ? "\nTo access your commands, first please connect your accounts, using /connect in " - + DPUtils.botmention() - + "\nThen y" - : "\nY") - + "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"); - return; - } - val ev = new TBMCCommandPreprocessEvent(dsender, dmessage); - Bukkit.getPluginManager().callEvent(ev); - if (ev.isCancelled()) - return; - int spi = cmdlowercased.indexOf(' '); - final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi); - Optional ch = Channel.getChannels() - .filter(c -> c.ID.equalsIgnoreCase(topcmd) - || (c.IDs().get().length > 0 - && Arrays.stream(c.IDs().get()).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny(); - if (!ch.isPresent()) //TODO: What if talking in the public chat while we have it on a different one - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, //Commands need to be run sync - () -> { //TODO: Better handling... - val channel = user.channel(); - val chtmp = channel.get(); - if (clmd != null) { - channel.set(clmd.mcchannel); //Hack to send command in the channel - } //TODO: Permcheck isn't implemented for commands - VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); - Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); - if (clmd != null) - channel.set(chtmp); - }); - else { - Channel chc = ch.get(); - if (!chc.isGlobal() && !event.getMessage().getChannel().isPrivate()) - dsender.sendMessage( - "You can only talk in a public chat here. DM `mcchat` to enable private chat to talk in the other channels."); - else { - if (spi == -1) // Switch channels - { - val channel = dsender.getChromaUser().channel(); - val oldch = channel.get(); - if (oldch instanceof ChatRoom) - ((ChatRoom) oldch).leaveRoom(dsender); - if (!oldch.ID.equals(chc.ID)) { - channel.set(chc); - if (chc instanceof ChatRoom) - ((ChatRoom) chc).joinRoom(dsender); - } else - channel.set(Channel.GlobalChat); - dsender.sendMessage("You're now talking in: " - + DPUtils.sanitizeString(channel.get().DisplayName().get())); - } else { // Send single message - final String msg = cmd.substring(spi + 1); - val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(msg)).fromCommand(true); - if (clmd == null) - TBMCChatAPI.SendChatMessage(cmb.build(), chc); - else - TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), chc); - react = true; - } - } - } - } else {// Not a command - if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 - && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) { - val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp) - : dsender.getChromaUser().channel().get().getRTR(dsender); - TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr, - (dsender instanceof Player ? ((Player) dsender).getDisplayName() - : dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL); - } - else { - val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); - if (clmd != null) - TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel); - else - TBMCChatAPI.SendChatMessage(cmb.build()); - react = true; - } - } - if (react) { - try { - val lmfd = MCChatUtils.lastmsgfromd.get(event.getChannel().getLongID()); - if (lmfd != null) { - DPUtils.perform(() -> lmfd.removeReaction(DiscordPlugin.dc.getOurUser(), - DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time - } - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e); - } - MCChatUtils.lastmsgfromd.put(event.getChannel().getLongID(), event.getMessage()); - DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION)); - } - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while handling message \"" + dmessage + "\"!", e); - } - } + if (dmessage.startsWith("/")) { // Ingame command + DPUtils.perform(() -> { + if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) + event.getMessage().delete(); + }); + final String cmd = dmessage.substring(1); + final String cmdlowercased = cmd.toLowerCase(); + if (dsender instanceof DiscordSender && module.whitelistedCommands().get().stream() + .noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) { + // Command not whitelisted + dsender.sendMessage("Sorry, you can only access these commands:\n" + + module.whitelistedCommands().get().stream().map(uc -> "/" + uc) + .collect(Collectors.joining(", ")) + + (user.getConnectedID(TBMCPlayer.class) == null + ? "\nTo access your commands, first please connect your accounts, using /connect in " + + DPUtils.botmention() + + "\nThen y" + : "\nY") + + "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"); + return; + } + val ev = new TBMCCommandPreprocessEvent(dsender, dmessage); + Bukkit.getPluginManager().callEvent(ev); + if (ev.isCancelled()) + return; + int spi = cmdlowercased.indexOf(' '); + final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi); + Optional ch = Channel.getChannels() + .filter(c -> c.ID.equalsIgnoreCase(topcmd) + || (c.IDs().get().length > 0 + && Arrays.stream(c.IDs().get()).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny(); + if (!ch.isPresent()) //TODO: What if talking in the public chat while we have it on a different one + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, //Commands need to be run sync + () -> { //TODO: Better handling... + val channel = user.channel(); + val chtmp = channel.get(); + if (clmd != null) { + channel.set(clmd.mcchannel); //Hack to send command in the channel + } //TODO: Permcheck isn't implemented for commands + VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); + Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); + if (clmd != null) + channel.set(chtmp); + }); + else { + Channel chc = ch.get(); + if (!chc.isGlobal() && !event.getMessage().getChannel().isPrivate()) + dsender.sendMessage( + "You can only talk in a public chat here. DM `mcchat` to enable private chat to talk in the other channels."); + else { + if (spi == -1) // Switch channels + { + val channel = dsender.getChromaUser().channel(); + val oldch = channel.get(); + if (oldch instanceof ChatRoom) + ((ChatRoom) oldch).leaveRoom(dsender); + if (!oldch.ID.equals(chc.ID)) { + channel.set(chc); + if (chc instanceof ChatRoom) + ((ChatRoom) chc).joinRoom(dsender); + } else + channel.set(Channel.GlobalChat); + dsender.sendMessage("You're now talking in: " + + DPUtils.sanitizeString(channel.get().DisplayName().get())); + } else { // Send single message + final String msg = cmd.substring(spi + 1); + val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(msg)).fromCommand(true); + if (clmd == null) + TBMCChatAPI.SendChatMessage(cmb.build(), chc); + else + TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), chc); + react = true; + } + } + } + } else {// Not a command + if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 + && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) { + val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp) + : dsender.getChromaUser().channel().get().getRTR(dsender); + TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr, + (dsender instanceof Player ? ((Player) dsender).getDisplayName() + : dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL); + } else { + val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); + if (clmd != null) + TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel); + else + TBMCChatAPI.SendChatMessage(cmb.build()); + react = true; + } + } + if (react) { + try { + val lmfd = MCChatUtils.lastmsgfromd.get(event.getChannel().getId().asLong()); + if (lmfd != null) { + DPUtils.perform(() -> lmfd.removeReaction(DiscordPlugin.dc.getSelf(), + DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time + } + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e); + } + MCChatUtils.lastmsgfromd.put(event.getChannel().getId().asLong(), event.getMessage()); + DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION)); + } + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while handling message \"" + dmessage + "\"!", e); + } + } - @FunctionalInterface - private interface InterruptibleConsumer { - void accept(T value) throws TimeoutException, InterruptedException; - } + @FunctionalInterface + private interface InterruptibleConsumer { + void accept(T value) throws TimeoutException, InterruptedException; + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 3a2f2f2..3c6c893 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -10,7 +10,7 @@ import org.bukkit.event.Event; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import sx.blah.discord.handle.obj.IPrivateChannel; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; @@ -22,7 +22,7 @@ public class MCChatPrivate { */ static ArrayList lastmsgPerUser = new ArrayList<>(); - public static boolean privateMCChat(MessageChannel channel, boolean start, IUser user, DiscordPlayer dp) { + public static boolean privateMCChat(MessageChannel channel, boolean start, User user, DiscordPlayer dp) { TBMCPlayer mcp = dp.getAs(TBMCPlayer.class); if (mcp != null) { // If the accounts aren't connected, can't make a connected sender val p = Bukkit.getPlayer(mcp.getUUID()); @@ -39,10 +39,10 @@ public class MCChatPrivate { } } // ---- PermissionsEx warning is normal on logout ---- if (!start) - MCChatUtils.lastmsgfromd.remove(channel.getLongID()); + MCChatUtils.lastmsgfromd.remove(channel.getId().asLong()); return start // ? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs - : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); + : lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()); } public static boolean isMinecraftChatEnabled(DiscordPlayer dp) { @@ -51,7 +51,7 @@ public class MCChatPrivate { public static boolean isMinecraftChatEnabled(String did) { // Don't load the player data just for this return lastmsgPerUser.stream() - .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did)); + .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getId().asString().equals(did)); } public static void logoutAll() { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 6399d90..5651d40 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -81,7 +81,7 @@ public class MCChatUtils { return addSender(senders, user.getId().asLong(), sender); } - public static T addSender(HashMap> senders, + public static T addSender(HashMap> senders, long did, T sender) { var map = senders.get(did); if (map == null) @@ -91,8 +91,8 @@ public class MCChatUtils { return sender; } - public static T getSender(HashMap> senders, - Channel channel, User user) { + public static T getSender(HashMap> senders, + MessageChannel channel, User user) { var map = senders.get(user.getId().asLong()); if (map != null) return map.get(channel); @@ -172,7 +172,7 @@ public class MCChatUtils { } public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { - if (notEnabled()) return + if (notEnabled()) return; if (event.getChannel().isGlobal()) action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) @@ -188,7 +188,7 @@ public class MCChatUtils { /** * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. */ - static DiscordSenderBase getSender(Channel channel, final User author) { + static DiscordSenderBase getSender(MessageChannel channel, final User author) { //noinspection OptionalGetWithoutIsPresent return Stream.>>of( // https://stackoverflow.com/a/28833677/2703239 () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null @@ -206,13 +206,13 @@ public class MCChatUtils { */ public static void resetLastMessage(Channel channel) { if (notEnabled()) return; - if (channel.getLongID() == module.chatChannel().get().getLongID()) { + if (channel.getId().asLong() == module.chatChannel().get().getId().asLong()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null) : lastmsgdata).message = null; return; } // Don't set the whole object to null, the player and channel information should be preserved for (LastMsgData data : channel.isPrivate() ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) { - if (data.channel.getLongID() == channel.getLongID()) { + if (data.channel.getId().asLong() == channel.getId().asLong()) { data.message = null; return; } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 3ed7bcf..3c2cf40 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -24,7 +24,7 @@ import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.IUser; +import sx.blah.discord.handle.obj.User; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.MissingPermissionsException; @@ -115,7 +115,7 @@ class MCListener implements Listener { final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) .getAs(DiscordPlayer.class); if (p == null) return; - final IUser user = DiscordPlugin.dc.getUserByID( + final User user = DiscordPlugin.dc.getUserByID( Long.parseLong(p.getDiscordID())); if (e.getValue()) user.addRole(role); @@ -149,7 +149,7 @@ class MCListener implements Listener { : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO val yeehaw = DiscordPlugin.mainServer.getEmojiByName("YEEHAW"); - MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getStringID() + ">s" : " YEEHAWs"))); + MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getId().asString() + ">s" : " YEEHAWs"))); } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 9e8cfe0..5418086 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -9,6 +9,9 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import com.google.common.collect.Lists; +import discord4j.core.event.domain.message.MessageCreateEvent; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.util.Snowflake; import lombok.Getter; import lombok.val; import org.bukkit.Bukkit; @@ -23,7 +26,8 @@ import java.util.stream.Collectors; * Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM. */ public class MinecraftChatModule extends Component { - private @Getter MCChatListener listener; + private @Getter + MCChatListener listener; /*public MCChatListener getListener() { //It doesn't want to generate return listener; - And now ButtonProcessor didn't look beyond this - return instead of continue... @@ -58,11 +62,20 @@ public class MinecraftChatModule extends Component { return getConfig().getData("excludedPlugins", new String[]{"ProtocolLib", "LibsDisguises", "JourneyMapServer"}); } + /** + * If this setting is on then players logged in through the 'mcchat' command will be able to teleport using plugin commands. + * They can then use commands like /tpahere to teleport others to that place.
+ * If this is off, then teleporting will have no effect. + */ + public ConfigData allowFakePlayerTeleports() { + return getConfig().getData("allowFakePlayerTeleports", false); + } + @Override protected void enable() { if (DPUtils.disableIfConfigError(this, chatChannel())) return; listener = new MCChatListener(this); - DiscordPlugin.dc.getDispatcher().registerListener(listener); + DiscordPlugin.dc.getEventDispatcher().on(MessageCreateEvent.class).subscribe(listener::handleDiscord); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled getPlugin().getManager().registerCommand(new MCChatCommand()); @@ -76,17 +89,17 @@ public class MinecraftChatModule extends Component { for (val chconkey : chconkeys) { val chcon = chcons.getConfigurationSection(chconkey); val mcch = Channel.getChannels().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); - val ch = DiscordPlugin.dc.getChannelByID(chcon.getLong("chid")); + val ch = DiscordPlugin.dc.getChannelById(Snowflake.of(chcon.getLong("chid"))).block(); val did = chcon.getLong("did"); - val user = DiscordPlugin.dc.fetchUser(did); + val user = DiscordPlugin.dc.getUserById(Snowflake.of(did)).block(); val groupid = chcon.getString("groupid"); val toggles = chcon.getInt("toggles"); val brtoggles = chcon.getStringList("brtoggles"); if (!mcch.isPresent() || ch == null || user == null || groupid == null) continue; Bukkit.getScheduler().runTask(getPlugin(), () -> { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase) - val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname")); - MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet())); + val dcp = new DiscordConnectedPlayer(user, (MessageChannel) ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this); + MCChatCustom.addCustomChat((MessageChannel) ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet())); }); } } @@ -97,10 +110,10 @@ public class MinecraftChatModule extends Component { val chcons = MCChatCustom.getCustomChats(); val chconsc = getConfig().getConfig().createSection("chcons"); for (val chcon : chcons) { - val chconc = chconsc.createSection(chcon.channel.getStringID()); + val chconc = chconsc.createSection(chcon.channel.getId().asString()); chconc.set("mcchid", chcon.mcchannel.ID); - chconc.set("chid", chcon.channel.getLongID()); - chconc.set("did", chcon.user.getLongID()); + chconc.set("chid", chcon.channel.getId().asLong()); + chconc.set("did", chcon.user.getId().asLong()); chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); chconc.set("mcname", chcon.dcp.getName()); chconc.set("groupid", chcon.groupID); diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java index 61cfa5e..9a75717 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java @@ -1,6 +1,10 @@ package buttondevteam.discordplugin.playerfaker; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import lombok.Getter; import lombok.Setter; import org.bukkit.*; @@ -11,8 +15,6 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.*; @@ -20,10 +22,11 @@ import java.util.*; @Setter @SuppressWarnings("deprecated") public abstract class DiscordEntity extends DiscordSenderBase implements Entity { - protected DiscordEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { + protected DiscordEntity(User user, MessageChannel channel, int entityId, UUID uuid, MinecraftChatModule module) { super(user, channel); this.entityId = entityId; uniqueId = uuid; + this.module = module; } private HashMap metadata = new HashMap(); @@ -34,6 +37,7 @@ public abstract class DiscordEntity extends DiscordSenderBase implements Entity private EntityDamageEvent lastDamageCause; private final Set scoreboardTags = new HashSet(); private final UUID uniqueId; + private final MinecraftChatModule module; @Override public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { @@ -42,7 +46,7 @@ public abstract class DiscordEntity extends DiscordSenderBase implements Entity @Override public List getMetadata(String metadataKey) { - return Arrays.asList(metadata.get(metadataKey)); // Who needs multiple data anyways + return Collections.singletonList(metadata.get(metadataKey)); // Who needs multiple data anyways } @Override @@ -91,31 +95,35 @@ public abstract class DiscordEntity extends DiscordSenderBase implements Entity @Override public boolean teleport(Location location) { - this.location = location; + if (module.allowFakePlayerTeleports().get()) + this.location = location; return true; } @Override public boolean teleport(Location location, TeleportCause cause) { - this.location = location; + if (module.allowFakePlayerTeleports().get()) + this.location = location; return true; } @Override public boolean teleport(Entity destination) { - this.location = destination.getLocation(); + if (module.allowFakePlayerTeleports().get()) + this.location = destination.getLocation(); return true; } @Override public boolean teleport(Entity destination, TeleportCause cause) { - this.location = destination.getLocation(); + if (module.allowFakePlayerTeleports().get()) + this.location = destination.getLocation(); return true; } @Override public List getNearbyEntities(double x, double y, double z) { - return Arrays.asList(); + return Collections.emptyList(); } @Override @@ -163,7 +171,7 @@ public abstract class DiscordEntity extends DiscordSenderBase implements Entity @Override public List getPassengers() { - return Arrays.asList(); + return Collections.emptyList(); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index e7d1c74..f197c84 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -1,6 +1,9 @@ package buttondevteam.discordplugin.playerfaker; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import lombok.Getter; import lombok.experimental.Delegate; import org.bukkit.*; @@ -16,16 +19,14 @@ import org.bukkit.map.MapView; import org.bukkit.permissions.PermissibleBase; import org.bukkit.plugin.Plugin; import org.bukkit.scoreboard.Scoreboard; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.net.InetSocketAddress; import java.util.*; @SuppressWarnings("deprecation") public class DiscordFakePlayer extends DiscordHumanEntity implements Player { - protected DiscordFakePlayer(IUser user, MessageChannel channel, int entityId, UUID uuid, String mcname) { - super(user, channel, entityId, uuid); + protected DiscordFakePlayer(User user, MessageChannel channel, int entityId, UUID uuid, String mcname, MinecraftChatModule module) { + super(user, channel, entityId, uuid, module); perm = new PermissibleBase(Bukkit.getOfflinePlayer(uuid)); name = mcname; } @@ -42,7 +43,7 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player { @Override public String getCustomName() { - return user.getName(); + return user.getUsername(); } @Override @@ -127,7 +128,7 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player { @Override public String getDisplayName() { - return user.getDisplayName(DiscordPlugin.mainServer); + return Objects.requireNonNull(user.asMember(DiscordPlugin.mainServer.getId()).block()).getDisplayName(); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java index f984b6c..4b8b32d 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java @@ -1,5 +1,8 @@ package buttondevteam.discordplugin.playerfaker; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; @@ -8,14 +11,12 @@ import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Villager; import org.bukkit.inventory.*; import org.bukkit.inventory.InventoryView.Property; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.UUID; public abstract class DiscordHumanEntity extends DiscordLivingEntity implements HumanEntity { - protected DiscordHumanEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { - super(user, channel, entityId, uuid); + protected DiscordHumanEntity(User user, MessageChannel channel, int entityId, UUID uuid, MinecraftChatModule module) { + super(user, channel, entityId, uuid, module); } private PlayerInventory inv = new DiscordPlayerInventory(this); diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java index 876d17e..c561fbf 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java @@ -1,5 +1,8 @@ package buttondevteam.discordplugin.playerfaker; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import lombok.Getter; import lombok.Setter; import org.bukkit.Location; @@ -16,15 +19,13 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; -import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.*; public abstract class DiscordLivingEntity extends DiscordEntity implements LivingEntity { - protected DiscordLivingEntity(IUser user, MessageChannel channel, int entityId, UUID uuid) { - super(user, channel, entityId, uuid); + protected DiscordLivingEntity(User user, MessageChannel channel, int entityId, UUID uuid, MinecraftChatModule module) { + super(user, channel, entityId, uuid, module); } private @Getter EntityEquipment equipment = new DiscordEntityEquipment(this); From 59066ce09a1380c654f3848163d6d163c39618fd Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 16:50:00 +0200 Subject: [PATCH 07/24] Refactoring... --- .../buttondevteam/discordplugin/DPUtils.java | 11 ++++ .../discordplugin/DiscordSender.java | 9 ++- .../discordplugin/DiscordSupplier.java | 11 ---- .../commands/Command2DCSender.java | 5 +- .../exceptions/ExceptionListenerModule.java | 19 +++--- .../discordplugin/fun/FunModule.java | 66 +++++++++---------- .../listeners/CommandListener.java | 19 +++--- .../listeners/CommonListeners.java | 9 +-- .../discordplugin/listeners/MCListener.java | 51 ++++++++------ .../mcchat/ChannelconCommand.java | 55 +++++++++------- .../discordplugin/mcchat/MCChatCommand.java | 4 +- .../discordplugin/mcchat/MCChatCustom.java | 10 +-- .../discordplugin/mcchat/MCChatUtils.java | 16 ++--- .../mcchat/MinecraftChatModule.java | 1 - .../discordplugin/role/GameRoleModule.java | 6 +- .../discordplugin/role/RoleCommand.java | 50 +++++++------- 16 files changed, 181 insertions(+), 161 deletions(-) delete mode 100755 src/main/java/buttondevteam/discordplugin/DiscordSupplier.java diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 9130495..f4a1ce0 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -8,6 +8,7 @@ import discord4j.core.object.entity.*; import discord4j.core.object.util.Snowflake; import discord4j.core.spec.EmbedCreateSpec; import lombok.val; +import reactor.core.publisher.Mono; import javax.annotation.Nullable; import java.util.logging.Logger; @@ -116,4 +117,14 @@ public final class DPUtils { return false; } + public static Mono reply(Message original, @Nullable MessageChannel channel, String message) { + Mono ch; + if (channel == null) + ch = original.getChannel(); + else + ch = Mono.just(channel); + return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent() + ? original.getAuthor().get().getMention() + ", " : "") + message)); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index 7b87b5d..9eda278 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -1,5 +1,9 @@ package buttondevteam.discordplugin; +import discord4j.core.object.entity.Member; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; +import lombok.val; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.command.CommandSender; @@ -8,8 +12,6 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; -import sx.blah.discord.handle.obj.User; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.Set; @@ -20,7 +22,8 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { public DiscordSender(User user, MessageChannel channel) { super(user, channel); - name = user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer); + val def = "Discord user"; + name = user == null ? def : user.asMember(DiscordPlugin.mainServer.getId()).blockOptional().map(Member::getDisplayName).orElse(def); } public DiscordSender(User user, MessageChannel channel, String name) { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java b/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java deleted file mode 100755 index 09b730a..0000000 --- a/src/main/java/buttondevteam/discordplugin/DiscordSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package buttondevteam.discordplugin; - -import sx.blah.discord.handle.obj.IDiscordObject; -import sx.blah.discord.util.DiscordException; -import sx.blah.discord.util.MissingPermissionsException; -import sx.blah.discord.util.RateLimitException; - -@FunctionalInterface -public interface DiscordSupplier> { - T get() throws DiscordException, RateLimitException, MissingPermissionsException; -} diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index 831cf6c..1165612 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -18,8 +18,9 @@ public class Command2DCSender implements Command2Sender { message = DPUtils.sanitizeString(message); message = Character.toLowerCase(message.charAt(0)) + message.substring(1); val msg = message; - this.message.getChannel().flatMap(ch -> ch.createMessage(this.message.getAuthorAsMember().a-> - a.getNicknameMention() + ", " + msg))) + val author = this.message.getAuthorAsMember().block(); + if (author == null) return; + this.message.getChannel().subscribe(ch -> ch.createMessage(author.getNicknameMention() + ", " + msg)); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index f03b67a..098ade3 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -7,13 +7,14 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCExceptionEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import discord4j.core.object.entity.Guild; +import discord4j.core.object.entity.GuildChannel; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.Role; import org.apache.commons.lang.exception.ExceptionUtils; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import sx.blah.discord.handle.obj.IGuild; -import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; import java.util.Arrays; @@ -49,19 +50,19 @@ public class ExceptionListenerModule extends Component implements try { MessageChannel channel = getChannel(); assert channel != null; - IRole coderRole = instance.pingRole(channel.getGuild()).get(); + Role coderRole = instance.pingRole(((GuildChannel) channel).getGuild().block()).get(); StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() - : new StringBuilder(coderRole == null ? "" : coderRole.mention()).append("\n"); + : new StringBuilder(coderRole == null ? "" : coderRole.getMention()).append("\n"); sb.append(sourcemessage).append("\n"); sb.append("```").append("\n"); String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) .filter(s -> !s.contains("\tat ") || s.contains("\tat buttondevteam.")) .collect(Collectors.joining("\n")); - if (stackTrace.length() > 1800) - stackTrace = stackTrace.substring(0, 1800); + if (sb.length() + stackTrace.length() >= 2000) + stackTrace = stackTrace.substring(0, 1999 - sb.length()); sb.append(stackTrace).append("\n"); sb.append("```"); - DiscordPlugin.sendMessageToChannel(channel, sb.toString()); //Instance isn't null here + channel.createMessage(sb.toString()).subscribe(); } catch (Exception ex) { ex.printStackTrace(); } @@ -78,7 +79,7 @@ public class ExceptionListenerModule extends Component implements return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } - private ConfigData pingRole(IGuild guild) { + private ConfigData pingRole(Guild guild) { return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild); } diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index ee72a6a..0ccc4b9 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -7,14 +7,14 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import com.google.common.collect.Lists; +import discord4j.core.event.domain.PresenceUpdateEvent; +import discord4j.core.object.entity.*; +import discord4j.core.object.presence.Status; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent; -import sx.blah.discord.handle.obj.*; -import sx.blah.discord.util.EmbedBuilder; import java.util.ArrayList; import java.util.Arrays; @@ -25,26 +25,26 @@ import java.util.stream.IntStream; public class FunModule extends Component implements Listener { private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali - "Between now and the heat-death of the universe.", // Ghostise - "Soon™", "Ask again this time next month", // Ghostise - "In about 3 seconds", // Nicolai - "After we finish 8 plugins", // Ali - "Tomorrow.", // Ali - "After one tiiiny feature", // Ali - "Next commit", // Ali - "After we finish strangling Towny", // Ali - "When we kill every *fucking* bug", // Ali - "Once the server stops screaming.", // Ali - "After HL3 comes out", // Ali - "Next time you ask", // Ali - "When will *you* be open?" // Ali + "Between now and the heat-death of the universe.", // Ghostise + "Soon™", "Ask again this time next month", // Ghostise + "In about 3 seconds", // Nicolai + "After we finish 8 plugins", // Ali + "Tomorrow.", // Ali + "After one tiiiny feature", // Ali + "Next commit", // Ali + "After we finish strangling Towny", // Ali + "When we kill every *fucking* bug", // Ali + "Once the server stops screaming.", // Ali + "After HL3 comes out", // Ali + "Next time you ask", // Ali + "When will *you* be open?" // Ali }; /** * Questions that the bot will choose a random answer to give to. */ private ConfigData serverReadyQuestions() { - return getConfig().getData("serverReady", ()->new String[]{"when will the server be open", + return getConfig().getData("serverReady", () -> new String[]{"when will the server be open", "when will the server be ready", "when will the server be done", "when will the server be complete", "when will the server be finished", "when's the server ready", "when's the server open", "Vhen vill ze server be open?"}); @@ -83,7 +83,7 @@ public class FunModule extends Component implements Listener { public static boolean executeMemes(Message message) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return false; - String msglowercased = message.getContent().toLowerCase(); + String msglowercased = message.getContent().orElse("").toLowerCase(); lastlist++; if (lastlist > 5) { ListC = 0; @@ -91,7 +91,7 @@ public class FunModule extends Component implements Listener { } if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already { - message.reply("Stop it. You know the answer."); + DPUtils.reply(message, null, "Stop it. You know the answer.").subscribe(); lastlist = 0; lastlistp = (short) Bukkit.getOnlinePlayers().size(); return true; //Handled @@ -103,7 +103,7 @@ public class FunModule extends Component implements Listener { if (usableServerReadyStrings.size() == 0) fm.createUsableServerReadyStrings(); next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); - DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]); + DPUtils.reply(message, null, serverReadyStrings[next]).subscribe(); return false; //Still process it as a command/mcchat if needed } return false; @@ -114,7 +114,7 @@ public class FunModule extends Component implements Listener { ListC = 0; } - private ConfigData fullHouseDevRole(IGuild guild) { + private ConfigData fullHouseDevRole(Guild guild) { return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); } @@ -125,26 +125,26 @@ public class FunModule extends Component implements Listener { private static long lasttime = 0; + @SuppressWarnings("ConstantConditions") public static void handleFullHouse(PresenceUpdateEvent event) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return; val channel = fm.fullHouseChannel().get(); if (channel == null) return; - val devrole = fm.fullHouseDevRole(channel.getGuild()).get(); + val devrole = fm.fullHouseDevRole(((GuildChannel) channel).getGuild().block()).get(); if (devrole == null) return; - if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) - && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(channel.getGuild()).stream() - .anyMatch(r -> r.getId().asLong() == devrole.getId().asLong()) - && channel.getGuild().getUsersByRole(devrole).stream() - .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) + if (event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false) + && !event.getCurrent().getStatus().equals(Status.OFFLINE) + && event.getMember().flatMap(m -> m.getRoles() + .any(r -> r.getId().asLong() == devrole.getId().asLong())).block() + && event.getGuild().flatMap(g -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(devrole.getId()))) + .flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE))).block() && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(channel, "Full house!", - new EmbedBuilder() - .withImage( - "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - .build()); + channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs -> + ecs.setImage( + "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") + )); lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index a12a665..2bb9399 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -1,15 +1,14 @@ package buttondevteam.discordplugin.listeners; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; import buttondevteam.lib.TBMCCoreAPI; import discord4j.core.object.entity.Message; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.PrivateChannel; +import discord4j.core.object.entity.Role; import lombok.val; -import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.Message; -import sx.blah.discord.handle.obj.MessageChannel; public class CommandListener { /** @@ -41,26 +40,24 @@ public class CommandListener { final String mentionNick = member.getNicknameMention(); boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention; - for (String mentionRole : (Iterable) message.getRoleMentions().filter(r -> member.getRoles().filter(r)).map(IRole::mention)::iterator) //TODO: Remove all that matches + val mentions = message.getRoleMentions(); + for (String mentionRole : member.getRoles().filter(r -> mentions.any(rr -> rr.getName().equals(r.getName())).blockOptional().orElse(false)).map(Role::getMention).toIterable()) gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions - if (mentionedonly && !gotmention) { - message.getChannel().setTypingStatus(false); + if (mentionedonly && !gotmention) return false; - } - message.getChannel().setTypingStatus(true); + channel.type().subscribe(); String cmdwithargsString = cmdwithargs.toString(); try { if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) - message.reply("Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); + DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString).subscribe(); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); } - message.getChannel().setTypingStatus(false); return true; } private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, Message message) { - if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text + if (message.getContent().orElse("").startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text if (cmdwithargs.length() > mention.length() + 1) { int i = cmdwithargs.indexOf(" ", mention.length()); if (i == -1) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 44e0118..48376b8 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -14,12 +14,6 @@ import discord4j.core.event.domain.role.RoleCreateEvent; import discord4j.core.event.domain.role.RoleDeleteEvent; import discord4j.core.event.domain.role.RoleUpdateEvent; import lombok.val; -import sx.blah.discord.api.events.IListener; -import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleCreateEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleDeleteEvent; -import sx.blah.discord.handle.impl.events.guild.role.RoleUpdateEvent; -import sx.blah.discord.handle.impl.events.user.PresenceUpdateEvent; public class CommonListeners { @@ -36,7 +30,8 @@ public class CommonListeners { dispatcher.on(MessageCreateEvent.class).subscribe(event->{ if (DiscordPlugin.SafeMode) return; - if (event.getMessage().getAuthor().isBot()) + val author = event.getMessage().getAuthor(); + if (!author.isPresent() || author.get().isBot()) return; if (FunModule.executeMemes(event.getMessage())) return; diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index e41713c..6062711 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -5,39 +5,50 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; import buttondevteam.lib.player.TBMCPlayerJoinEvent; +import discord4j.core.object.entity.Member; +import discord4j.core.object.entity.User; +import discord4j.core.object.util.Snowflake; +import lombok.val; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.server.ServerCommandEvent; -import sx.blah.discord.handle.obj.User; public class MCListener implements Listener { @EventHandler public void onPlayerJoin(TBMCPlayerJoinEvent e) { if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { @SuppressWarnings("ConstantConditions") User user = DiscordPlugin.dc - .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); - e.getPlayer().sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() + .getUserById(Snowflake.of(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))).block(); + if (user == null) return; + e.getPlayer().sendMessage("§bTo connect with the Discord account @" + user.getUsername() + "#" + user.getDiscriminator() + " do /discord accept"); e.getPlayer().sendMessage("§bIf it wasn't you, do /discord decline"); } } - @EventHandler - public void onGetInfo(TBMCPlayerGetInfoEvent e) { - if (DiscordPlugin.SafeMode) - return; - DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class); - if (dp == null || dp.getDiscordID() == null || dp.getDiscordID().equals("")) - return; - User user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); - e.addInfo("Discord tag: " + user.getName() + "#" + user.getDiscriminator()); - e.addInfo(user.getPresence().getStatus().toString()); - if (user.getPresence().getActivity().isPresent() && user.getPresence().getText().isPresent()) - e.addInfo(user.getPresence().getActivity().get() + ": " + user.getPresence().getText().get()); - } + @EventHandler + public void onGetInfo(TBMCPlayerGetInfoEvent e) { + if (DiscordPlugin.SafeMode) + return; + DiscordPlayer dp = e.getPlayer().getAs(DiscordPlayer.class); + if (dp == null || dp.getDiscordID() == null || dp.getDiscordID().equals("")) + return; + User user = DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).block(); + if (user == null) return; + e.addInfo("Discord tag: " + user.getUsername() + "#" + user.getDiscriminator()); + Member member = user.asMember(DiscordPlugin.mainServer.getId()).block(); + if (member == null) return; + val pr = member.getPresence().block(); + if (pr == null) return; + e.addInfo(pr.getStatus().toString()); + if (pr.getActivity().isPresent()) { + val activity = pr.getActivity().get(); + e.addInfo(activity.getType() + ": " + activity.getName()); + } + } - @EventHandler - public void onServerCommand(ServerCommandEvent e) { - DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped - } + @EventHandler + public void onServerCommand(ServerCommandEvent e) { + DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index fad76fc..41599b7 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -9,15 +9,16 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.TBMCPlayer; +import discord4j.core.object.entity.Message; +import discord4j.core.object.util.Permission; +import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.handle.obj.Message; -import sx.blah.discord.handle.obj.Permissions; -import sx.blah.discord.util.PermissionUtils; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; +import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -32,15 +33,17 @@ import java.util.stream.Collectors; "Mentioning the bot is needed in this case because the / prefix only works in #bot.", // "Invite link: " // }) +@RequiredArgsConstructor public class ChannelconCommand extends ICommand2DC { + private final MinecraftChatModule module; @Command2.Subcommand public boolean remove(Command2DCSender sender) { val message = sender.getMessage(); if (checkPerms(message)) return true; - if (MCChatCustom.removeCustomChat(message.getChannel())) - message.reply("channel connection removed."); + if (MCChatCustom.removeCustomChat(message.getChannelId())) + DPUtils.reply(message, null, "channel connection removed.").subscribe(); else - message.reply("this channel isn't connected."); + DPUtils.reply(message, null, "this channel isn't connected.").subscribe(); return true; } @@ -48,13 +51,13 @@ public class ChannelconCommand extends ICommand2DC { public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) { val message = sender.getMessage(); if (checkPerms(message)) return true; - val cc = MCChatCustom.getCustomChat(message.getChannel()); + val cc = MCChatCustom.getCustomChat(message.getChannelId()); if (cc == null) return respond(sender, "this channel isn't connected."); Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")) + "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n")); if (toggle == null) { - message.reply("toggles:\n" + togglesString.get()); + DPUtils.reply(message, null, "toggles:\n" + togglesString.get()).subscribe(); return true; } String arg = toggle.toUpperCase(); @@ -62,7 +65,7 @@ public class ChannelconCommand extends ICommand2DC { if (!b.isPresent()) { val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg); if (bt == null) { - message.reply("cannot find toggle. Toggles:\n" + togglesString.get()); + DPUtils.reply(message, null, "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe(); return true; } final boolean add; @@ -80,7 +83,7 @@ public class ChannelconCommand extends ICommand2DC { //1 1 | 0 // XOR cc.toggles ^= b.get().flag; - message.reply("'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")); + DPUtils.reply(message, null, "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe(); return true; } @@ -88,45 +91,49 @@ public class ChannelconCommand extends ICommand2DC { public boolean def(Command2DCSender sender, String channelID) { val message = sender.getMessage(); if (checkPerms(message)) return true; - if (MCChatCustom.hasCustomChat(message.getChannel())) + if (MCChatCustom.hasCustomChat(message.getChannelId())) return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny(); if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) - message.reply("MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /."); + DPUtils.reply(message, null, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe(); return true; } - val dp = DiscordPlayer.getUser(message.getAuthor().getId().asString(), DiscordPlayer.class); + if (!message.getAuthor().isPresent()) return true; + val author = message.getAuthor().get(); + val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class); val chp = dp.getAs(TBMCPlayer.class); if (chp == null) { - message.reply("you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect "); + DPUtils.reply(message, null, "you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect ").subscribe(); return true; } - DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()); + val channel = message.getChannel().block(); + DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module); //Using a fake player with no login/logout, should be fine for this event String groupid = chan.get().getGroupID(dcp); if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later - message.reply("sorry, you cannot use that Minecraft channel."); + DPUtils.reply(message, null, "sorry, you cannot use that Minecraft channel.").subscribe(); return true; } if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well - message.reply("chat rooms are not supported yet."); + DPUtils.reply(message, null, "chat rooms are not supported yet.").subscribe(); return true; } /*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) { - message.reply("sorry, this MC chat is already connected to a different channel, multiple channels are not supported atm."); + DPUtils.reply(message, null, "sorry, this MC chat is already connected to a different channel, multiple channels are not supported atm."); return true; }*/ //TODO: "Channel admins" that can connect channels? - MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0, new HashSet<>()); + MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>()); if (chan.get() instanceof ChatRoom) - message.reply("alright, connection made to the room!"); + DPUtils.reply(message, null, "alright, connection made to the room!").subscribe(); else - message.reply("alright, connection made to group `" + groupid + "`!"); + DPUtils.reply(message, null, "alright, connection made to group `" + groupid + "`!").subscribe(); return true; } + @SuppressWarnings("ConstantConditions") private boolean checkPerms(Message message) { - if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { - message.reply("you need to have manage permissions for this channel!"); + if (!message.getAuthorAsMember().block().getBasePermissions().block().contains(Permission.MANAGE_CHANNELS)) { + DPUtils.reply(message, null, "you need to have manage permissions for this channel!").subscribe(); return true; } return false; @@ -140,7 +147,7 @@ public class ChannelconCommand extends ICommand2DC { "You need to have access to the MC channel and have manage permissions on the Discord channel.", // "You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect .", // "Call this command from the channel you want to use.", // - "Usage: @" + DiscordPlugin.dc.getSelf().getName() + " channelcon ", // + "Usage: " + Objects.requireNonNull(DiscordPlugin.dc.getSelf().block()).getMention() + " channelcon ", // "Use the ID (command) of the channel, for example `g` for the global chat.", // "To remove a connection use @ChromaBot channelcon remove in the channel.", // "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", // diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index c579818..df2bff0 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -21,13 +21,13 @@ public class MCChatCommand extends ICommand2DC { public boolean def(Command2DCSender sender) { val message = sender.getMessage(); if (!message.getChannel().isPrivate()) { - message.reply("this command can only be issued in a direct message with the bot."); + DPUtils.reply(message, null, "this command can only be issued in a direct message with the bot."); return true; } try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getId().asString(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); - message.reply("Minecraft chat " + (mcchat // + DPUtils.reply(message, null, "Minecraft chat " + (mcchat // ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // : "disabled.")); } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 7302ad6..c83232b 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -37,14 +37,14 @@ public class MCChatCustom { } @Nullable - public static CustomLMD getCustomChat(MessageChannel channel) { - return lastmsgCustom.stream().filter(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()).findAny().orElse(null); + public static CustomLMD getCustomChat(Snowflake channel) { + return lastmsgCustom.stream().filter(lmd -> lmd.channel.getId().asLong() == channel.asLong()).findAny().orElse(null); } - public static boolean removeCustomChat(MessageChannel channel) { - MCChatUtils.lastmsgfromd.remove(channel.getId().asLong()); + public static boolean removeCustomChat(Snowflake channel) { + MCChatUtils.lastmsgfromd.remove(channel.asLong()); return lastmsgCustom.removeIf(lmd -> { - if (lmd.channel.getId().asLong() != channel.getId().asLong()) + if (lmd.channel.getId().asLong() != channel.asLong()) return false; if (lmd.mcchannel instanceof ChatRoom) ((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 5651d40..2b08093 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -76,13 +76,13 @@ public class MCChatUtils { lmd.channel.edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } - public static T addSender(HashMap> senders, + public static T addSender(HashMap> senders, User user, T sender) { - return addSender(senders, user.getId().asLong(), sender); + return addSender(senders, user.getId().asString(), sender); } - public static T addSender(HashMap> senders, - long did, T sender) { + public static T addSender(HashMap> senders, + String did, T sender) { var map = senders.get(did); if (map == null) map = new HashMap<>(); @@ -91,17 +91,17 @@ public class MCChatUtils { return sender; } - public static T getSender(HashMap> senders, + public static T getSender(HashMap> senders, MessageChannel channel, User user) { - var map = senders.get(user.getId().asLong()); + var map = senders.get(user.getId().asString()); if (map != null) return map.get(channel); return null; } - public static T removeSender(HashMap> senders, + public static T removeSender(HashMap> senders, Channel channel, User user) { - var map = senders.get(user.getId().asLong()); + var map = senders.get(user.getId().asString()); if (map != null) return map.remove(channel); return null; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 5418086..76383b7 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -15,7 +15,6 @@ import discord4j.core.object.util.Snowflake; import lombok.Getter; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; import java.util.Objects; diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 916f116..59496aa 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -15,6 +15,7 @@ import lombok.val; import org.bukkit.Bukkit; import java.awt.*; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -54,7 +55,7 @@ public class GameRoleModule extends Component { Role role=((RoleDeleteEvent) roleEvent).getRole().orElse(null); if(role==null) return; if (GameRoles.remove(role.getName()) && logChannel != null) - logChannel, "Removed " + role.getName() + " as a game role.") + logChannel.createMessage("Removed " + role.getName() + " as a game role.").subscribe(); } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; if(!event.getOld().isPresent()) { @@ -80,11 +81,12 @@ public class GameRoleModule extends Component { } } + @SuppressWarnings("ConstantConditions") private boolean isGameRole(Role r) { if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) return false; //Only allow on the main server val rc = new Color(149, 165, 166, 0); return r.getColor().equals(rc) - && DiscordPlugin.dc.getSelf().block().asMember(DiscordPlugin.mainServer.getId()).block().hasHigherRoles(r); //Below one of our roles + && DiscordPlugin.dc.getSelf().block().asMember(DiscordPlugin.mainServer.getId()).block().hasHigherRoles(Collections.singleton(r)).block(); //Below one of our roles } } diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 3381ae4..eb93eb6 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -1,14 +1,13 @@ package buttondevteam.discordplugin.role; -import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; +import discord4j.core.object.entity.Role; import lombok.val; -import sx.blah.discord.handle.obj.IRole; import java.util.List; import java.util.stream.Collectors; @@ -27,12 +26,12 @@ public class RoleCommand extends ICommand2DC { "This command adds a role to your account." }) public boolean add(Command2DCSender sender, @Command2.TextArg String rolename) { - final IRole role = checkAndGetRole(sender, rolename); + final Role role = checkAndGetRole(sender, rolename); if (role == null) return true; try { - DPUtils.perform(() -> sender.getMessage().getAuthor().addRole(role)); - sender.sendMessage("added role."); + sender.getMessage().getAuthorAsMember() + .subscribe(m -> m.addRole(role.getId()).subscribe(r -> sender.sendMessage("added role."))); } catch (Exception e) { TBMCCoreAPI.SendException("Error while adding role!", e); sender.sendMessage("an error occured while adding the role."); @@ -45,12 +44,12 @@ public class RoleCommand extends ICommand2DC { "This command removes a role from your account." }) public boolean remove(Command2DCSender sender, @Command2.TextArg String rolename) { - final IRole role = checkAndGetRole(sender, rolename); + final Role role = checkAndGetRole(sender, rolename); if (role == null) return true; try { - DPUtils.perform(() -> sender.getMessage().getAuthor().removeRole(role)); - sender.sendMessage("removed role."); + sender.getMessage().getAuthorAsMember() + .subscribe(m -> m.removeRole(role.getId()).subscribe(r -> sender.sendMessage("removed role."))); } catch (Exception e) { TBMCCoreAPI.SendException("Error while removing role!", e); sender.sendMessage("an error occured while removing the role."); @@ -61,9 +60,9 @@ public class RoleCommand extends ICommand2DC { @Command2.Subcommand public void list(Command2DCSender sender) { sender.sendMessage("list of roles:\n" + grm.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); - } + } - private IRole checkAndGetRole(Command2DCSender sender, String rolename) { + private Role checkAndGetRole(Command2DCSender sender, String rolename) { String rname = rolename; if (!grm.GameRoles.contains(rolename)) { //If not found as-is, correct case val orn = grm.GameRoles.stream().filter(r -> r.equalsIgnoreCase(rolename)).findAny(); @@ -73,18 +72,23 @@ public class RoleCommand extends ICommand2DC { return null; } rname = orn.get(); - } - final List roles = DiscordPlugin.mainServer.getRolesByName(rname); - if (roles.size() == 0) { - sender.sendMessage("the specified role cannot be found on Discord! Removing from the list."); - grm.GameRoles.remove(rolename); - return null; - } - if (roles.size() > 1) { - sender.sendMessage("there are multiple roles with this name. Why are there multiple roles with this name?"); - return null; - } - return roles.get(0); - } + } + val frname = rname; + final List roles = DiscordPlugin.mainServer.getRoles().filter(r -> r.getName().equals(frname)).collectList().block(); + if (roles == null) { + sender.sendMessage("an error occured."); + return null; + } + if (roles.size() == 0) { + sender.sendMessage("the specified role cannot be found on Discord! Removing from the list."); + grm.GameRoles.remove(rolename); + return null; + } + if (roles.size() > 1) { + sender.sendMessage("there are multiple roles with this name. Why are there multiple roles with this name?"); + return null; + } + return roles.get(0); + } } From 2500572e0d688bab4aee8091b199d366ca623ad7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 17:50:13 +0200 Subject: [PATCH 08/24] Even more refactoring --- .../discordplugin/mcchat/MCChatListener.java | 22 +++---- .../discordplugin/mcchat/MCChatPrivate.java | 1 + .../discordplugin/mcchat/MCChatUtils.java | 37 ++++++------ .../discordplugin/mcchat/MCListener.java | 60 +++++++++---------- 4 files changed, 54 insertions(+), 66 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index ee2a6fb..550e9df 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -18,6 +18,7 @@ import discord4j.core.event.domain.message.MessageCreateEvent; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.PrivateChannel; import discord4j.core.object.entity.TextChannel; +import discord4j.core.object.entity.User; import discord4j.core.spec.EmbedCreateSpec; import lombok.val; import org.bukkit.Bukkit; @@ -25,14 +26,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitTask; -import sx.blah.discord.api.internal.json.objects.EmbedObject; -import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; -import sx.blah.discord.handle.obj.User; -import sx.blah.discord.handle.obj.Message; -import sx.blah.discord.handle.obj.MessageChannel; -import sx.blah.discord.util.DiscordException; -import sx.blah.discord.util.EmbedBuilder; -import sx.blah.discord.util.MissingPermissionsException; import java.awt.*; import java.time.Instant; @@ -265,22 +258,21 @@ public class MCChatListener implements Listener { } private void processDiscordToMC() { - @val - sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent event; + MessageCreateEvent event; try { event = recevents.take(); } catch (InterruptedException e1) { rectask.cancel(); return; } - val sender = event.getMessage().getAuthor(); - String dmessage = event.getMessage().getContent(); + val sender = event.getMessage().getAuthor().orElse(null); + String dmessage = event.getMessage().getContent().orElse(""); try { - final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannel(), sender); + final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannelId(), sender); val user = dsender.getChromaUser(); - for (User u : event.getMessage().getMentions()) { - dmessage = dmessage.replace(u.mention(false), "@" + u.getName()); // TODO: IG Formatting + for (User u : event.getMessage().getUserMentions()) { //TODO: Role mentions + dmessage = dmessage.replace(u.me(false), "@" + u.getName()); // TODO: IG Formatting final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 3c6c893..e706a68 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -4,6 +4,7 @@ import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.player.TBMCPlayer; +import discord4j.core.object.entity.MessageChannel; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.event.Event; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 2b08093..6ee9292 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -1,14 +1,11 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; -import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCSystemChatEvent; -import discord4j.core.object.entity.Message; -import discord4j.core.object.entity.MessageChannel; -import discord4j.core.object.entity.TextChannel; -import discord4j.core.object.entity.User; +import discord4j.core.object.entity.*; +import discord4j.core.object.util.Snowflake; import io.netty.util.collection.LongObjectHashMap; import lombok.RequiredArgsConstructor; import lombok.experimental.var; @@ -35,12 +32,12 @@ public class MCChatUtils { /** * May contain P<DiscordID> as key for public chat */ - public static final HashMap> UnconnectedSenders = new HashMap<>(); - public static final HashMap> ConnectedSenders = new HashMap<>(); + public static final HashMap> UnconnectedSenders = new HashMap<>(); + public static final HashMap> ConnectedSenders = new HashMap<>(); /** * May contain P<DiscordID> as key for public chat */ - public static final HashMap> OnlineSenders = new HashMap<>(); + public static final HashMap> OnlineSenders = new HashMap<>(); static @Nullable LastMsgData lastmsgdata; static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks private static MinecraftChatModule module; @@ -76,31 +73,31 @@ public class MCChatUtils { lmd.channel.edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } - public static T addSender(HashMap> senders, + public static T addSender(HashMap> senders, User user, T sender) { return addSender(senders, user.getId().asString(), sender); } - public static T addSender(HashMap> senders, + public static T addSender(HashMap> senders, String did, T sender) { var map = senders.get(did); if (map == null) map = new HashMap<>(); - map.put(sender.getChannel(), sender); + map.put(sender.getChannel().getId(), sender); senders.put(did, map); return sender; } - public static T getSender(HashMap> senders, - MessageChannel channel, User user) { + public static T getSender(HashMap> senders, + Snowflake channel, User user) { var map = senders.get(user.getId().asString()); if (map != null) return map.get(channel); return null; } - public static T removeSender(HashMap> senders, - Channel channel, User user) { + public static T removeSender(HashMap> senders, + Snowflake channel, User user) { var map = senders.get(user.getId().asString()); if (map != null) return map.remove(channel); @@ -176,7 +173,7 @@ public class MCChatUtils { if (event.getChannel().isGlobal()) action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) - if (event.shouldSendTo(getSender(data.channel, data.user))) + if (event.shouldSendTo(getSender(data.channel.getId(), data.user))) action.accept(data.channel); MCChatCustom.lastmsgCustom.stream().filter(clmd -> { if (!clmd.brtoggles.contains(event.getTarget())) @@ -188,14 +185,14 @@ public class MCChatUtils { /** * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. */ - static DiscordSenderBase getSender(MessageChannel channel, final User author) { + static DiscordSenderBase getSender(Snowflake channel, final User author) { //noinspection OptionalGetWithoutIsPresent return Stream.>>of( // https://stackoverflow.com/a/28833677/2703239 () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null () -> Optional.ofNullable(getSender(ConnectedSenders, channel, author)), // This doesn't support the public chat, but it'll always return null for it () -> Optional.ofNullable(getSender(UnconnectedSenders, channel, author)), // () -> Optional.of(addSender(UnconnectedSenders, author, - new DiscordSender(author, channel)))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); + new DiscordSender(author, (MessageChannel) DiscordPlugin.dc.getChannelById(channel).block())))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); } /** @@ -207,11 +204,11 @@ public class MCChatUtils { public static void resetLastMessage(Channel channel) { if (notEnabled()) return; if (channel.getId().asLong() == module.chatChannel().get().getId().asLong()) { - (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null) + (lastmsgdata == null ? lastmsgdata = new LastMsgData((TextChannel) module.chatChannel().get(), null) : lastmsgdata).message = null; return; } // Don't set the whole object to null, the player and channel information should be preserved - for (LastMsgData data : channel.isPrivate() ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) { + for (LastMsgData data : channel instanceof PrivateChannel ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) { if (data.channel.getId().asLong() == channel.getId().asLong()) { data.message = null; return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 3c2cf40..d4b6891 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -6,6 +6,9 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.player.*; import com.earth2me.essentials.CommandSource; +import discord4j.core.object.entity.Role; +import discord4j.core.object.entity.User; +import discord4j.core.object.util.Snowflake; import lombok.RequiredArgsConstructor; import lombok.val; import net.ess3.api.events.AfkStatusChangeEvent; @@ -23,10 +26,9 @@ import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; -import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.User; -import sx.blah.discord.util.DiscordException; -import sx.blah.discord.util.MissingPermissionsException; +import reactor.core.publisher.Mono; + +import java.util.Objects; @RequiredArgsConstructor class MCListener implements Listener { @@ -49,9 +51,9 @@ class MCListener implements Listener { final Player p = e.getPlayer(); DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); if (dp != null) { - val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); + val user = DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).block(); MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); + new DiscordPlayerSender(user, Objects.requireNonNull(user).getPrivateChannel().block(), p)); MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), new DiscordPlayerSender(user, module.chatChannel().get(), p)); //Stored per-channel } @@ -99,38 +101,34 @@ class MCListener implements Listener { MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); } - private ConfigData muteRole() { + private ConfigData muteRole() { return DPUtils.roleData(module.getConfig(), "muteRole", "Muted"); } @EventHandler public void onPlayerMute(MuteStatusChangeEvent e) { - try { - DPUtils.performNoWait(() -> { - final IRole role = muteRole().get(); - if (role == null) return; - final CommandSource source = e.getAffected().getSource(); - if (!source.isPlayer()) - return; - final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) - .getAs(DiscordPlayer.class); - if (p == null) return; - final User user = DiscordPlugin.dc.getUserByID( - Long.parseLong(p.getDiscordID())); + final Role role = muteRole().get(); + if (role == null) return; + final CommandSource source = e.getAffected().getSource(); + if (!source.isPlayer()) + return; + final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) + .getAs(DiscordPlayer.class); + if (p == null) return; + DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID())) + .flatMap(user -> user.asMember(DiscordPlugin.mainServer.getId())) + .flatMap(user -> { if (e.getValue()) - user.addRole(role); + user.addRole(role.getId()); else - user.removeRole(role); + user.removeRole(role.getId()); val modlog = module.modlogChannel().get(); - String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName(); - if (modlog != null) - DiscordPlugin.sendMessageToChannel(modlog, msg); + String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getUsername() + "#" + user.getDiscriminator(); DPUtils.getLogger().info(msg); - }); - } catch (DiscordException | MissingPermissionsException ex) { - TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", - ex); - } + if (modlog != null) + return modlog.createMessage(msg); + return Mono.empty(); + }).subscribe(); } @EventHandler @@ -148,8 +146,8 @@ class MCListener implements Listener { String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO - val yeehaw = DiscordPlugin.mainServer.getEmojiByName("YEEHAW"); - MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getId().asString() + ">s" : " YEEHAWs"))); + DiscordPlugin.mainServer.getEmojis().filter(e -> "YEEHAW".equals(e.getName())).subscribe(yeehaw -> + MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getId().asString() + ">s" : " YEEHAWs")))); } @EventHandler From e2e8a58c4e46cb983c0dcfb762b5317ff234fc21 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Apr 2019 02:50:55 +0200 Subject: [PATCH 09/24] It compiles! And I thought this is gonna be easy #93 --- .../discordplugin/AsyncDiscordEvent.java | 27 ----- .../buttondevteam/discordplugin/DPUtils.java | 4 +- .../discordplugin/DiscordPlugin.java | 7 ++ .../discordplugin/DiscordRunnable.java | 10 -- .../commands/ConnectCommand.java | 30 ++--- .../discordplugin/commands/DebugCommand.java | 16 ++- .../commands/UserinfoCommand.java | 70 +++++------ .../exceptions/DebugMessageListener.java | 7 +- .../listeners/CommandListener.java | 2 +- .../discordplugin/mcchat/MCChatCommand.java | 16 ++- .../discordplugin/mcchat/MCChatListener.java | 110 +++++++++--------- .../discordplugin/mcchat/MCChatPrivate.java | 19 +-- .../discordplugin/mcchat/MCChatUtils.java | 16 ++- .../mcchat/MinecraftChatModule.java | 2 +- .../mccommands/DiscordMCCommand.java | 18 +-- .../mccommands/DiscordMCCommandBase.java | 9 -- 16 files changed, 173 insertions(+), 190 deletions(-) delete mode 100644 src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java delete mode 100755 src/main/java/buttondevteam/discordplugin/DiscordRunnable.java delete mode 100755 src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommandBase.java diff --git a/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java b/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java deleted file mode 100644 index c4479f3..0000000 --- a/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package buttondevteam.discordplugin; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -@RequiredArgsConstructor -public class AsyncDiscordEvent extends Event implements Cancellable { - private final @Getter T event; - @Getter - @Setter - private boolean cancelled; - - private static final HandlerList handlers = new HandlerList(); - - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index f4a1ce0..028a7f2 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -16,8 +16,8 @@ import java.util.regex.Matcher; public final class DPUtils { - public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String playername, String profileUrl) { - return ecs.setAuthor(playername, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png"); + public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String displayname, String playername, String profileUrl) { + return ecs.setAuthor(displayname, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png"); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 7980e37..bcf5e5e 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -73,6 +73,13 @@ public class DiscordPlugin extends ButtonPlugin { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); } + /** + * The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access. + */ + public ConfigData InviteLink() { + return getIConfig().getData("inviteLink", ""); + } + @Override public void pluginEnable() { try { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java b/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java deleted file mode 100755 index 3e8094f..0000000 --- a/src/main/java/buttondevteam/discordplugin/DiscordRunnable.java +++ /dev/null @@ -1,10 +0,0 @@ -package buttondevteam.discordplugin; - -import sx.blah.discord.util.DiscordException; -import sx.blah.discord.util.MissingPermissionsException; -import sx.blah.discord.util.RateLimitException; - -@FunctionalInterface -public interface DiscordRunnable { - void run() throws DiscordException, RateLimitException, MissingPermissionsException; -} diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index a4c829e..afa4cfb 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -1,7 +1,6 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; @@ -28,34 +27,37 @@ public class ConnectCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String Minecraftname) { val message = sender.getMessage(); - if (WaitingToConnect.inverse().containsKey(message.getAuthor().getId().asString())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getId().asString()) + " with " + Minecraftname); - WaitingToConnect.inverse().remove(message.getAuthor().getId().asString()); + val channel = message.getChannel().block(); + val author = message.getAuthor().orElse(null); + if (author == null || channel == null) return true; + if (WaitingToConnect.inverse().containsKey(author.getId().asString())) { + channel.createMessage( + "Replacing " + WaitingToConnect.inverse().get(author.getId().asString()) + " with " + Minecraftname).subscribe(); + WaitingToConnect.inverse().remove(author.getId().asString()); } @SuppressWarnings("deprecation") OfflinePlayer p = Bukkit.getOfflinePlayer(Minecraftname); if (p == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found"); + channel.createMessage("The specified Minecraft player cannot be found").subscribe(); return true; } try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { DiscordPlayer dp = pl.getAs(DiscordPlayer.class); - if (dp != null && message.getAuthor().getId().asString().equals(dp.getDiscordID())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); + if (dp != null && author.getId().asString().equals(dp.getDiscordID())) { + channel.createMessage("You already have this account connected.").subscribe(); return true; } } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "An internal error occured!\n" + e); + channel.createMessage("An internal error occured!\n" + e).subscribe(); } - WaitingToConnect.put(p.getName(), message.getAuthor().getId().asString()); - DiscordPlugin.sendMessageToChannel(message.getChannel(), + WaitingToConnect.put(p.getName(), author.getId().asString()); + channel.createMessage( "Alright! Now accept the connection in Minecraft from the account " + Minecraftname - + " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command."); + + " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command.").subscribe(); if (p.isOnline()) - ((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#" - + message.getAuthor().getDiscriminator() + " do /discord accept"); + ((Player) p).sendMessage("§bTo connect with the Discord account " + author.getUsername() + "#" + + author.getDiscriminator() + " do /discord accept"); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index 2cf87fb..e75a163 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -11,10 +11,14 @@ import buttondevteam.lib.chat.CommandClass; public class DebugCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String args) { - if (sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get())) - sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); - else - sender.sendMessage("you need to be a moderator to use this command."); - return true; - } + sender.getMessage().getAuthorAsMember() + .map(m -> m.getRoleIds().stream().anyMatch(r -> r.equals(DiscordPlugin.plugin.ModRole().get().getId()))) + .subscribe(success -> { + if (success) + sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); + else + sender.sendMessage("you need to be a moderator to use this command."); + }); + return true; + } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index 83242ae..40f98cb 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -7,13 +7,11 @@ import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.User; import lombok.val; -import sx.blah.discord.handle.obj.User; -import sx.blah.discord.handle.obj.Message; import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; @CommandClass(helpText = { "User information", // @@ -25,20 +23,21 @@ public class UserinfoCommand extends ICommand2DC { public boolean def(Command2DCSender sender, @Command2.OptionalArg @Command2.TextArg String user) { val message = sender.getMessage(); User target = null; + val channel = message.getChannel().block(); + assert channel != null; if (user == null || user.length() == 0) - target = message.getAuthor(); + target = message.getAuthor().orElse(null); else { - final Optional firstmention = message.getMentions().stream() - .filter(m -> !m.getId().asString().equals(DiscordPlugin.dc.getSelf().getId().asString())).findFirst(); - if (firstmention.isPresent()) - target = firstmention.get(); + @SuppressWarnings("OptionalGetWithoutIsPresent") final User firstmention = message.getUserMentions() + .filter(m -> !m.getId().asString().equals(DiscordPlugin.dc.getSelfId().get().asString())).blockFirst(); + if (firstmention != null) + target = firstmention; else if (user.contains("#")) { String[] targettag = user.split("#"); final List targets = getUsers(message, targettag[0]); if (targets.size() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found (by name): " + user); - return true; + channel.createMessage("The user cannot be found (by name): " + user).subscribe(); + return true; } for (User ptarget : targets) { if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { @@ -47,44 +46,47 @@ public class UserinfoCommand extends ICommand2DC { } } if (target == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found (by discriminator): " + user + "(Found " + targets.size() - + " users with the name.)"); - return true; + channel.createMessage("The user cannot be found (by discriminator): " + user + "(Found " + targets.size() + + " users with the name.)").subscribe(); + return true; } } else { final List targets = getUsers(message, user); if (targets.size() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found on Discord: " + user); - return true; + channel.createMessage("The user cannot be found on Discord: " + user).subscribe(); + return true; } if (targets.size() > 1) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping."); - return true; + channel.createMessage("Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping.").subscribe(); + return true; } target = targets.get(0); } } - try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getId().asString(), DiscordPlayer.class)) { - StringBuilder uinfo = new StringBuilder("User info for ").append(target.getName()).append(":\n"); - uinfo.append(dp.getInfo(InfoTarget.Discord)); - DiscordPlugin.sendMessageToChannel(message.getChannel(), uinfo.toString()); - } catch (Exception e) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while getting the user!"); - TBMCCoreAPI.SendException("Error while getting info about " + target.getName() + "!", e); + if (target == null) { + sender.sendMessage("An error occurred."); + return true; } - return true; + try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getId().asString(), DiscordPlayer.class)) { + StringBuilder uinfo = new StringBuilder("User info for ").append(target.getUsername()).append(":\n"); + uinfo.append(dp.getInfo(InfoTarget.Discord)); + channel.createMessage(uinfo.toString()).subscribe(); + } catch (Exception e) { + channel.createMessage("An error occured while getting the user!").subscribe(); + TBMCCoreAPI.SendException("Error while getting info about " + target.getUsername() + "!", e); + } + return true; } private List getUsers(Message message, String args) { final List targets; - if (message.getChannel().isPrivate()) - targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args)) - .collect(Collectors.toList()); + val guild = message.getGuild().block(); + if (guild == null) //Private channel + targets = DiscordPlugin.dc.getUsers().filter(u -> u.getUsername().equalsIgnoreCase(args)) + .collectList().block(); else - targets = message.getGuild().getUsersByName(args, true); + targets = guild.getMembers().filter(m -> m.getUsername().equalsIgnoreCase(args)) + .map(m -> (User) m).collectList().block(); return targets; } diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java index 95c3cdb..12606af 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java @@ -3,10 +3,11 @@ package buttondevteam.discordplugin.exceptions; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCDebugMessageEvent; +import discord4j.core.object.entity.MessageChannel; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -public class DebugMessageListener implements Listener{ +public class DebugMessageListener implements Listener { @EventHandler public void onDebugMessage(TBMCDebugMessageEvent e) { SendMessage(e.getDebugMessage()); @@ -17,13 +18,15 @@ public class DebugMessageListener implements Listener{ if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(ExceptionListenerModule.class)) return; try { + MessageChannel mc = ExceptionListenerModule.getChannel(); + if (mc == null) return; StringBuilder sb = new StringBuilder(); sb.append("```").append("\n"); if (message.length() > 2000) message = message.substring(0, 2000); sb.append(message).append("\n"); sb.append("```"); - DiscordPlugin.sendMessageToChannel(ExceptionListenerModule.getChannel(), sb.toString()); + mc.createMessage(sb.toString()).subscribe(); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 2bb9399..f72e066 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -19,7 +19,7 @@ public class CommandListener { * @return Whether it ran the command */ public static boolean runCommand(Message message, boolean mentionedonly) { - if (message.getContent().isEmpty()) + if (!message.getContent().isPresent()) return false; //Pin messages and such, let the mcchat listener deal with it final MessageChannel channel = message.getChannel().block(); @SuppressWarnings("OptionalGetWithoutIsPresent") val content = message.getContent().get(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index df2bff0..63b2fb5 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; @@ -7,6 +8,7 @@ import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; +import discord4j.core.object.entity.PrivateChannel; import lombok.val; @CommandClass(helpText = { @@ -20,18 +22,20 @@ public class MCChatCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender) { val message = sender.getMessage(); - if (!message.getChannel().isPrivate()) { - DPUtils.reply(message, null, "this command can only be issued in a direct message with the bot."); + val channel = message.getChannel().block(); + @SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get(); + if (!(channel instanceof PrivateChannel)) { + DPUtils.reply(message, null, "this command can only be issued in a direct message with the bot.").subscribe(); return true; } - try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getId().asString(), DiscordPlayer.class)) { + try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); - MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); + MCChatPrivate.privateMCChat(channel, mcchat, author, user); DPUtils.reply(message, null, "Minecraft chat " + (mcchat // ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // - : "disabled.")); + : "disabled.")).subscribe(); } catch (Exception e) { - TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e); + TBMCCoreAPI.SendException("Error while setting mcchat for user " + author.getUsername() + "#" + author.getDiscriminator(), e); } return true; } // TODO: Pin channel switching to indicate the current channel diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 550e9df..d89740c 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -15,10 +15,8 @@ import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; import discord4j.core.event.domain.message.MessageCreateEvent; -import discord4j.core.object.entity.MessageChannel; -import discord4j.core.object.entity.PrivateChannel; -import discord4j.core.object.entity.TextChannel; -import discord4j.core.object.entity.User; +import discord4j.core.object.Embed; +import discord4j.core.object.entity.*; import discord4j.core.spec.EmbedCreateSpec; import lombok.val; import org.bukkit.Bukkit; @@ -34,6 +32,7 @@ import java.util.Arrays; import java.util.Optional; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -75,46 +74,39 @@ public class MCChatListener implements Listener { final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName().get()) + "] " // + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin().substring(0, 1) + "]") // - + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // - ? ((Player) e.getSender()).getDisplayName() // - : e.getSender().getName())); + + (DPUtils.sanitizeStringNoEscape(ThorpeUtils.getDisplayName(e.getSender()))); val color = e.getChannel().Color().get(); - final EmbedCreateSpec embed = new EmbedBuilder().withAuthorName(authorPlayer) - .withDescription(e.getMessage()).withColor(new Color(color.getRed(), + final Consumer embed = ecs -> { + ecs.setDescription(e.getMessage()).setColor(new Color(color.getRed(), color.getGreen(), color.getBlue())); - // embed.appendField("Channel", ((e.getSender() instanceof DiscordSenderBase ? "d|" : "") - // + DiscordPlugin.sanitizeString(e.getChannel().DisplayName)), false); - if (e.getSender() instanceof Player) - DPUtils.embedWithHead( - embed.withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=minecraft&id=" - + ((Player) e.getSender()).getUniqueId()), - e.getSender().getName()); - else if (e.getSender() instanceof DiscordSenderBase) - embed.withAuthorIcon(((DiscordSenderBase) e.getSender()).getUser().getAvatarURL()) - .withAuthorUrl("https://tbmcplugins.github.io/profile.html?type=discord&id=" - + ((DiscordSenderBase) e.getSender()).getUser().getId().asString()); // TODO: Constant/method to get URLs like this - // embed.withFooterText(e.getChannel().DisplayName); - embed.withTimestamp(time); + if (e.getSender() instanceof Player) + DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), + "https://tbmcplugins.github.io/profile.html?type=minecraft&id=" + + ((Player) e.getSender()).getUniqueId()); + else if (e.getSender() instanceof DiscordSenderBase) + ecs.setAuthor(authorPlayer, "https://tbmcplugins.github.io/profile.html?type=discord&id=" // TODO: Constant/method to get URLs like this + + ((DiscordSenderBase) e.getSender()).getUser().getId().asString(), + ((DiscordSenderBase) e.getSender()).getUser().getAvatarUrl()); + else + DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), null); + ecs.setTimestamp(time); + }; final long nanoTime = System.nanoTime(); InterruptibleConsumer doit = lastmsgdata -> { - final EmbedObject embedObject = embed.build(); - if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() - || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) + if (lastmsgdata.message == null + || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().map(Embed.Author::getName).orElse(null)) || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 || !lastmsgdata.mcchannel.ID.equals(e.getChannel().ID)) { - lastmsgdata.message = DiscordPlugin.sendMessageToChannelWait(lastmsgdata.channel, "", - embedObject); // TODO Use ChromaBot API + lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block(); lastmsgdata.time = nanoTime; lastmsgdata.mcchannel = e.getChannel(); - lastmsgdata.content = embedObject.description; - } else - try { - lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n" - + embedObject.description;// The message object doesn't get updated - lastmsgdata.message.edit(mes -> mes.setEmbed(ecs -> embedObject)).block(); - } catch (MissingPermissionsException | DiscordException e1) { - TBMCCoreAPI.SendException("An error occurred while editing chat message!", e1); - } + lastmsgdata.content = e.getMessage(); + } else { + lastmsgdata.content = lastmsgdata.content + "\n" + + e.getMessage(); // The message object doesn't get updated + lastmsgdata.message.edit(mes -> mes.setEmbed(embed.andThen(ecs -> + ecs.setDescription(lastmsgdata.content)))).block(); + } }; // Checks if the given channel is different than where the message was sent from // Or if it was from MC @@ -124,12 +116,12 @@ public class MCChatListener implements Listener { if (e.getChannel().isGlobal() && (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get()))) doit.accept(MCChatUtils.lastmsgdata == null - ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData((TextChannel) module.chatChannel().get(), null) + ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null) : MCChatUtils.lastmsgdata); for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { if ((e.isFromCommand() || isdifferentchannel.test(data.channel)) - && e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user))) + && e.shouldSendTo(MCChatUtils.getSender(data.channel.getId(), data.user))) doit.accept(data); } @@ -143,7 +135,7 @@ public class MCChatListener implements Listener { doit.accept(lmd); else { iterator.remove(); //If the user no longer has permission, remove the connection - DiscordPlugin.sendMessageToChannel(lmd.channel, "The user no longer has permission to view the channel, connection removed."); + lmd.channel.createMessage("The user no longer has permission to view the channel, connection removed.").subscribe(); } } } @@ -271,13 +263,16 @@ public class MCChatListener implements Listener { final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannelId(), sender); val user = dsender.getChromaUser(); - for (User u : event.getMessage().getUserMentions()) { //TODO: Role mentions - dmessage = dmessage.replace(u.me(false), "@" + u.getName()); // TODO: IG Formatting - final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); - dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); + for (User u : event.getMessage().getUserMentions().toIterable()) { //TODO: Role mentions + dmessage = dmessage.replace(u.getMention(), "@" + u.getUsername()); // TODO: IG Formatting + val m = u.asMember(DiscordPlugin.mainServer.getId()).block(); + if (m != null) { + final String nick = m.getDisplayName(); + dmessage = dmessage.replace(m.getNicknameMention(), "@" + nick); + } } - for (MessageChannel ch : event.getMessage().getChannelMentions()) { - dmessage = dmessage.replace(ch.mention(), "#" + ch.getName()); // TODO: IG Formatting + for (GuildChannel ch : event.getGuild().flux().flatMap(Guild::getChannels).toIterable()) { + dmessage = dmessage.replace(ch.getMention(), "#" + ch.getName()); // TODO: IG Formatting } dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?) @@ -285,18 +280,18 @@ public class MCChatListener implements Listener { Function getChatMessage = msg -> // msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() - .getAttachments().stream().map(Message.Attachment::getUrl).collect(Collectors.joining("\n")) + .getAttachments().stream().map(Attachment::getUrl).collect(Collectors.joining("\n")) : ""); - MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel()); + MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getMessage().getChannelId()); boolean react = false; + val sendChannel = event.getMessage().getChannel().block(); + boolean isPrivate = sendChannel instanceof PrivateChannel; if (dmessage.startsWith("/")) { // Ingame command - DPUtils.perform(() -> { - if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) - event.getMessage().delete(); - }); + if (!isPrivate) + event.getMessage().delete().subscribe(); final String cmd = dmessage.substring(1); final String cmdlowercased = cmd.toLowerCase(); if (dsender instanceof DiscordSender && module.whitelistedCommands().get().stream() @@ -338,7 +333,7 @@ public class MCChatListener implements Listener { }); else { Channel chc = ch.get(); - if (!chc.isGlobal() && !event.getMessage().getChannel().isPrivate()) + if (!chc.isGlobal() && !isPrivate) dsender.sendMessage( "You can only talk in a public chat here. DM `mcchat` to enable private chat to talk in the other channels."); else { @@ -369,7 +364,7 @@ public class MCChatListener implements Listener { } } else {// Not a command if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 - && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) { + && !isPrivate && event.getMessage().getType() == Message.Type.CHANNEL_PINNED_MESSAGE) { val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp) : dsender.getChromaUser().channel().get().getRTR(dsender); TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr, @@ -386,16 +381,15 @@ public class MCChatListener implements Listener { } if (react) { try { - val lmfd = MCChatUtils.lastmsgfromd.get(event.getChannel().getId().asLong()); + val lmfd = MCChatUtils.lastmsgfromd.get(event.getMessage().getChannelId().asLong()); if (lmfd != null) { - DPUtils.perform(() -> lmfd.removeReaction(DiscordPlugin.dc.getSelf(), - DiscordPlugin.DELIVERED_REACTION)); // Remove it no matter what, we know it's there 99.99% of the time + lmfd.removeSelfReaction(DiscordPlugin.DELIVERED_REACTION).subscribe(); // Remove it no matter what, we know it's there 99.99% of the time } } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e); } - MCChatUtils.lastmsgfromd.put(event.getChannel().getId().asLong(), event.getMessage()); - DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION)); + MCChatUtils.lastmsgfromd.put(event.getMessage().getChannelId().asLong(), event.getMessage()); + event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION).subscribe(); } } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while handling message \"" + dmessage + "\"!", e); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index e706a68..452168a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -1,18 +1,19 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.player.TBMCPlayer; import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.PrivateChannel; +import discord4j.core.object.entity.TextChannel; +import discord4j.core.object.entity.User; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; -import sx.blah.discord.handle.obj.IPrivateChannel; -import sx.blah.discord.handle.obj.User; -import sx.blah.discord.handle.obj.MessageChannel; import java.util.ArrayList; @@ -28,13 +29,14 @@ public class MCChatPrivate { if (mcp != null) { // If the accounts aren't connected, can't make a connected sender val p = Bukkit.getPlayer(mcp.getUUID()); val op = Bukkit.getOfflinePlayer(mcp.getUUID()); + val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class); if (start) { - val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); + val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName(), mcm); MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence callEventSync(new PlayerJoinEvent(sender, "")); } else { - val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel, user); + val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user); if (p == null)// Player is offline - If the player is online, that takes precedence callEventSync(new PlayerQuitEvent(sender, "")); } @@ -42,8 +44,8 @@ public class MCChatPrivate { if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId().asLong()); return start // - ? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs - : lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()); + ? lastmsgPerUser.add(new MCChatUtils.LastMsgData((TextChannel) channel, user)) // Doesn't support group DMs + : lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()); } public static boolean isMinecraftChatEnabled(DiscordPlayer dp) { @@ -52,7 +54,8 @@ public class MCChatPrivate { public static boolean isMinecraftChatEnabled(String did) { // Don't load the player data just for this return lastmsgPerUser.stream() - .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getId().asString().equals(did)); + .anyMatch(lmd -> ((PrivateChannel) lmd.channel) + .getRecipientIds().stream().anyMatch(u -> u.asString().equals(did))); } public static void logoutAll() { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 6ee9292..6cb58ee 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; +import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import discord4j.core.object.entity.*; import discord4j.core.object.util.Snowflake; @@ -60,7 +61,12 @@ public class MCChatUtils { } private static void updatePL(LastMsgData lmd) { - String topic = lmd.channel.getTopic().orElse(""); + if (!(lmd.channel instanceof TextChannel)) { + TBMCCoreAPI.SendException("Failed to update player list for channel " + lmd.channel.getId(), + new Exception("The channel isn't a (guild) text channel.")); + return; + } + String topic = ((TextChannel) lmd.channel).getTopic().orElse(""); if (topic.length() == 0) topic = ".\n----\nMinecraft chat\n----\n."; String[] s = topic.split("\\n----\\n"); @@ -70,7 +76,7 @@ public class MCChatUtils { + " online"; s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream() .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); - lmd.channel.edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait + ((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } public static T addSender(HashMap> senders, @@ -204,7 +210,7 @@ public class MCChatUtils { public static void resetLastMessage(Channel channel) { if (notEnabled()) return; if (channel.getId().asLong() == module.chatChannel().get().getId().asLong()) { - (lastmsgdata == null ? lastmsgdata = new LastMsgData((TextChannel) module.chatChannel().get(), null) + (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null) : lastmsgdata).message = null; return; } // Don't set the whole object to null, the player and channel information should be preserved @@ -285,8 +291,8 @@ public class MCChatUtils { public Message message; public long time; public String content; - public final TextChannel channel; - public Channel mcchannel; + public final MessageChannel channel; + public buttondevteam.core.component.channel.Channel mcchannel; public final User user; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 76383b7..cc7e9dc 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -78,7 +78,7 @@ public class MinecraftChatModule extends Component { TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled getPlugin().getManager().registerCommand(new MCChatCommand()); - getPlugin().getManager().registerCommand(new ChannelconCommand()); + getPlugin().getManager().registerCommand(new ChannelconCommand(this)); val chcons = getConfig().getConfig().getConfigurationSection("chcons"); if (chcons == null) //Fallback to old place diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 7fa76d0..6ff0ccc 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -8,16 +8,15 @@ import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.discordplugin.commands.VersionCommand; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.chat.Command2; -import buttondevteam.lib.chat.Command2MCSender; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayerBase; -import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import reactor.core.publisher.Mono; import java.lang.reflect.Method; @@ -98,11 +97,16 @@ public class DiscordMCCommand extends ICommand2MC { "Shows an invite link to the server" }) public void invite(CommandSender sender) { - val inv=DiscordPlugin.mainServer.getExtendedInvites().stream().findAny(); //TODO: Needs manage server perms - if (!inv.isPresent()) - sender.sendMessage("§cNo invites found for the server."); - else - sender.sendMessage("§bInvite link: https://discord.gg/"+inv.get().getCode()); + String invi = DiscordPlugin.plugin.InviteLink().get(); + if (invi.length() > 0) { + sender.sendMessage("§bInvite link: " + invi); + return; + } + DiscordPlugin.mainServer.getInvites().limitRequest(1) + .switchIfEmpty(Mono.fromRunnable(() -> sender.sendMessage("§cNo invites found for the server."))) + .subscribe(inv -> {//TODO: Needs manage server perms + sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode()); + }); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommandBase.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommandBase.java deleted file mode 100755 index 5edbafe..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommandBase.java +++ /dev/null @@ -1,9 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.PlayerCommandBase; - -@CommandClass(modOnly = false, path = "discord") -public abstract class DiscordMCCommandBase extends PlayerCommandBase { - -} From eeb1955ebe6784c5f2757b949ed0f94cf7333abf Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Apr 2019 19:52:43 +0200 Subject: [PATCH 10/24] Bunch of fixes #93 --- pom.xml | 7 +- .../buttondevteam/discordplugin/DPUtils.java | 9 +- .../discordplugin/DiscordPlugin.java | 141 ++++++++---------- .../discordplugin/DiscordSenderBase.java | 2 +- .../commands/Command2DCSender.java | 9 +- .../discordplugin/commands/HelpCommand.java | 18 ++- .../listeners/CommandListener.java | 21 +-- .../listeners/CommonListeners.java | 73 ++++----- .../discordplugin/mcchat/MCChatCustom.java | 3 +- .../discordplugin/mcchat/MCChatListener.java | 1 + .../discordplugin/mcchat/MCChatPrivate.java | 3 +- .../mcchat/MinecraftChatModule.java | 2 - .../mccommands/DiscordMCCommand.java | 4 +- 13 files changed, 145 insertions(+), 148 deletions(-) diff --git a/pom.xml b/pom.xml index 7a38cc9..fc313cc 100755 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ com.discord4j discord4j-core - 3.0.2 + 3.0.3 @@ -200,11 +200,6 @@ 2.13.1 provided - - com.github.xaanit - D4J-OAuth - master-SNAPSHOT - org.projectlombok diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 028a7f2..069e675 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -58,7 +58,10 @@ public final class DPUtils { public static ConfigData channelData(IHaveConfig config, String key, long defID) { return config.getDataPrimDef(key, defID, id -> { - Channel ch = DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).block(); + Channel ch = DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).onErrorResume(e -> { + getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage()); + return Mono.empty(); + }).block(); if (ch instanceof MessageChannel) return (MessageChannel) ch; else @@ -127,4 +130,8 @@ public final class DPUtils { ? original.getAuthor().get().getMention() + ", " : "") + message)); } + public static String nickMention(Snowflake userId) { + return "<@!" + userId.asString() + ">"; + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index bcf5e5e..307f8b9 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -20,6 +20,7 @@ import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; import discord4j.core.DiscordClient; import discord4j.core.DiscordClientBuilder; +import discord4j.core.event.domain.guild.GuildCreateEvent; import discord4j.core.event.domain.lifecycle.ReadyEvent; import discord4j.core.object.entity.Guild; import discord4j.core.object.entity.MessageChannel; @@ -35,14 +36,14 @@ import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.scheduler.BukkitTask; import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.List; +import java.util.Objects; import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class DiscordPlugin extends ButtonPlugin { @@ -105,15 +106,16 @@ public class DiscordPlugin extends ButtonPlugin { } } val cb = new DiscordClientBuilder(token); + cb.setInitialPresence(Presence.doNotDisturb(Activity.playing("booting"))); dc = cb.build(); - dc.getEventDispatcher().on(ReadyEvent.class).subscribe(this::handleReady); - /*dc.getEventDispatcher().on(ReadyEvent.class) // Listen for ReadyEvent(s) + dc.getEventDispatcher().on(ReadyEvent.class) // Listen for ReadyEvent(s) .map(event -> event.getGuilds().size()) // Get how many guilds the bot is in .flatMap(size -> dc.getEventDispatcher() .on(GuildCreateEvent.class) // Listen for GuildCreateEvent(s) .take(size) // Take only the first `size` GuildCreateEvent(s) to be received .collectList()) // Take all received GuildCreateEvents and make it a List - .subscribe(events -> /* All guilds have been received, client is fully connected *);*/ //TODO + .subscribe(this::handleReady); /* All guilds have been received, client is fully connected */ + dc.login().subscribe(); } catch (Exception e) { e.printStackTrace(); Bukkit.getPluginManager().disablePlugin(this); @@ -122,86 +124,68 @@ public class DiscordPlugin extends ButtonPlugin { public static Guild mainServer; - private static volatile BukkitTask task; - private static volatile boolean sent = false; - - private void handleReady(ReadyEvent event) { + private void handleReady(List event) { try { - dc.updatePresence(Presence.doNotDisturb(Activity.playing("booting"))).subscribe(); - val tries = new AtomicInteger(); - task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { - tries.incrementAndGet(); - if (tries.get() > 10) { //5 seconds - task.cancel(); + mainServer = MainServer().get(); //Shouldn't change afterwards + if (mainServer == null) { + if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); - //getIConfig().getConfig().set("mainServer", 219529124321034241L); //Needed because it won't save as long as it's null - made it save saveConfig(); //Put default there - return; + return; //We should have all guilds by now, no need to retry } - mainServer = MainServer().get(); //Shouldn't change afterwards - if (mainServer == null) { - val guilds = dc.getGuilds(); - if (guilds.count().blockOptional().orElse(0L) == 0L) - return; //If there are no guilds in cache, retry - mainServer = guilds.blockFirst(); - if (mainServer == null) return; - getLogger().warning("Main server set to first one: " + mainServer.getName()); - MainServer().set(mainServer); //Save in config - } - if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - dc.updatePresence(Presence.online(Activity.playing("Minecraft"))); - } else { - dc.updatePresence(Presence.online(Activity.playing("testing"))); - } - SafeMode = false; - if (task != null) - task.cancel(); - if (!sent) { - DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here + mainServer = event.get(0).getGuild(); + getLogger().warning("Main server set to first one: " + mainServer.getName()); + MainServer().set(mainServer); //Save in config + } + if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() + dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); + } else { + dc.updatePresence(Presence.online(Activity.playing("testing"))).subscribe(); + } + SafeMode = false; + DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here - Component.registerComponent(this, new GeneralEventBroadcasterModule()); - Component.registerComponent(this, new MinecraftChatModule()); - Component.registerComponent(this, new ExceptionListenerModule()); - Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set - Component.registerComponent(this, new AnnouncerModule()); - Component.registerComponent(this, new FunModule()); - new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled + Component.registerComponent(this, new GeneralEventBroadcasterModule()); + Component.registerComponent(this, new MinecraftChatModule()); + Component.registerComponent(this, new ExceptionListenerModule()); + Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set + Component.registerComponent(this, new AnnouncerModule()); + Component.registerComponent(this, new FunModule()); + new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled - getManager().registerCommand(new VersionCommand()); - getManager().registerCommand(new UserinfoCommand()); - getManager().registerCommand(new HelpCommand()); - getManager().registerCommand(new DebugCommand()); - getManager().registerCommand(new ConnectCommand()); - if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled - ChromaBot.getInstance().sendMessageCustomAsWell(ch->ch.createEmbed(ecs->ecs.setColor(Color.CYAN) - .setTitle("Discord plugin restarted - chat connected.")), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm - else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessageCustomAsWell(ch->ch.createEmbed(ecs->ecs.setColor(Color.YELLOW) - .setTitle("Server recovered from a crash - chat connected.")), ChannelconBroadcast.RESTART); - val thr = new Throwable( - "The server shut down unexpectedly. See the log of the previous run for more details."); - thr.setStackTrace(new StackTraceElement[0]); - TBMCCoreAPI.SendException("The server crashed!", thr); - } else - ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) - .setTitle("Server started - chat connected.")), ChannelconBroadcast.RESTART); + getManager().registerCommand(new VersionCommand()); + getManager().registerCommand(new UserinfoCommand()); + getManager().registerCommand(new HelpCommand()); + getManager().registerCommand(new DebugCommand()); + getManager().registerCommand(new ConnectCommand()); + if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled + ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.CYAN) + .setTitle("Discord plugin restarted - chat connected.")), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm + else if (getConfig().getBoolean("serverup", false)) { + ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.YELLOW) + .setTitle("Server recovered from a crash - chat connected.")), ChannelconBroadcast.RESTART); + val thr = new Throwable( + "The server shut down unexpectedly. See the log of the previous run for more details."); + thr.setStackTrace(new StackTraceElement[0]); + TBMCCoreAPI.SendException("The server crashed!", thr); + } else + ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) + .setTitle("Server started - chat connected.")), ChannelconBroadcast.RESTART); - DiscordMCCommand.resetting = false; //This is the last event handling this flag + DiscordMCCommand.resetting = false; //This is the last event handling this flag + + getConfig().set("serverup", true); + saveConfig(); + if (TBMCCoreAPI.IsTestServer() && !Objects.requireNonNull(dc.getSelf().block()).getUsername().toLowerCase().contains("test")) { + TBMCCoreAPI.SendException( + "Won't load because we're in testing mode and not using a separate account.", + new Exception( + "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)")); + Bukkit.getPluginManager().disablePlugin(this); + } + TBMCCoreAPI.SendUnsentExceptions(); + TBMCCoreAPI.SendUnsentDebugMessages(); - getConfig().set("serverup", true); - saveConfig(); - sent = true; - if (TBMCCoreAPI.IsTestServer() && !event.getSelf().getUsername().toLowerCase().contains("test")) { - TBMCCoreAPI.SendException( - "Won't load because we're in testing mode and not using a separate account.", - new Exception( - "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)")); - Bukkit.getPluginManager().disablePlugin(this); - } - TBMCCoreAPI.SendUnsentExceptions(); - TBMCCoreAPI.SendUnsentDebugMessages(); - } - }, 0, 10); CommonListeners.register(dc.getEventDispatcher()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); getCommand2MC().registerCommand(new DiscordMCCommand()); @@ -253,7 +237,6 @@ public class DiscordPlugin extends ButtonPlugin { dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing dc.logout().block(); //Configs are emptied so channels and servers are fetched again - sent = false; } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); } @@ -263,7 +246,7 @@ public class DiscordPlugin extends ButtonPlugin { public static Permission perms; - public boolean setupProviders() { + private boolean setupProviders() { try { Class.forName("net.milkbowl.vault.permission.Permission"); Class.forName("net.milkbowl.vault.chat.Chat"); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index 145a8c0..103a350 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -58,7 +58,7 @@ public abstract class DiscordSenderBase implements CommandSender { msgtosend += "\n" + sendmsg; if (sendtask == null) sendtask = Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - channel.createMessage((!broadcast && user != null ? user.getMention() + "\n" : "") + msgtosend.trim()); + channel.createMessage((!broadcast && user != null ? user.getMention() + "\n" : "") + msgtosend.trim()).subscribe(); sendtask = null; msgtosend = ""; }, 4); // Waits a 0.2 second to gather all/most of the different messages diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index 1165612..8b705fd 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -18,9 +18,12 @@ public class Command2DCSender implements Command2Sender { message = DPUtils.sanitizeString(message); message = Character.toLowerCase(message.charAt(0)) + message.substring(1); val msg = message; - val author = this.message.getAuthorAsMember().block(); - if (author == null) return; - this.message.getChannel().subscribe(ch -> ch.createMessage(author.getNicknameMention() + ", " + msg)); + /*this.message.getAuthorAsMember().flatMap(author -> + this.message.getChannel().flatMap(ch -> + ch.createMessage(author.getNicknameMention() + ", " + msg))).subscribe();*/ + this.message.getChannel().flatMap(ch -> + ch.createMessage(this.message.getAuthor().map(u -> DPUtils.nickMention(u.getId()) + ", ").orElse("") + + msg)).subscribe(); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java index 0194dab..546d4ee 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.commands; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; @CommandClass(helpText = { @@ -7,12 +8,17 @@ import buttondevteam.lib.chat.CommandClass; "Shows some info about a command or lists the available commands.", // }) public class HelpCommand extends ICommand2DC { - @Override - public boolean def(Command2DCSender sender, String args) { - if (args.length() == 0) + @Command2.Subcommand + public boolean def(Command2DCSender sender, @Command2.TextArg @Command2.OptionalArg String args) { + if (args == null || args.length() == 0) sender.sendMessage(getManager().getCommandsText()); - else - sender.sendMessage("Soon:tm:"); //TODO - return true; + else { + String[] ht = getManager().getHelpText(args); + if (ht == null) + sender.sendMessage("Command not found: " + args); + else + sender.sendMessage(ht); + } + return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index f72e066..aff8339 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -22,7 +22,7 @@ public class CommandListener { if (!message.getContent().isPresent()) return false; //Pin messages and such, let the mcchat listener deal with it final MessageChannel channel = message.getChannel().block(); - @SuppressWarnings("OptionalGetWithoutIsPresent") val content = message.getContent().get(); + val content = message.getContent().get(); if (channel == null) return false; if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!(channel instanceof PrivateChannel) @@ -32,10 +32,10 @@ public class CommandListener { channel.type().subscribe(); // Fun } final StringBuilder cmdwithargs = new StringBuilder(content); - val self=DiscordPlugin.dc.getSelf().block(); - if(self==null) return false; - val member=self.asMember(DiscordPlugin.mainServer.getId()).block(); - if(member==null) return false; + val self = DiscordPlugin.dc.getSelf().block(); + if (self == null) return false; + val member = self.asMember(DiscordPlugin.mainServer.getId()).block(); + if (member == null) return false; final String mention = self.getMention(); final String mentionNick = member.getNicknameMention(); boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); @@ -57,6 +57,7 @@ public class CommandListener { } private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, Message message) { + final char prefix = DiscordPlugin.getPrefix(); if (message.getContent().orElse("").startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text if (cmdwithargs.length() > mention.length() + 1) { int i = cmdwithargs.indexOf(" ", mention.length()); @@ -67,14 +68,16 @@ public class CommandListener { for (; i < cmdwithargs.length() && cmdwithargs.charAt(i) == ' '; i++) ; //Removes any space before the command cmdwithargs.delete(0, i); - cmdwithargs.insert(0, DiscordPlugin.getPrefix()); //Always use the prefix for processing + cmdwithargs.insert(0, prefix); //Always use the prefix for processing } else - cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help"); + cmdwithargs.replace(0, cmdwithargs.length(), prefix + "help"); else { + if (cmdwithargs.length() == 0) + cmdwithargs.replace(0, cmdwithargs.length(), prefix + "help"); + else if (cmdwithargs.charAt(0) != prefix) + cmdwithargs.insert(0, prefix); return false; //Don't treat / as mention, mentions can be used in public mcchat } - if (cmdwithargs.length() == 0) - cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help"); return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 48376b8..6c55615 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -27,48 +27,51 @@ public class CommonListeners { - CommandListener (with the correct prefix in #bot, or in private) */ public static void register(EventDispatcher dispatcher) { - dispatcher.on(MessageCreateEvent.class).subscribe(event->{ - if (DiscordPlugin.SafeMode) - return; + dispatcher.on(MessageCreateEvent.class).subscribe(event -> { + if (DiscordPlugin.SafeMode) + return; val author = event.getMessage().getAuthor(); if (!author.isPresent() || author.get().isBot()) - return; - if (FunModule.executeMemes(event.getMessage())) - return; - try { - boolean handled = false; - val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); - if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.getId().asLong()) //If mentioned, that's higher than chat - || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels - handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here - if (handled) return; - val mcchat = Component.getComponents().get(MinecraftChatModule.class); - if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again - handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels - if (!handled) - handled = CommandListener.runCommand(event.getMessage(), false); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while handling a message!", e); - } - }); - dispatcher.on(PresenceUpdateEvent.class).subscribe(event->{ - if (DiscordPlugin.SafeMode) - return; - FunModule.handleFullHouse(event); - }); + return; + //System.out.println("Author: "+author.get()); + //System.out.println("Bot: "+author.get().isBot()); + if (FunModule.executeMemes(event.getMessage())) + return; + try { + boolean handled = false; + val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); + if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.getId().asLong()) //If mentioned, that's higher than chat + || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels + handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here + if (handled) return; + //System.out.println("Message handling"); + val mcchat = Component.getComponents().get(MinecraftChatModule.class); + if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again + handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels + if (!handled) + handled = CommandListener.runCommand(event.getMessage(), false); + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while handling a message!", e); + } + }); + dispatcher.on(PresenceUpdateEvent.class).subscribe(event -> { + if (DiscordPlugin.SafeMode) + return; + FunModule.handleFullHouse(event); + }); dispatcher.on(RoleCreateEvent.class).subscribe(GameRoleModule::handleRoleEvent); dispatcher.on(RoleDeleteEvent.class).subscribe(GameRoleModule::handleRoleEvent); dispatcher.on(RoleUpdateEvent.class).subscribe(GameRoleModule::handleRoleEvent); } - private static boolean debug = false; + private static boolean debug = false; - public static void debug(String debug) { - if (CommonListeners.debug) //Debug - DPUtils.getLogger().info(debug); - } + public static void debug(String debug) { + if (CommonListeners.debug) //Debug + DPUtils.getLogger().info(debug); + } - public static boolean debug() { - return debug = !debug; - } + public static boolean debug() { + return debug = !debug; + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index c83232b..c9edaca 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -5,7 +5,6 @@ import buttondevteam.core.component.channel.ChatRoom; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.lib.TBMCSystemChatEvent; import discord4j.core.object.entity.MessageChannel; -import discord4j.core.object.entity.TextChannel; import discord4j.core.object.entity.User; import discord4j.core.object.util.Snowflake; import lombok.NonNull; @@ -65,7 +64,7 @@ public class MCChatCustom { private CustomLMD(@NonNull MessageChannel channel, @NonNull User user, @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, Set brtoggles) { - super((TextChannel) channel, user); + super(channel, user); groupID = groupid; this.mcchannel = mcchannel; this.dcp = dcp; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index d89740c..f013c1b 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -236,6 +236,7 @@ public class MCChatListener implements Listener { if (CommandListener.runCommand(ev.getMessage(), true)) return true; //Allow running commands in chat channels MCChatUtils.resetLastMessage(channel); + //System.out.println("Message: "+ev.getMessage().getAuthor().toString()); recevents.add(ev); if (rectask != null) return true; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 452168a..1ef1111 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -7,7 +7,6 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.player.TBMCPlayer; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.PrivateChannel; -import discord4j.core.object.entity.TextChannel; import discord4j.core.object.entity.User; import lombok.val; import org.bukkit.Bukkit; @@ -44,7 +43,7 @@ public class MCChatPrivate { if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId().asLong()); return start // - ? lastmsgPerUser.add(new MCChatUtils.LastMsgData((TextChannel) channel, user)) // Doesn't support group DMs + ? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs : lastmsgPerUser.removeIf(lmd -> lmd.channel.getId().asLong() == channel.getId().asLong()); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index cc7e9dc..d7f1860 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -9,7 +9,6 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import com.google.common.collect.Lists; -import discord4j.core.event.domain.message.MessageCreateEvent; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.util.Snowflake; import lombok.Getter; @@ -74,7 +73,6 @@ public class MinecraftChatModule extends Component { protected void enable() { if (DPUtils.disableIfConfigError(this, chatChannel())) return; listener = new MCChatListener(this); - DiscordPlugin.dc.getEventDispatcher().on(MessageCreateEvent.class).subscribe(listener::handleDiscord); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled getPlugin().getManager().registerCommand(new MCChatCommand()); diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 6ff0ccc..0fd6fe3 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -104,9 +104,9 @@ public class DiscordMCCommand extends ICommand2MC { } DiscordPlugin.mainServer.getInvites().limitRequest(1) .switchIfEmpty(Mono.fromRunnable(() -> sender.sendMessage("§cNo invites found for the server."))) - .subscribe(inv -> {//TODO: Needs manage server perms + .subscribe(inv -> { sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode()); - }); + }, e -> sender.sendMessage("§cThe invite link is not set and the bot has no permission to get it.")); } @Override From 4881f6bdd24d231c62c524e8e8e157fac9f4175b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 1 May 2019 00:50:24 +0200 Subject: [PATCH 11/24] Some more fixes Made the channel data return a Mono and used that #93 --- .../buttondevteam/discordplugin/DPUtils.java | 17 ++-- .../discordplugin/DiscordPlugin.java | 14 ++- .../discordplugin/commands/Command2DC.java | 4 +- .../discordplugin/commands/DebugCommand.java | 3 +- .../exceptions/ExceptionListenerModule.java | 92 ++++++++++--------- .../discordplugin/fun/FunModule.java | 14 +-- .../discordplugin/mcchat/MCListener.java | 14 ++- 7 files changed, 88 insertions(+), 70 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 069e675..6630839 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -46,7 +46,7 @@ public final class DPUtils { return sanitizedString.toString(); } - public static String escape(String message) { + private static String escape(String message) { return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\") + "$1"); } @@ -69,15 +69,18 @@ public final class DPUtils { }, ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer) } - public static ConfigData roleData(IHaveConfig config, String key, String defName) { - return roleData(config, key, defName, DiscordPlugin.mainServer); + public static ConfigData> roleData(IHaveConfig config, String key, String defName) { + return roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer)); } - public static ConfigData roleData(IHaveConfig config, String key, String defName, Guild guild) { + /** + * Needs to be a {@link ConfigData} for checking if it's set + */ + public static ConfigData> roleData(IHaveConfig config, String key, String defName, Mono guild) { return config.getDataPrimDef(key, defName, name -> { - if (!(name instanceof String)) return null; - return guild.getRoles().filter(r -> r.getName().equals(name)).blockFirst(); - }, r -> r.getId().asLong()); + if (!(name instanceof String)) return Mono.empty(); + return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).last(); + }, r -> defName); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 307f8b9..4f7befb 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -16,6 +16,7 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.IHaveConfig; import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; import discord4j.core.DiscordClient; @@ -36,16 +37,17 @@ import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.RegisteredServiceProvider; +import reactor.core.publisher.Mono; import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +@ButtonPlugin.ConfigOpts(disableConfigGen = true) public class DiscordPlugin extends ButtonPlugin { public static DiscordClient dc; public static DiscordPlugin plugin; @@ -53,7 +55,7 @@ public class DiscordPlugin extends ButtonPlugin { @Getter private Command2DC manager; - public ConfigData Prefix() { + private ConfigData Prefix() { return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); } @@ -62,7 +64,7 @@ public class DiscordPlugin extends ButtonPlugin { return plugin.Prefix().get(); } - public ConfigData MainServer() { + private ConfigData MainServer() { return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); } @@ -70,7 +72,7 @@ public class DiscordPlugin extends ButtonPlugin { return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); } - public ConfigData ModRole() { + public ConfigData> ModRole() { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); } @@ -193,6 +195,8 @@ public class DiscordPlugin extends ButtonPlugin { ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase ? ((DiscordSenderBase) sender).getChromaUser() : null)); setupProviders(); + + IHaveConfig.pregenConfig(this, null); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); } @@ -220,7 +224,7 @@ public class DiscordPlugin extends ButtonPlugin { + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") + "kicked the hell out.") //TODO: Make configurable : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled - }).block(Duration.ofSeconds(5)), ChannelconBroadcast.RESTART, false); + }).block(), ChannelconBroadcast.RESTART, false); ChromaBot.getInstance().updatePlayerList(); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index a0b8fda..4f5d0ec 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -3,6 +3,8 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.chat.Command2; +import java.lang.reflect.Method; + public class Command2DC extends Command2 { @Override public void registerCommand(ICommand2DC command) { @@ -10,7 +12,7 @@ public class Command2DC extends Command2 { } @Override - public boolean hasPermission(Command2DCSender sender, ICommand2DC command) { + public boolean hasPermission(Command2DCSender sender, ICommand2DC command, Method method) { //return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); //TODO: ModRole may be null; more customisable way? return true; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index e75a163..96d00b3 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -12,7 +12,8 @@ public class DebugCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String args) { sender.getMessage().getAuthorAsMember() - .map(m -> m.getRoleIds().stream().anyMatch(r -> r.equals(DiscordPlugin.plugin.ModRole().get().getId()))) + .flatMap(m -> DiscordPlugin.plugin.ModRole().get() + .map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId())))) .subscribe(success -> { if (success) sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 098ade3..a4d4848 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -15,6 +15,7 @@ import org.apache.commons.lang.exception.ExceptionUtils; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.Arrays; @@ -22,51 +23,58 @@ import java.util.List; import java.util.stream.Collectors; public class ExceptionListenerModule extends Component implements Listener { - private List lastthrown = new ArrayList<>(); - private List lastsourcemsg = new ArrayList<>(); + private List lastthrown = new ArrayList<>(); + private List lastsourcemsg = new ArrayList<>(); - @EventHandler - public void onException(TBMCExceptionEvent e) { - if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(getClass())) - return; - if (lastthrown.stream() - .anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace()) - && (e.getException().getMessage() == null ? ex.getMessage() == null - : e.getException().getMessage().equals(ex.getMessage()))) // e.Exception.Message==ex.Message - && lastsourcemsg.contains(e.getSourceMessage())) - return; - SendException(e.getException(), e.getSourceMessage()); - if (lastthrown.size() >= 10) - lastthrown.remove(0); - if (lastsourcemsg.size() >= 10) - lastsourcemsg.remove(0); - lastthrown.add(e.getException()); - lastsourcemsg.add(e.getSourceMessage()); - e.setHandled(); - } + @EventHandler + public void onException(TBMCExceptionEvent e) { + if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(getClass())) + return; + if (lastthrown.stream() + .anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace()) + && (e.getException().getMessage() == null ? ex.getMessage() == null + : e.getException().getMessage().equals(ex.getMessage()))) // e.Exception.Message==ex.Message + && lastsourcemsg.contains(e.getSourceMessage())) + return; + SendException(e.getException(), e.getSourceMessage()); + if (lastthrown.size() >= 10) + lastthrown.remove(0); + if (lastsourcemsg.size() >= 10) + lastsourcemsg.remove(0); + lastthrown.add(e.getException()); + lastsourcemsg.add(e.getSourceMessage()); + e.setHandled(); + } - private static void SendException(Throwable e, String sourcemessage) { + private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; - try { + try { MessageChannel channel = getChannel(); - assert channel != null; - Role coderRole = instance.pingRole(((GuildChannel) channel).getGuild().block()).get(); - StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() - : new StringBuilder(coderRole == null ? "" : coderRole.getMention()).append("\n"); - sb.append(sourcemessage).append("\n"); - sb.append("```").append("\n"); - String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) - .filter(s -> !s.contains("\tat ") || s.contains("\tat buttondevteam.")) - .collect(Collectors.joining("\n")); - if (sb.length() + stackTrace.length() >= 2000) - stackTrace = stackTrace.substring(0, 1999 - sb.length()); - sb.append(stackTrace).append("\n"); - sb.append("```"); - channel.createMessage(sb.toString()).subscribe(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } + assert channel != null; + Mono coderRole; + if (channel instanceof GuildChannel) + coderRole = instance.pingRole(((GuildChannel) channel).getGuild()).get(); + else + coderRole = Mono.empty(); + coderRole.map(role -> TBMCCoreAPI.IsTestServer() ? new StringBuilder() + : new StringBuilder(role.getMention()).append("\n")) + .defaultIfEmpty(new StringBuilder()) + .flatMap(sb -> { + sb.append(sourcemessage).append("\n"); + sb.append("```").append("\n"); + String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) + .filter(s -> !s.contains("\tat ") || s.contains("\tat buttondevteam.")) + .collect(Collectors.joining("\n")); + if (sb.length() + stackTrace.length() >= 2000) + stackTrace = stackTrace.substring(0, 1999 - sb.length()); + sb.append(stackTrace).append("\n"); + sb.append("```"); + return channel.createMessage(sb.toString()); + }).subscribe(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } private static ExceptionListenerModule instance; @@ -79,7 +87,7 @@ public class ExceptionListenerModule extends Component implements return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } - private ConfigData pingRole(Guild guild) { + private ConfigData> pingRole(Mono guild) { return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild); } diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 0ccc4b9..ac9e423 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -15,6 +15,7 @@ import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; +import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.Arrays; @@ -114,7 +115,7 @@ public class FunModule extends Component implements Listener { ListC = 0; } - private ConfigData fullHouseDevRole(Guild guild) { + private ConfigData> fullHouseDevRole(Mono guild) { return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); } @@ -131,20 +132,21 @@ public class FunModule extends Component implements Listener { if (fm == null) return; val channel = fm.fullHouseChannel().get(); if (channel == null) return; - val devrole = fm.fullHouseDevRole(((GuildChannel) channel).getGuild().block()).get(); + if (!(channel instanceof GuildChannel)) return; + val devrole = fm.fullHouseDevRole(((GuildChannel) channel).getGuild()).get(); if (devrole == null) return; if (event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false) && !event.getCurrent().getStatus().equals(Status.OFFLINE) - && event.getMember().flatMap(m -> m.getRoles() - .any(r -> r.getId().asLong() == devrole.getId().asLong())).block() - && event.getGuild().flatMap(g -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(devrole.getId()))) + && event.getMember().flatMap(m -> devrole.flatMap(dr -> m.getRoles() + .any(r -> r.getId().asLong() == dr.getId().asLong()))).block() + && event.getGuild().flatMap(g -> devrole.flatMapMany(dr -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(dr.getId())))) .flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE))).block() && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs -> ecs.setImage( "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - )); + )).subscribe(); lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index d4b6891..5d64aeb 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -1,13 +1,11 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.*; -import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.player.*; import com.earth2me.essentials.CommandSource; import discord4j.core.object.entity.Role; -import discord4j.core.object.entity.User; import discord4j.core.object.util.Snowflake; import lombok.RequiredArgsConstructor; import lombok.val; @@ -101,13 +99,13 @@ class MCListener implements Listener { MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); } - private ConfigData muteRole() { + private ConfigData> muteRole() { return DPUtils.roleData(module.getConfig(), "muteRole", "Muted"); } @EventHandler public void onPlayerMute(MuteStatusChangeEvent e) { - final Role role = muteRole().get(); + final Mono role = muteRole().get(); if (role == null) return; final CommandSource source = e.getAffected().getSource(); if (!source.isPlayer()) @@ -117,18 +115,18 @@ class MCListener implements Listener { if (p == null) return; DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID())) .flatMap(user -> user.asMember(DiscordPlugin.mainServer.getId())) - .flatMap(user -> { + .flatMap(user -> role.flatMap(r -> { if (e.getValue()) - user.addRole(role.getId()); + user.addRole(r.getId()); else - user.removeRole(role.getId()); + user.removeRole(r.getId()); val modlog = module.modlogChannel().get(); String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getUsername() + "#" + user.getDiscriminator(); DPUtils.getLogger().info(msg); if (modlog != null) return modlog.createMessage(msg); return Mono.empty(); - }).subscribe(); + })).subscribe(); } @EventHandler From b68456e6f44d669de1c740b44ed4621d45b9db2f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 4 May 2019 03:11:03 +0200 Subject: [PATCH 12/24] Even more fixes Actually made the channel data return a Mono and used that Used the read only config stuff #93 --- .../buttondevteam/discordplugin/DPUtils.java | 54 +++++++++++-------- .../discordplugin/DiscordPlugin.java | 13 +++-- .../announcer/AnnouncerModule.java | 19 ++++--- .../exceptions/ExceptionListenerModule.java | 11 ++-- .../discordplugin/fun/FunModule.java | 42 +++++++-------- .../listeners/CommandListener.java | 2 +- .../listeners/CommonListeners.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 13 ++--- .../mcchat/MinecraftChatModule.java | 12 +++-- 9 files changed, 98 insertions(+), 70 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 6630839..45a8e53 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -4,7 +4,11 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; -import discord4j.core.object.entity.*; +import buttondevteam.lib.architecture.ReadOnlyConfigData; +import discord4j.core.object.entity.Guild; +import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.Role; import discord4j.core.object.util.Snowflake; import discord4j.core.spec.EmbedCreateSpec; import lombok.val; @@ -56,43 +60,36 @@ public final class DPUtils { return DiscordPlugin.plugin.getLogger(); } - public static ConfigData channelData(IHaveConfig config, String key, long defID) { - return config.getDataPrimDef(key, defID, id -> { - Channel ch = DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).onErrorResume(e -> { - getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage()); - return Mono.empty(); - }).block(); - if (ch instanceof MessageChannel) - return (MessageChannel) ch; - else - return null; - }, ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer) + public static ReadOnlyConfigData> channelData(IHaveConfig config, String key, long defID) { + return config.getReadOnlyDataPrimDef(key, defID, id -> getMessageChannel(key, Snowflake.of((Long) id)), ch -> defID); //We can afford to search for the channel in the cache once (instead of using mainServer) } - public static ConfigData> roleData(IHaveConfig config, String key, String defName) { + public static ReadOnlyConfigData> roleData(IHaveConfig config, String key, String defName) { return roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer)); } /** * Needs to be a {@link ConfigData} for checking if it's set */ - public static ConfigData> roleData(IHaveConfig config, String key, String defName, Mono guild) { - return config.getDataPrimDef(key, defName, name -> { + public static ReadOnlyConfigData> roleData(IHaveConfig config, String key, String defName, Mono guild) { + return config.getReadOnlyDataPrimDef(key, defName, name -> { if (!(name instanceof String)) return Mono.empty(); return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).last(); }, r -> defName); } + public static ConfigData snowflakeData(IHaveConfig config, String key, long defID) { + return config.getDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong); + } + /** * Mentions the bot channel. Useful for help texts. * * @return The string for mentioning the channel */ public static String botmention() { - Channel channel; - if (DiscordPlugin.plugin == null - || (channel = DiscordPlugin.plugin.CommandChannel().get()) == null) return "#bot"; - return channel.getMention(); + if (DiscordPlugin.plugin == null) return "#bot"; + return channelMention(DiscordPlugin.plugin.CommandChannel().get()); } /** @@ -104,14 +101,14 @@ public final class DPUtils { */ public static boolean disableIfConfigError(@Nullable Component component, ConfigData... configs) { for (val config : configs) { - if (config.get() == null) { + Object v = config.get(); + //noinspection ConstantConditions + if (v == null || (v instanceof Mono && !((Mono) v).hasElement().block())) { String path = null; try { if (component != null) Component.setComponentEnabled(component, false); - val f = ConfigData.class.getDeclaredField("path"); - f.setAccessible(true); //Hacking my own plugin - path = (String) f.get(config); + path = config.getPath(); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to disable component after config error!", e); } @@ -137,4 +134,15 @@ public final class DPUtils { return "<@!" + userId.asString() + ">"; } + public static String channelMention(Snowflake channelId) { + return "<#" + channelId.asString() + ">"; + } + + public static Mono getMessageChannel(String key, Snowflake id) { + return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> { + getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage()); + return Mono.empty(); + }).filter(ch -> ch instanceof MessageChannel).cast(MessageChannel.class); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 4f7befb..75e22d7 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -24,7 +24,6 @@ import discord4j.core.DiscordClientBuilder; import discord4j.core.event.domain.guild.GuildCreateEvent; import discord4j.core.event.domain.lifecycle.ReadyEvent; import discord4j.core.object.entity.Guild; -import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.Role; import discord4j.core.object.presence.Activity; import discord4j.core.object.presence.Presence; @@ -68,8 +67,8 @@ public class DiscordPlugin extends ButtonPlugin { return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); } - public ConfigData CommandChannel() { - return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); + public ConfigData CommandChannel() { + return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L); } public ConfigData> ModRole() { @@ -210,7 +209,9 @@ public class DiscordPlugin extends ButtonPlugin { @Override public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load + System.out.println("Disable start"); MCChatUtils.forCustomAndAllMCChat(ch -> ch.createEmbed(ecs -> { + System.out.println("Sending message to " + ch.getMention()); if (DiscordMCCommand.resetting) ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting"); else @@ -225,12 +226,16 @@ public class DiscordPlugin extends ButtonPlugin { + "kicked the hell out.") //TODO: Make configurable : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled }).block(), ChannelconBroadcast.RESTART, false); + System.out.println("Updating player list"); ChromaBot.getInstance().updatePlayerList(); + System.out.println("Done"); } @Override public void pluginDisable() { + System.out.println("Actual disable start (logout)"); MCChatPrivate.logoutAll(); + System.out.println("Config setup"); getConfig().set("serverup", false); if (ChromaBot.getInstance() == null) return; //Failed to load @@ -238,7 +243,9 @@ public class DiscordPlugin extends ButtonPlugin { try { SafeMode = true; // Stop interacting with Discord ChromaBot.delete(); + System.out.println("Updating presence..."); dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing + System.out.println("Logging out..."); dc.logout().block(); //Configs are emptied so channels and servers are fetched again } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index 690a085..afde743 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -6,6 +6,7 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.ReadOnlyConfigData; import buttondevteam.lib.player.ChromaGamerBase; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -16,19 +17,22 @@ import discord4j.core.object.entity.MessageChannel; import lombok.val; import org.bukkit.configuration.file.YamlConfiguration; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import java.io.File; -import java.util.Objects; public class AnnouncerModule extends Component { /** * Channel to post new posts. */ - public ConfigData channel() { + public ReadOnlyConfigData> channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } - public ConfigData modChannel() { + /** + * Channel where distinguished (moderator) posts go. + */ + public ReadOnlyConfigData> modChannel() { return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L); } @@ -56,8 +60,7 @@ public class AnnouncerModule extends Component { stop = false; //If not the first time val keepPinned = keepPinned().get(); if (keepPinned == 0) return; - val channel = channel().get(); - Flux msgs = channel.getPinnedMessages(); + Flux msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages); msgs.subscribe(Message::unpin); val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change if (lastannouncementtime().get() == 0) //Load old data @@ -118,9 +121,11 @@ public class AnnouncerModule extends Component { } } if (msgsb.length() > 0) - Objects.requireNonNull(channel().get().createMessage(msgsb.toString()).block()).pin().block(); + channel().get().flatMap(ch -> ch.createMessage(msgsb.toString())) + .flatMap(Message::pin).subscribe(); if (modmsgsb.length() > 0) - modChannel().get().createMessage(modmsgsb.toString()).block(); + modChannel().get().flatMap(ch -> ch.createMessage(modmsgsb.toString())) + .flatMap(Message::pin).subscribe(); if (lastannouncementtime().get() != lastanntime) lastannouncementtime().set(lastanntime); // If sending succeeded } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index a4d4848..45ac2c7 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -7,6 +7,7 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCExceptionEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.ReadOnlyConfigData; import discord4j.core.object.entity.Guild; import discord4j.core.object.entity.GuildChannel; import discord4j.core.object.entity.MessageChannel; @@ -49,7 +50,7 @@ public class ExceptionListenerModule extends Component implements private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; try { - MessageChannel channel = getChannel(); + Mono channel = getChannel(); assert channel != null; Mono coderRole; if (channel instanceof GuildChannel) @@ -69,7 +70,7 @@ public class ExceptionListenerModule extends Component implements stackTrace = stackTrace.substring(0, 1999 - sb.length()); sb.append(stackTrace).append("\n"); sb.append("```"); - return channel.createMessage(sb.toString()); + return channel.flatMap(ch -> ch.createMessage(sb.toString())); }).subscribe(); } catch (Exception ex) { ex.printStackTrace(); @@ -78,12 +79,12 @@ public class ExceptionListenerModule extends Component implements private static ExceptionListenerModule instance; - public static MessageChannel getChannel() { + public static Mono getChannel() { if (instance != null) return instance.channel().get(); - return null; + return Mono.empty(); } - private ConfigData channel() { + private ReadOnlyConfigData> channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index ac9e423..9866334 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -6,6 +6,7 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.ReadOnlyConfigData; import com.google.common.collect.Lists; import discord4j.core.event.domain.PresenceUpdateEvent; import discord4j.core.object.entity.*; @@ -120,34 +121,33 @@ public class FunModule extends Component implements Listener { } - private ConfigData fullHouseChannel() { + private ReadOnlyConfigData> fullHouseChannel() { return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L); } private static long lasttime = 0; - @SuppressWarnings("ConstantConditions") public static void handleFullHouse(PresenceUpdateEvent event) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return; - val channel = fm.fullHouseChannel().get(); - if (channel == null) return; - if (!(channel instanceof GuildChannel)) return; - val devrole = fm.fullHouseDevRole(((GuildChannel) channel).getGuild()).get(); - if (devrole == null) return; - if (event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false) - && !event.getCurrent().getStatus().equals(Status.OFFLINE) - && event.getMember().flatMap(m -> devrole.flatMap(dr -> m.getRoles() - .any(r -> r.getId().asLong() == dr.getId().asLong()))).block() - && event.getGuild().flatMap(g -> devrole.flatMapMany(dr -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(dr.getId())))) - .flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE))).block() - && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) - && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs -> - ecs.setImage( - "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - )).subscribe(); - lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); - } + if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 != 0) return; + fm.fullHouseChannel().get() + .filter(ch -> ch instanceof GuildChannel) + .flatMap(channel -> fm.fullHouseDevRole(((GuildChannel) channel).getGuild()).get() + .filter(role -> event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false)) + .filter(role -> !event.getCurrent().getStatus().equals(Status.OFFLINE)) + .filterWhen(devrole -> event.getMember().flatMap(m -> m.getRoles() + .any(r -> r.getId().asLong() == devrole.getId().asLong()))) + .filterWhen(devrole -> + event.getGuild().flatMapMany(g -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(devrole.getId())))) + .flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE))) + .filter(devrole -> lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())) //This should stay so it checks this last + .flatMap(devrole -> { + lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); + return channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs -> + ecs.setImage( + "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") + )); + })).subscribe(); } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index aff8339..ccd36f3 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -27,7 +27,7 @@ public class CommandListener { if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!(channel instanceof PrivateChannel) && !(content.charAt(0) == DiscordPlugin.getPrefix() - && channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().getId().asString()))) // + && channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().asString()))) // return false; channel.type().subscribe(); // Fun } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 6c55615..0f7ee85 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -40,7 +40,7 @@ public class CommonListeners { try { boolean handled = false; val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); - if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.getId().asLong()) //If mentioned, that's higher than chat + if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here if (handled) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index f013c1b..f843450 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -17,6 +17,7 @@ import com.vdurmont.emoji.EmojiParser; import discord4j.core.event.domain.message.MessageCreateEvent; import discord4j.core.object.Embed; import discord4j.core.object.entity.*; +import discord4j.core.object.util.Snowflake; import discord4j.core.spec.EmbedCreateSpec; import lombok.val; import org.bukkit.Bukkit; @@ -110,17 +111,17 @@ public class MCChatListener implements Listener { }; // Checks if the given channel is different than where the message was sent from // Or if it was from MC - Predicate isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) - || ((DiscordSenderBase) e.getSender()).getChannel().getId().asLong() != ch.getId().asLong(); + Predicate isdifferentchannel = id -> !(e.getSender() instanceof DiscordSenderBase) + || ((DiscordSenderBase) e.getSender()).getChannel().getId().asLong() != id.asLong(); if (e.getChannel().isGlobal() && (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get()))) doit.accept(MCChatUtils.lastmsgdata == null - ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null) + ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono().block(), null) : MCChatUtils.lastmsgdata); for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { - if ((e.isFromCommand() || isdifferentchannel.test(data.channel)) + if ((e.isFromCommand() || isdifferentchannel.test(data.channel.getId())) && e.shouldSendTo(MCChatUtils.getSender(data.channel.getId(), data.user))) doit.accept(data); } @@ -128,7 +129,7 @@ public class MCChatListener implements Listener { val iterator = MCChatCustom.lastmsgCustom.iterator(); while (iterator.hasNext()) { val lmd = iterator.next(); - if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord + if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel.getId())) //Test if msg is from Discord && e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it && e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58 if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions @@ -222,7 +223,7 @@ public class MCChatListener implements Listener { val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); val channel = ev.getMessage().getChannel().block(); - if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().getId().asLong() + if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() && !(channel instanceof PrivateChannel && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) && !hasCustomChat)) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index d7f1860..b4f8ec6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -8,12 +8,14 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.ReadOnlyConfigData; import com.google.common.collect.Lists; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.util.Snowflake; import lombok.Getter; import lombok.val; import org.bukkit.Bukkit; +import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.Objects; @@ -42,14 +44,18 @@ public class MinecraftChatModule extends Component { /** * The channel to use as the public Minecraft chat - everything public gets broadcasted here */ - public ConfigData chatChannel() { - return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L); + public ConfigData chatChannel() { + return DPUtils.snowflakeData(getConfig(), "chatChannel", 239519012529111040L); + } + + public Mono chatChannelMono() { + return DPUtils.getMessageChannel(chatChannel().getPath(), chatChannel().get()); } /** * The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute */ - public ConfigData modlogChannel() { + public ReadOnlyConfigData> modlogChannel() { return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L); } From f266924a9a1495f72412082def8f2fb07aeb5915 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 6 May 2019 15:47:01 +0200 Subject: [PATCH 13/24] More reacts --- .../discordplugin/ChromaBot.java | 4 +-- .../buttondevteam/discordplugin/DPUtils.java | 4 +++ .../exceptions/DebugMessageListener.java | 5 +-- .../discordplugin/mcchat/MCChatUtils.java | 33 ++++++++++--------- .../discordplugin/mcchat/MCListener.java | 6 ++-- .../discordplugin/role/GameRoleModule.java | 15 +++++---- 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index 81a43d1..6f74671 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -38,7 +38,7 @@ public class ChromaBot { * @param message * The message to send, duh (use {@link MessageChannel#createMessage(String)}) */ - public void sendMessage(Function> message) { + public void sendMessage(Function, Mono> message) { MCChatUtils.forAllMCChat(ch -> message.apply(ch).subscribe()); } @@ -48,7 +48,7 @@ public class ChromaBot { * @param message The message to send, duh * @param toggle The toggle type for channelcon */ - public void sendMessageCustomAsWell(Function> message, @Nullable ChannelconBroadcast toggle) { + public void sendMessageCustomAsWell(Function, Mono> message, @Nullable ChannelconBroadcast toggle) { MCChatUtils.forCustomAndAllMCChat(ch -> message.apply(ch).subscribe(), toggle, false); } diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 45a8e53..9aa6dd5 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -145,4 +145,8 @@ public final class DPUtils { }).filter(ch -> ch instanceof MessageChannel).cast(MessageChannel.class); } + public static Mono getMessageChannel(ConfigData config) { + return getMessageChannel(config.getPath(), config.get()); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java index 12606af..0f05934 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java @@ -6,6 +6,7 @@ import buttondevteam.lib.TBMCDebugMessageEvent; import discord4j.core.object.entity.MessageChannel; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import reactor.core.publisher.Mono; public class DebugMessageListener implements Listener { @EventHandler @@ -18,7 +19,7 @@ public class DebugMessageListener implements Listener { if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(ExceptionListenerModule.class)) return; try { - MessageChannel mc = ExceptionListenerModule.getChannel(); + Mono mc = ExceptionListenerModule.getChannel(); if (mc == null) return; StringBuilder sb = new StringBuilder(); sb.append("```").append("\n"); @@ -26,7 +27,7 @@ public class DebugMessageListener implements Listener { message = message.substring(0, 2000); sb.append(message).append("\n"); sb.append("```"); - mc.createMessage(sb.toString()).subscribe(); + mc.flatMap(ch -> ch.createMessage(sb.toString())).subscribe(); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 6cb58ee..64740c4 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -18,6 +18,7 @@ import org.bukkit.event.HandlerList; import org.bukkit.plugin.AuthorNagException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; +import reactor.core.publisher.Mono; import javax.annotation.Nullable; import java.util.Arrays; @@ -110,11 +111,11 @@ public class MCChatUtils { return null; } - public static void forAllMCChat(Consumer action) { + public static void forAllMCChat(Consumer> action) { if (notEnabled()) return; - action.accept(module.chatChannel().get()); + action.accept(module.chatChannelMono()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) - action.accept(data.channel); + action.accept(Mono.just(data.channel)); // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat } @@ -125,11 +126,11 @@ public class MCChatUtils { * @param toggle The toggle to check * @param hookmsg Whether the message is also sent from the hook */ - public static void forCustomAndAllMCChat(Consumer action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + public static void forCustomAndAllMCChat(Consumer> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (notEnabled()) return; if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); - final Consumer customLMDConsumer = cc -> action.accept(cc.channel); + final Consumer customLMDConsumer = cc -> action.accept(Mono.just(cc.channel)); if (toggle == null) MCChatCustom.lastmsgCustom.forEach(customLMDConsumer); else @@ -143,7 +144,7 @@ public class MCChatUtils { * @param sender The sender to check perms of or null to send to all that has it toggled * @param toggle The toggle to check or null to send to all allowed */ - public static void forAllowedCustomMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { + public static void forAllowedCustomMCChat(Consumer> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { if (notEnabled()) return; MCChatCustom.lastmsgCustom.stream().filter(clmd -> { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple @@ -152,7 +153,7 @@ public class MCChatUtils { if (sender == null) return true; return clmd.groupID.equals(clmd.mcchannel.getGroupID(sender)); - }).forEach(cc -> action.accept(cc.channel)); //TODO: Send error messages on channel connect + }).forEach(cc -> action.accept(Mono.just(cc.channel))); //TODO: Send error messages on channel connect } /** @@ -163,29 +164,29 @@ public class MCChatUtils { * @param toggle The toggle to check or null to send to all allowed * @param hookmsg Whether the message is also sent from the hook */ - public static void forAllowedCustomAndAllMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + public static void forAllowedCustomAndAllMCChat(Consumer> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (notEnabled()) return; if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); forAllowedCustomMCChat(action, sender, toggle); } - public static Consumer send(String message) { - return ch -> ch.createMessage(DPUtils.sanitizeString(message)).subscribe(); + public static Consumer> send(String message) { + return ch -> ch.flatMap(mc -> mc.createMessage(DPUtils.sanitizeString(message))).subscribe(); } - public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { + public static void forAllowedMCChat(Consumer> action, TBMCSystemChatEvent event) { if (notEnabled()) return; if (event.getChannel().isGlobal()) - action.accept(module.chatChannel().get()); + action.accept(module.chatChannelMono()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) if (event.shouldSendTo(getSender(data.channel.getId(), data.user))) - action.accept(data.channel); + action.accept(Mono.just(data.channel)); //TODO: Only store ID? MCChatCustom.lastmsgCustom.stream().filter(clmd -> { if (!clmd.brtoggles.contains(event.getTarget())) return false; return event.shouldSendTo(clmd.dcp); - }).map(clmd -> clmd.channel).forEach(action); + }).map(clmd -> Mono.just(clmd.channel)).forEach(action); } /** @@ -209,8 +210,8 @@ public class MCChatUtils { */ public static void resetLastMessage(Channel channel) { if (notEnabled()) return; - if (channel.getId().asLong() == module.chatChannel().get().getId().asLong()) { - (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannel().get(), null) + if (channel.getId().asLong() == module.chatChannel().get().asLong()) { + (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannelMono().block(), null) : lastmsgdata).message = null; return; } // Don't set the whole object to null, the player and channel information should be preserved diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 5d64aeb..44f1f96 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -51,9 +51,9 @@ class MCListener implements Listener { if (dp != null) { val user = DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).block(); MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, Objects.requireNonNull(user).getPrivateChannel().block(), p)); + new DiscordPlayerSender(user, Objects.requireNonNull(user).getPrivateChannel().block(), p)); //TODO: Don't block MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, module.chatChannel().get(), p)); //Stored per-channel + new DiscordPlayerSender(user, module.chatChannelMono().block(), p)); //Stored per-channel } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); @@ -124,7 +124,7 @@ class MCListener implements Listener { String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getUsername() + "#" + user.getDiscriminator(); DPUtils.getLogger().info(msg); if (modlog != null) - return modlog.createMessage(msg); + return modlog.flatMap(ch -> ch.createMessage(msg)); return Mono.empty(); })).subscribe(); } diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 59496aa..8a0fdcf 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -4,7 +4,7 @@ import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.ReadOnlyConfigData; import discord4j.core.event.domain.role.RoleCreateEvent; import discord4j.core.event.domain.role.RoleDeleteEvent; import discord4j.core.event.domain.role.RoleEvent; @@ -13,6 +13,7 @@ import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.Role; import lombok.val; import org.bukkit.Bukkit; +import reactor.core.publisher.Mono; import java.awt.*; import java.util.Collections; @@ -33,7 +34,7 @@ public class GameRoleModule extends Component { } - private ConfigData logChannel() { + private ReadOnlyConfigData> logChannel() { return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L); } @@ -49,13 +50,13 @@ public class GameRoleModule extends Component { return; //Deleted or not a game role GameRoles.add(role.getName()); if (logChannel != null) - logChannel.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default.").subscribe(); + logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default.")).subscribe(); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { Role role=((RoleDeleteEvent) roleEvent).getRole().orElse(null); if(role==null) return; if (GameRoles.remove(role.getName()) && logChannel != null) - logChannel.createMessage("Removed " + role.getName() + " as a game role.").subscribe(); + logChannel.flatMap(ch -> ch.createMessage("Removed " + role.getName() + " as a game role.")).subscribe(); } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; if(!event.getOld().isPresent()) { @@ -65,7 +66,7 @@ public class GameRoleModule extends Component { Role or=event.getOld().get(); if (!grm.isGameRole(event.getCurrent())) { if (GameRoles.remove(or.getName()) && logChannel != null) - logChannel.createMessage("Removed " + or.getName() + " as a game role because it's color changed.").subscribe(); + logChannel.flatMap(ch -> ch.createMessage("Removed " + or.getName() + " as a game role because it's color changed.")).subscribe(); } else { if (GameRoles.contains(or.getName()) && or.getName().equals(event.getCurrent().getName())) return; @@ -73,9 +74,9 @@ public class GameRoleModule extends Component { GameRoles.add(event.getCurrent().getName()); //Add it because it has no color if (logChannel != null) { if (removed) - logChannel.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + ".").subscribe(); + logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + ".")).subscribe(); else - logChannel.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color.").subscribe(); + logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color.")).subscribe(); } } } From beab4008737fe5bcc58e43c890d61ddd77371828 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 10 May 2019 21:39:25 +0200 Subject: [PATCH 14/24] Some debugging, some fixes #93 --- pom.xml | 10 ++++++++++ .../buttondevteam/discordplugin/DPUtils.java | 2 +- .../discordplugin/DiscordPlugin.java | 20 +++++++++---------- .../listeners/CommandListener.java | 10 ++++++++++ .../listeners/CommonListeners.java | 11 ++++++++++ .../discordplugin/mcchat/MCChatListener.java | 14 +++++++++++++ 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index fc313cc..9e2d7cf 100755 --- a/pom.xml +++ b/pom.xml @@ -149,6 +149,10 @@ pex-repo http://pex-repo.aoeu.xyz --> + @@ -231,6 +235,12 @@ emoji-java 4.0.0 + + diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 9aa6dd5..6c3927c 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -74,7 +74,7 @@ public final class DPUtils { public static ReadOnlyConfigData> roleData(IHaveConfig config, String key, String defName, Mono guild) { return config.getReadOnlyDataPrimDef(key, defName, name -> { if (!(name instanceof String)) return Mono.empty(); - return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).last(); + return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).next(); }, r -> defName); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 75e22d7..a56e4f5 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -160,18 +160,18 @@ public class DiscordPlugin extends ButtonPlugin { getManager().registerCommand(new DebugCommand()); getManager().registerCommand(new ConnectCommand()); if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled - ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.CYAN) - .setTitle("Discord plugin restarted - chat connected.")), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm + ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.CYAN) + .setTitle("Discord plugin restarted - chat connected."))), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.YELLOW) - .setTitle("Server recovered from a crash - chat connected.")), ChannelconBroadcast.RESTART); + ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.YELLOW) + .setTitle("Server recovered from a crash - chat connected."))), ChannelconBroadcast.RESTART); val thr = new Throwable( "The server shut down unexpectedly. See the log of the previous run for more details."); thr.setStackTrace(new StackTraceElement[0]); TBMCCoreAPI.SendException("The server crashed!", thr); } else - ChromaBot.getInstance().sendMessageCustomAsWell(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) - .setTitle("Server started - chat connected.")), ChannelconBroadcast.RESTART); + ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) + .setTitle("Server started - chat connected."))), ChannelconBroadcast.RESTART); DiscordMCCommand.resetting = false; //This is the last event handling this flag @@ -181,7 +181,7 @@ public class DiscordPlugin extends ButtonPlugin { TBMCCoreAPI.SendException( "Won't load because we're in testing mode and not using a separate account.", new Exception( - "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in it's name.)")); + "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in its name.)")); Bukkit.getPluginManager().disablePlugin(this); } TBMCCoreAPI.SendUnsentExceptions(); @@ -197,7 +197,7 @@ public class DiscordPlugin extends ButtonPlugin { IHaveConfig.pregenConfig(this, null); } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); + TBMCCoreAPI.SendException("An error occurred while enabling DiscordPlugin!", e); } } @@ -210,7 +210,7 @@ public class DiscordPlugin extends ButtonPlugin { public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load System.out.println("Disable start"); - MCChatUtils.forCustomAndAllMCChat(ch -> ch.createEmbed(ecs -> { + MCChatUtils.forCustomAndAllMCChat(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> { System.out.println("Sending message to " + ch.getMention()); if (DiscordMCCommand.resetting) ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting"); @@ -225,7 +225,7 @@ public class DiscordPlugin extends ButtonPlugin { + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") + "kicked the hell out.") //TODO: Make configurable : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled - }).block(), ChannelconBroadcast.RESTART, false); + })).subscribe(), ChannelconBroadcast.RESTART, false); System.out.println("Updating player list"); ChromaBot.getInstance().updatePlayerList(); System.out.println("Done"); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index ccd36f3..744e189 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -21,7 +21,9 @@ public class CommandListener { public static boolean runCommand(Message message, boolean mentionedonly) { if (!message.getContent().isPresent()) return false; //Pin messages and such, let the mcchat listener deal with it + System.out.println("1"); final MessageChannel channel = message.getChannel().block(); + System.out.println("2"); val content = message.getContent().get(); if (channel == null) return false; if (!mentionedonly) { //mentionedonly conditions are in CommonListeners @@ -31,28 +33,36 @@ public class CommandListener { return false; channel.type().subscribe(); // Fun } + System.out.println("3"); final StringBuilder cmdwithargs = new StringBuilder(content); val self = DiscordPlugin.dc.getSelf().block(); + System.out.println("4"); if (self == null) return false; val member = self.asMember(DiscordPlugin.mainServer.getId()).block(); + System.out.println("5"); if (member == null) return false; final String mention = self.getMention(); final String mentionNick = member.getNicknameMention(); + System.out.println("6"); boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention; + System.out.println("7"); val mentions = message.getRoleMentions(); for (String mentionRole : member.getRoles().filter(r -> mentions.any(rr -> rr.getName().equals(r.getName())).blockOptional().orElse(false)).map(Role::getMention).toIterable()) gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions if (mentionedonly && !gotmention) return false; + System.out.println("8"); channel.type().subscribe(); String cmdwithargsString = cmdwithargs.toString(); + System.out.println("9"); try { if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString).subscribe(); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); } + System.out.println("10"); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 0f7ee85..2d1c546 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -35,25 +35,36 @@ public class CommonListeners { return; //System.out.println("Author: "+author.get()); //System.out.println("Bot: "+author.get().isBot()); + System.out.println("A"); if (FunModule.executeMemes(event.getMessage())) return; + System.out.println("B"); try { boolean handled = false; val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); + System.out.println("C"); if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here + System.out.println("D"); if (handled) return; //System.out.println("Message handling"); val mcchat = Component.getComponents().get(MinecraftChatModule.class); if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels + System.out.println("E"); if (!handled) handled = CommandListener.runCommand(event.getMessage(), false); + System.out.println("F"); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while handling a message!", e); } }); + /*dispatcher.on(MessageCreateEvent.class).doOnNext(x -> System.out.println("Got message")) + .flatMap(MessageCreateEvent::getGuild) + .flatMap(guild -> DiscordPlugin.dc.getSelf()) + .flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) + .flatMap(Member::getRoles).subscribe(roles -> System.out.println("Roles: " + roles));*/ dispatcher.on(PresenceUpdateEvent.class).subscribe(event -> { if (DiscordPlugin.SafeMode) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index f843450..71a1b9e 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -220,22 +220,28 @@ public class MCChatListener implements Listener { public boolean handleDiscord(MessageCreateEvent ev) { if (!ComponentManager.isEnabled(MinecraftChatModule.class)) return false; + System.out.println("Chat event"); val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); + System.out.println("C1"); val channel = ev.getMessage().getChannel().block(); + System.out.println("C2"); if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() && !(channel instanceof PrivateChannel && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) && !hasCustomChat)) return false; //Chat isn't enabled on this channel + System.out.println("C3"); if (channel instanceof PrivateChannel //Only in private chat && ev.getMessage().getContent().isPresent() && ev.getMessage().getContent().get().length() < "/mcchat<>".length() && ev.getMessage().getContent().get().replace("/", "") .equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat return false; //Allow disabling the chat if needed + System.out.println("C4"); if (CommandListener.runCommand(ev.getMessage(), true)) return true; //Allow running commands in chat channels + System.out.println("C5"); MCChatUtils.resetLastMessage(channel); //System.out.println("Message: "+ev.getMessage().getAuthor().toString()); recevents.add(ev); @@ -259,12 +265,14 @@ public class MCChatListener implements Listener { rectask.cancel(); return; } + System.out.println("Processing..."); val sender = event.getMessage().getAuthor().orElse(null); String dmessage = event.getMessage().getContent().orElse(""); try { final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannelId(), sender); val user = dsender.getChromaUser(); + System.out.println("Mentions start"); for (User u : event.getMessage().getUserMentions().toIterable()) { //TODO: Role mentions dmessage = dmessage.replace(u.getMention(), "@" + u.getUsername()); // TODO: IG Formatting val m = u.asMember(DiscordPlugin.mainServer.getId()).block(); @@ -276,6 +284,7 @@ public class MCChatListener implements Listener { for (GuildChannel ch : event.getGuild().flux().flatMap(Guild::getChannels).toIterable()) { dmessage = dmessage.replace(ch.getMention(), "#" + ch.getName()); // TODO: IG Formatting } + System.out.println("Mentions end"); dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?) dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up @@ -289,7 +298,9 @@ public class MCChatListener implements Listener { boolean react = false; + System.out.println("Getting channel..."); val sendChannel = event.getMessage().getChannel().block(); + System.out.println("Got channel"); boolean isPrivate = sendChannel instanceof PrivateChannel; if (dmessage.startsWith("/")) { // Ingame command if (!isPrivate) @@ -365,6 +376,7 @@ public class MCChatListener implements Listener { } } } else {// Not a command + System.out.println("Not a command"); if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 && !isPrivate && event.getMessage().getType() == Message.Type.CHANNEL_PINNED_MESSAGE) { val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp) @@ -374,11 +386,13 @@ public class MCChatListener implements Listener { : dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL); } else { val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); + System.out.println("Message created"); if (clmd != null) TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel); else TBMCChatAPI.SendChatMessage(cmb.build()); react = true; + System.out.println("Message sent"); } } if (react) { From b396ec47b4292eee3b8a27026eb484d6bbf338eb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 11 May 2019 00:15:50 +0200 Subject: [PATCH 15/24] Some fixes, some debugging #93 --- pom.xml | 1 + .../listeners/CommandListener.java | 71 +++++++++---------- .../listeners/CommonListeners.java | 48 ++++++------- .../discordplugin/mcchat/MCChatListener.java | 67 +++++++++-------- 4 files changed, 87 insertions(+), 100 deletions(-) diff --git a/pom.xml b/pom.xml index 9e2d7cf..1d5288e 100755 --- a/pom.xml +++ b/pom.xml @@ -68,6 +68,7 @@ net.ess3:Essentials + true
diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 744e189..40b6efd 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -9,6 +9,9 @@ import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.PrivateChannel; import discord4j.core.object.entity.Role; import lombok.val; +import reactor.core.publisher.Mono; + +import java.util.concurrent.atomic.AtomicBoolean; public class CommandListener { /** @@ -16,54 +19,44 @@ public class CommandListener { * * @param message The Discord message * @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message - * @return Whether it ran the command + * @return Whether it did not run the command */ - public static boolean runCommand(Message message, boolean mentionedonly) { + public static Mono runCommand(Message message, MessageChannel channel, boolean mentionedonly) { + Mono ret = Mono.just(true); if (!message.getContent().isPresent()) - return false; //Pin messages and such, let the mcchat listener deal with it - System.out.println("1"); - final MessageChannel channel = message.getChannel().block(); - System.out.println("2"); + return ret; //Pin messages and such, let the mcchat listener deal with it val content = message.getContent().get(); - if (channel == null) return false; + Mono tmp = ret; if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!(channel instanceof PrivateChannel) && !(content.charAt(0) == DiscordPlugin.getPrefix() && channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().asString()))) // - return false; - channel.type().subscribe(); // Fun + return ret; + tmp = ret.then(channel.type()); // Fun } - System.out.println("3"); final StringBuilder cmdwithargs = new StringBuilder(content); - val self = DiscordPlugin.dc.getSelf().block(); - System.out.println("4"); - if (self == null) return false; - val member = self.asMember(DiscordPlugin.mainServer.getId()).block(); - System.out.println("5"); - if (member == null) return false; - final String mention = self.getMention(); - final String mentionNick = member.getNicknameMention(); - System.out.println("6"); - boolean gotmention = checkanddeletemention(cmdwithargs, mention, message); - gotmention = checkanddeletemention(cmdwithargs, mentionNick, message) || gotmention; - System.out.println("7"); - val mentions = message.getRoleMentions(); - for (String mentionRole : member.getRoles().filter(r -> mentions.any(rr -> rr.getName().equals(r.getName())).blockOptional().orElse(false)).map(Role::getMention).toIterable()) - gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions - if (mentionedonly && !gotmention) - return false; - System.out.println("8"); - channel.type().subscribe(); - String cmdwithargsString = cmdwithargs.toString(); - System.out.println("9"); - try { - if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) - DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString).subscribe(); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); - } - System.out.println("10"); - return true; + val gotmention = new AtomicBoolean(); + return tmp.flatMapMany(x -> + DiscordPlugin.dc.getSelf().flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) + .flatMapMany(self -> { + gotmention.set(checkanddeletemention(cmdwithargs, self.getMention(), message)); + gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention(), message) || gotmention.get()); + val mentions = message.getRoleMentions(); + return self.getRoles().filterWhen(r -> mentions.any(rr -> rr.getName().equals(r.getName()))) + .map(Role::getMention); + }).map(mentionRole -> { + gotmention.set(checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention.get()); // Delete all mentions + return !mentionedonly || gotmention.get(); //Stops here if false + })).filter(b -> b).last(false).flatMap(b -> channel.type()).flatMap(v -> { + String cmdwithargsString = cmdwithargs.toString(); + try { + if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) + return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); + } + return Mono.empty(); + }).map(m -> false).defaultIfEmpty(true); } private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, Message message) { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 2d1c546..886d7c7 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -14,6 +14,7 @@ import discord4j.core.event.domain.role.RoleCreateEvent; import discord4j.core.event.domain.role.RoleDeleteEvent; import discord4j.core.event.domain.role.RoleUpdateEvent; import lombok.val; +import reactor.core.publisher.Mono; public class CommonListeners { @@ -27,39 +28,31 @@ public class CommonListeners { - CommandListener (with the correct prefix in #bot, or in private) */ public static void register(EventDispatcher dispatcher) { - dispatcher.on(MessageCreateEvent.class).subscribe(event -> { + dispatcher.on(MessageCreateEvent.class).flatMap(event -> { + val def = Mono.empty(); if (DiscordPlugin.SafeMode) - return; + return def; val author = event.getMessage().getAuthor(); if (!author.isPresent() || author.get().isBot()) - return; + return def; //System.out.println("Author: "+author.get()); //System.out.println("Bot: "+author.get().isBot()); - System.out.println("A"); if (FunModule.executeMemes(event.getMessage())) - return; - System.out.println("B"); - try { - boolean handled = false; - val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); - System.out.println("C"); - if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat - || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels - handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here - System.out.println("D"); - if (handled) return; - //System.out.println("Message handling"); - val mcchat = Component.getComponents().get(MinecraftChatModule.class); - if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again - handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels - System.out.println("E"); - if (!handled) - handled = CommandListener.runCommand(event.getMessage(), false); - System.out.println("F"); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while handling a message!", e); - } - }); + return def; + val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); + val commandCh = DPUtils.getMessageChannel(DiscordPlugin.plugin.CommandChannel()); + return commandCh.filter(ch -> (commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat + || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels + .filterWhen(ch -> { //Only continue if this doesn't handle the event + return CommandListener.runCommand(event.getMessage(), ch, true); //#bot is handled here + }).filterWhen(ch -> { + val mcchat = Component.getComponents().get(MinecraftChatModule.class); + if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again + return ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels + return Mono.empty(); //Wasn't handled, continue + }).filterWhen(ch -> CommandListener.runCommand(event.getMessage(), ch, false)); + }).onErrorContinue((err, obj) -> TBMCCoreAPI.SendException("An error occured while handling a message!", err)) + .subscribe(); /*dispatcher.on(MessageCreateEvent.class).doOnNext(x -> System.out.println("Got message")) .flatMap(MessageCreateEvent::getGuild) .flatMap(guild -> DiscordPlugin.dc.getSelf()) @@ -73,6 +66,7 @@ public class CommonListeners { dispatcher.on(RoleCreateEvent.class).subscribe(GameRoleModule::handleRoleEvent); dispatcher.on(RoleDeleteEvent.class).subscribe(GameRoleModule::handleRoleEvent); dispatcher.on(RoleUpdateEvent.class).subscribe(GameRoleModule::handleRoleEvent); + } private static boolean debug = false; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 71a1b9e..ccb41b8 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -25,6 +25,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitTask; +import reactor.core.publisher.Mono; import java.awt.*; import java.time.Instant; @@ -217,44 +218,42 @@ public class MCChatListener implements Listener { private static Thread recthread; // Discord - public boolean handleDiscord(MessageCreateEvent ev) { + public Mono handleDiscord(MessageCreateEvent ev) { + val ret = Mono.just(true); if (!ComponentManager.isEnabled(MinecraftChatModule.class)) - return false; + return ret; System.out.println("Chat event"); val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); - System.out.println("C1"); - val channel = ev.getMessage().getChannel().block(); - System.out.println("C2"); - if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() - && !(channel instanceof PrivateChannel - && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) - && !hasCustomChat)) - return false; //Chat isn't enabled on this channel - System.out.println("C3"); - if (channel instanceof PrivateChannel //Only in private chat - && ev.getMessage().getContent().isPresent() - && ev.getMessage().getContent().get().length() < "/mcchat<>".length() - && ev.getMessage().getContent().get().replace("/", "") - .equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat - return false; //Allow disabling the chat if needed - System.out.println("C4"); - if (CommandListener.runCommand(ev.getMessage(), true)) - return true; //Allow running commands in chat channels - System.out.println("C5"); - MCChatUtils.resetLastMessage(channel); - //System.out.println("Message: "+ev.getMessage().getAuthor().toString()); - recevents.add(ev); - if (rectask != null) - return true; - recrun = () -> { //Don't return in a while loop next time - recthread = Thread.currentThread(); - processDiscordToMC(); - if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down - rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing - }; - rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing - return true; + return ev.getMessage().getChannel().filter(channel -> { + return !(ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() + && !(channel instanceof PrivateChannel + && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) + && !hasCustomChat)); //Chat isn't enabled on this channel + }).filter(channel -> { + return !(channel instanceof PrivateChannel //Only in private chat + && ev.getMessage().getContent().isPresent() + && ev.getMessage().getContent().get().length() < "/mcchat<>".length() + && ev.getMessage().getContent().get().replace("/", "") + .equalsIgnoreCase("mcchat")); //Either mcchat or /mcchat + //Allow disabling the chat if needed + }).filterWhen(channel -> CommandListener.runCommand(ev.getMessage(), channel, true)) + //Allow running commands in chat channels + .filter(channel -> { + MCChatUtils.resetLastMessage(channel); + recevents.add(ev); + System.out.println("Message event added"); + if (rectask != null) + return true; + recrun = () -> { //Don't return in a while loop next time + recthread = Thread.currentThread(); + processDiscordToMC(); + if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down + rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing + }; + rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing + return true; + }).map(b -> false).defaultIfEmpty(true); } private void processDiscordToMC() { From 9e8f988ea6dd46ae4d75deeeb434ce1a50cf469c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 13:07:20 +0200 Subject: [PATCH 16/24] Renaming config methods to match keys --- .../buttondevteam/discordplugin/DPUtils.java | 2 +- .../discordplugin/DiscordPlugin.java | 18 +++++++------- .../announcer/AnnouncerModule.java | 24 +++++++++---------- .../discordplugin/commands/Command2DC.java | 2 +- .../discordplugin/commands/DebugCommand.java | 2 +- .../discordplugin/fun/FunModule.java | 4 ++-- .../listeners/CommandListener.java | 2 +- .../listeners/CommonListeners.java | 4 ++-- .../mccommands/DiscordMCCommand.java | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 6c3927c..a2902c3 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -89,7 +89,7 @@ public final class DPUtils { */ public static String botmention() { if (DiscordPlugin.plugin == null) return "#bot"; - return channelMention(DiscordPlugin.plugin.CommandChannel().get()); + return channelMention(DiscordPlugin.plugin.commandChannel().get()); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index a56e4f5..c812860 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -54,31 +54,31 @@ public class DiscordPlugin extends ButtonPlugin { @Getter private Command2DC manager; - private ConfigData Prefix() { + private ConfigData prefix() { return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); } public static char getPrefix() { if (plugin == null) return '/'; - return plugin.Prefix().get(); + return plugin.prefix().get(); } - private ConfigData MainServer() { + private ConfigData mainServer() { return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); } - public ConfigData CommandChannel() { + public ConfigData commandChannel() { return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L); } - public ConfigData> ModRole() { + public ConfigData> modRole() { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); } /** * The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access. */ - public ConfigData InviteLink() { + public ConfigData inviteLink() { return getIConfig().getData("inviteLink", ""); } @@ -127,7 +127,7 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { - mainServer = MainServer().get(); //Shouldn't change afterwards + mainServer = mainServer().get(); //Shouldn't change afterwards if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); @@ -136,7 +136,7 @@ public class DiscordPlugin extends ButtonPlugin { } mainServer = event.get(0).getGuild(); getLogger().warning("Main server set to first one: " + mainServer.getName()); - MainServer().set(mainServer); //Save in config + mainServer().set(mainServer); //Save in config } if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); @@ -144,7 +144,7 @@ public class DiscordPlugin extends ButtonPlugin { dc.updatePresence(Presence.online(Activity.playing("testing"))).subscribe(); } SafeMode = false; - DPUtils.disableIfConfigError(null, CommandChannel(), ModRole()); //Won't disable, just prints the warning here + DPUtils.disableIfConfigError(null, commandChannel(), modRole()); //Won't disable, just prints the warning here Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new MinecraftChatModule()); diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index afde743..11250a8 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -43,11 +43,11 @@ public class AnnouncerModule extends Component { return getConfig().getData("keepPinned", (short) 40); } - private ConfigData lastannouncementtime() { + private ConfigData lastAnnouncementTime() { return getConfig().getData("lastAnnouncementTime", 0L); } - private ConfigData lastseentime() { + private ConfigData lastSeenTime() { return getConfig().getData("lastSeenTime", 0L); } @@ -63,10 +63,10 @@ public class AnnouncerModule extends Component { Flux msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages); msgs.subscribe(Message::unpin); val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change - if (lastannouncementtime().get() == 0) //Load old data - lastannouncementtime().set(yc.getLong("lastannouncementtime")); - if (lastseentime().get() == 0) - lastseentime().set(yc.getLong("lastseentime")); + if (lastAnnouncementTime().get() == 0) //Load old data + lastAnnouncementTime().set(yc.getLong("lastannouncementtime")); + if (lastSeenTime().get() == 0) + lastSeenTime().set(yc.getLong("lastseentime")); new Thread(this::AnnouncementGetterThreadMethod).start(); } @@ -87,7 +87,7 @@ public class AnnouncerModule extends Component { .get("children").getAsJsonArray(); StringBuilder msgsb = new StringBuilder(); StringBuilder modmsgsb = new StringBuilder(); - long lastanntime = lastannouncementtime().get(); + long lastanntime = lastAnnouncementTime().get(); for (int i = json.size() - 1; i >= 0; i--) { JsonObject item = json.get(i).getAsJsonObject(); final JsonObject data = item.get("data").getAsJsonObject(); @@ -100,9 +100,9 @@ public class AnnouncerModule extends Component { distinguished = distinguishedjson.getAsString(); String permalink = "https://www.reddit.com" + data.get("permalink").getAsString(); long date = data.get("created_utc").getAsLong(); - if (date > lastseentime().get()) - lastseentime().set(date); - else if (date > lastannouncementtime().get()) { + if (date > lastSeenTime().get()) + lastSeenTime().set(date); + else if (date > lastAnnouncementTime().get()) { do { val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit"); if (reddituserclass == null) @@ -126,8 +126,8 @@ public class AnnouncerModule extends Component { if (modmsgsb.length() > 0) modChannel().get().flatMap(ch -> ch.createMessage(modmsgsb.toString())) .flatMap(Message::pin).subscribe(); - if (lastannouncementtime().get() != lastanntime) - lastannouncementtime().set(lastanntime); // If sending succeeded + if (lastAnnouncementTime().get() != lastanntime) + lastAnnouncementTime().set(lastanntime); // If sending succeeded } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index 4f5d0ec..ab56eb8 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -13,7 +13,7 @@ public class Command2DC extends Command2 { @Override public boolean hasPermission(Command2DCSender sender, ICommand2DC command, Method method) { - //return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); //TODO: ModRole may be null; more customisable way? + //return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.modRole().get()); //TODO: modRole may be null; more customisable way? return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index 96d00b3..b678e62 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -12,7 +12,7 @@ public class DebugCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String args) { sender.getMessage().getAuthorAsMember() - .flatMap(m -> DiscordPlugin.plugin.ModRole().get() + .flatMap(m -> DiscordPlugin.plugin.modRole().get() .map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId())))) .subscribe(success -> { if (success) diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 9866334..c37536d 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -45,7 +45,7 @@ public class FunModule extends Component implements Listener { /** * Questions that the bot will choose a random answer to give to. */ - private ConfigData serverReadyQuestions() { + private ConfigData serverReady() { return getConfig().getData("serverReady", () -> new String[]{"when will the server be open", "when will the server be ready", "when will the server be done", "when will the server be complete", "when will the server be finished", "when's the server ready", "when's the server open", @@ -100,7 +100,7 @@ public class FunModule extends Component implements Listener { } lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle if (!TBMCCoreAPI.IsTestServer() - && Arrays.stream(fm.serverReadyQuestions().get()).anyMatch(msglowercased::contains)) { + && Arrays.stream(fm.serverReady().get()).anyMatch(msglowercased::contains)) { int next; if (usableServerReadyStrings.size() == 0) fm.createUsableServerReadyStrings(); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 40b6efd..9d53f58 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -30,7 +30,7 @@ public class CommandListener { if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!(channel instanceof PrivateChannel) && !(content.charAt(0) == DiscordPlugin.getPrefix() - && channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().asString()))) // + && channel.getId().asString().equals(DiscordPlugin.plugin.commandChannel().get().asString()))) // return ret; tmp = ret.then(channel.type()); // Fun } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 886d7c7..6dce3e3 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -39,8 +39,8 @@ public class CommonListeners { //System.out.println("Bot: "+author.get().isBot()); if (FunModule.executeMemes(event.getMessage())) return def; - val commandChannel = DiscordPlugin.plugin.CommandChannel().get(); - val commandCh = DPUtils.getMessageChannel(DiscordPlugin.plugin.CommandChannel()); + val commandChannel = DiscordPlugin.plugin.commandChannel().get(); + val commandCh = DPUtils.getMessageChannel(DiscordPlugin.plugin.commandChannel()); return commandCh.filter(ch -> (commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels .filterWhen(ch -> { //Only continue if this doesn't handle the event diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 0fd6fe3..29eb5ce 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -97,7 +97,7 @@ public class DiscordMCCommand extends ICommand2MC { "Shows an invite link to the server" }) public void invite(CommandSender sender) { - String invi = DiscordPlugin.plugin.InviteLink().get(); + String invi = DiscordPlugin.plugin.inviteLink().get(); if (invi.length() > 0) { sender.sendMessage("§bInvite link: " + invi); return; From ac61225730ec9c94cf1c68375de96da2fb28232d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 21:51:28 +0200 Subject: [PATCH 17/24] Update, bot cmd fix, debugging --- pom.xml | 2 +- .../listeners/CommandListener.java | 73 +++++++++++-------- .../listeners/CommonListeners.java | 14 +++- .../discordplugin/mcchat/MCChatListener.java | 2 + .../discordplugin/mcchat/MCChatUtils.java | 3 + .../discordplugin/role/GameRoleModule.java | 56 +++++++------- 6 files changed, 90 insertions(+), 60 deletions(-) diff --git a/pom.xml b/pom.xml index 1d5288e..fdc1d53 100755 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ com.discord4j discord4j-core - 3.0.3 + 3.0.5 diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 9d53f58..011885a 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -21,42 +21,53 @@ public class CommandListener { * @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message * @return Whether it did not run the command */ - public static Mono runCommand(Message message, MessageChannel channel, boolean mentionedonly) { + public static Mono runCommand(Message message, MessageChannel commandChannel, boolean mentionedonly) { Mono ret = Mono.just(true); if (!message.getContent().isPresent()) return ret; //Pin messages and such, let the mcchat listener deal with it val content = message.getContent().get(); - Mono tmp = ret; - if (!mentionedonly) { //mentionedonly conditions are in CommonListeners - if (!(channel instanceof PrivateChannel) - && !(content.charAt(0) == DiscordPlugin.getPrefix() - && channel.getId().asString().equals(DiscordPlugin.plugin.commandChannel().get().asString()))) // - return ret; - tmp = ret.then(channel.type()); // Fun - } - final StringBuilder cmdwithargs = new StringBuilder(content); - val gotmention = new AtomicBoolean(); - return tmp.flatMapMany(x -> - DiscordPlugin.dc.getSelf().flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) - .flatMapMany(self -> { - gotmention.set(checkanddeletemention(cmdwithargs, self.getMention(), message)); - gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention(), message) || gotmention.get()); - val mentions = message.getRoleMentions(); - return self.getRoles().filterWhen(r -> mentions.any(rr -> rr.getName().equals(r.getName()))) - .map(Role::getMention); - }).map(mentionRole -> { - gotmention.set(checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention.get()); // Delete all mentions - return !mentionedonly || gotmention.get(); //Stops here if false - })).filter(b -> b).last(false).flatMap(b -> channel.type()).flatMap(v -> { - String cmdwithargsString = cmdwithargs.toString(); - try { - if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) - return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); + System.out.println("A"); + return message.getChannel().flatMap(channel -> { + Mono tmp = ret; + if (!mentionedonly) { //mentionedonly conditions are in CommonListeners + System.out.println("B"); + //System.out.println("Channel type: " + commandChannel.getClass().getSimpleName()); + //System.out.println("Guild: " + ((TextChannel) commandChannel).getGuildId()); + if (!(channel instanceof PrivateChannel) + && !(content.charAt(0) == DiscordPlugin.getPrefix() + && channel.getId().asLong() == commandChannel.getId().asLong())) // + return ret; + System.out.println("C"); + tmp = ret.then(channel.type()).thenReturn(true); // Fun (this true is ignored - x) } - return Mono.empty(); - }).map(m -> false).defaultIfEmpty(true); + final StringBuilder cmdwithargs = new StringBuilder(content); + val gotmention = new AtomicBoolean(); + return tmp.flatMapMany(x -> + DiscordPlugin.dc.getSelf().flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) + .flatMapMany(self -> { + System.out.println("D"); + gotmention.set(checkanddeletemention(cmdwithargs, self.getMention(), message)); + gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention(), message) || gotmention.get()); + val mentions = message.getRoleMentions(); + return self.getRoles().filterWhen(r -> mentions.any(rr -> rr.getName().equals(r.getName()))) + .map(Role::getMention); + }).map(mentionRole -> { + System.out.println("E"); + gotmention.set(checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention.get()); // Delete all mentions + return !mentionedonly || gotmention.get(); //Stops here if false + }).switchIfEmpty(Mono.fromSupplier(() -> !mentionedonly || gotmention.get()))) + .filter(b -> b).last(false).filter(b -> b).doOnNext(b -> channel.type().subscribe()).flatMap(b -> { + String cmdwithargsString = cmdwithargs.toString(); + try { + System.out.println("F"); + if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) + return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); + } + return Mono.empty(); + }).map(m -> false).defaultIfEmpty(true); + }); } private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, Message message) { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 6dce3e3..e6275df 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -13,6 +13,7 @@ import discord4j.core.event.domain.message.MessageCreateEvent; import discord4j.core.event.domain.role.RoleCreateEvent; import discord4j.core.event.domain.role.RoleDeleteEvent; import discord4j.core.event.domain.role.RoleUpdateEvent; +import discord4j.core.object.entity.PrivateChannel; import lombok.val; import reactor.core.publisher.Mono; @@ -41,16 +42,23 @@ public class CommonListeners { return def; val commandChannel = DiscordPlugin.plugin.commandChannel().get(); val commandCh = DPUtils.getMessageChannel(DiscordPlugin.plugin.commandChannel()); - return commandCh.filter(ch -> (commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat - || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels + return commandCh.filterWhen(ch -> event.getMessage().getChannel().map(mch -> + commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong() //If mentioned, that's higher than chat + || mch instanceof PrivateChannel + || event.getMessage().getContent().orElse("").contains("channelcon"))) //Only 'channelcon' is allowed in other channels .filterWhen(ch -> { //Only continue if this doesn't handle the event + System.out.println("Run command 1"); return CommandListener.runCommand(event.getMessage(), ch, true); //#bot is handled here }).filterWhen(ch -> { + System.out.println("mcchat"); val mcchat = Component.getComponents().get(MinecraftChatModule.class); if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again return ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels return Mono.empty(); //Wasn't handled, continue - }).filterWhen(ch -> CommandListener.runCommand(event.getMessage(), ch, false)); + }).filterWhen(ch -> { + System.out.println("Run command 2"); + return CommandListener.runCommand(event.getMessage(), ch, false); + }); }).onErrorContinue((err, obj) -> TBMCCoreAPI.SendException("An error occured while handling a message!", err)) .subscribe(); /*dispatcher.on(MessageCreateEvent.class).doOnNext(x -> System.out.println("Got message")) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index ccb41b8..0dc7be8 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -226,11 +226,13 @@ public class MCChatListener implements Listener { val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); return ev.getMessage().getChannel().filter(channel -> { + System.out.println("Filter 1"); return !(ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() && !(channel instanceof PrivateChannel && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) && !hasCustomChat)); //Chat isn't enabled on this channel }).filter(channel -> { + System.out.println("Filter 2"); return !(channel instanceof PrivateChannel //Only in private chat && ev.getMessage().getContent().isPresent() && ev.getMessage().getContent().get().length() < "/mcchat<>".length() diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 64740c4..bd516c2 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -210,14 +210,17 @@ public class MCChatUtils { */ public static void resetLastMessage(Channel channel) { if (notEnabled()) return; + System.out.println("Reset last message"); if (channel.getId().asLong() == module.chatChannel().get().asLong()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannelMono().block(), null) : lastmsgdata).message = null; + System.out.println("Reset done: public chat"); return; } // Don't set the whole object to null, the player and channel information should be preserved for (LastMsgData data : channel instanceof PrivateChannel ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) { if (data.channel.getId().asLong() == channel.getId().asLong()) { data.message = null; + System.out.println("Reset done: private/custom chat"); return; } } diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 8a0fdcf..0ab0cac 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -26,7 +26,7 @@ public class GameRoleModule extends Component { @Override protected void enable() { getPlugin().getManager().registerCommand(new RoleCommand(this)); - GameRoles = DiscordPlugin.mainServer.getRoles().filter(this::isGameRole).map(Role::getName).collect(Collectors.toList()).block(); + GameRoles = DiscordPlugin.mainServer.getRoles().filterWhen(this::isGameRole).map(Role::getName).collect(Collectors.toList()).block(); } @Override @@ -46,11 +46,14 @@ public class GameRoleModule extends Component { if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { Role role=((RoleCreateEvent) roleEvent).getRole(); - if (!grm.isGameRole(role)) - return; //Deleted or not a game role - GameRoles.add(role.getName()); - if (logChannel != null) - logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default.")).subscribe(); + grm.isGameRole(role).flatMap(b -> { + if (!b) + return Mono.empty(); //Deleted or not a game role + GameRoles.add(role.getName()); + if (logChannel != null) + return logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the default.")); + return Mono.empty(); + }).subscribe(); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { Role role=((RoleDeleteEvent) roleEvent).getRole().orElse(null); @@ -64,30 +67,33 @@ public class GameRoleModule extends Component { return; } Role or=event.getOld().get(); - if (!grm.isGameRole(event.getCurrent())) { - if (GameRoles.remove(or.getName()) && logChannel != null) - logChannel.flatMap(ch -> ch.createMessage("Removed " + or.getName() + " as a game role because it's color changed.")).subscribe(); - } else { - if (GameRoles.contains(or.getName()) && or.getName().equals(event.getCurrent().getName())) - return; - boolean removed = GameRoles.remove(or.getName()); //Regardless of whether it was a game role - GameRoles.add(event.getCurrent().getName()); //Add it because it has no color - if (logChannel != null) { - if (removed) - logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + ".")).subscribe(); - else - logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color.")).subscribe(); + grm.isGameRole(event.getCurrent()).flatMap(b -> { + if (!b) { + if (GameRoles.remove(or.getName()) && logChannel != null) + return logChannel.flatMap(ch -> ch.createMessage("Removed " + or.getName() + " as a game role because it's color changed.")); + } else { + if (GameRoles.contains(or.getName()) && or.getName().equals(event.getCurrent().getName())) + return Mono.empty(); + boolean removed = GameRoles.remove(or.getName()); //Regardless of whether it was a game role + GameRoles.add(event.getCurrent().getName()); //Add it because it has no color + if (logChannel != null) { + if (removed) + return logChannel.flatMap(ch -> ch.createMessage("Changed game role from " + or.getName() + " to " + event.getCurrent().getName() + ".")); + else + return logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the default color.")); + } } - } + return Mono.empty(); + }).subscribe(); } } - @SuppressWarnings("ConstantConditions") - private boolean isGameRole(Role r) { + private Mono isGameRole(Role r) { if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) - return false; //Only allow on the main server + return Mono.just(false); //Only allow on the main server val rc = new Color(149, 165, 166, 0); - return r.getColor().equals(rc) - && DiscordPlugin.dc.getSelf().block().asMember(DiscordPlugin.mainServer.getId()).block().hasHigherRoles(Collections.singleton(r)).block(); //Below one of our roles + return Mono.just(r.getColor().equals(rc)).filter(b -> b).flatMap(b -> + DiscordPlugin.dc.getSelf().flatMap(u -> u.asMember(DiscordPlugin.mainServer.getId())).flatMap(m -> m.hasHigherRoles(Collections.singleton(r)))) //Below one of our roles + .defaultIfEmpty(false); } } From 2bdba0af220b4927c032001a8ead833d0a49c16f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 23:35:22 +0200 Subject: [PATCH 18/24] Calling login events #96 isn't fixed by this --- .../discordplugin/mcchat/MCChatPrivate.java | 3 +- .../discordplugin/mcchat/MCListener.java | 29 +++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 1ef1111..e43bf74 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -11,7 +11,6 @@ import discord4j.core.object.entity.User; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.event.Event; -import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import java.util.ArrayList; @@ -33,7 +32,7 @@ public class MCChatPrivate { val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName(), mcm); MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence - callEventSync(new PlayerJoinEvent(sender, "")); + MCListener.callLoginEvents(sender); } else { val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user); if (p == null)// Player is offline - If the player is online, that takes precedence diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 44f1f96..279cc04 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -18,14 +18,12 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.*; import org.bukkit.event.player.PlayerLoginEvent.Result; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; import reactor.core.publisher.Mono; +import java.net.InetAddress; import java.util.Objects; @RequiredArgsConstructor @@ -36,6 +34,8 @@ class MCListener implements Listener { public void onPlayerLogin(PlayerLoginEvent e) { if (e.getResult() != Result.ALLOWED) return; + if (e.getPlayer() instanceof DiscordConnectedPlayer) + return; MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) //Only private mcchat should be in ConnectedSenders .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() .ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); @@ -67,16 +67,33 @@ class MCListener implements Listener { return; // Only care about real users MCChatUtils.OnlineSenders.entrySet() .removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()))); - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, + Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); + .ifPresent(MCListener::callLoginEvents)); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } + /** + * Call it from an async thread. + */ + public static void callLoginEvents(DiscordConnectedPlayer dcp) { + val event = new AsyncPlayerPreLoginEvent(dcp.getName(), InetAddress.getLoopbackAddress(), dcp.getUniqueId()); + MCChatUtils.callEventExcludingSome(event); + if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) + return; + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { + val ev = new PlayerLoginEvent(dcp, "localhost", InetAddress.getLoopbackAddress()); + MCChatUtils.callEventExcludingSome(ev); + if (ev.getResult() != Result.ALLOWED) + return; + MCChatUtils.callEventExcludingSome(new PlayerJoinEvent(dcp, "")); + }); + } + @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerKick(PlayerKickEvent e) { /*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") From bf538d9bd0f689ada75b053a78c07480af109867 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 25 May 2019 01:48:06 +0200 Subject: [PATCH 19/24] LP injecting, fake player fixes #96 LuckPerms Added support for excluding plugins from certain events from code Also might have fixed some message timeouts by relocating netty --- pom.xml | 422 ++++--- .../discordplugin/DiscordConnectedPlayer.java | 6 +- .../discordplugin/mcchat/MCChatPrivate.java | 17 +- .../discordplugin/mcchat/MCChatUtils.java | 92 +- .../discordplugin/mcchat/MCListener.java | 25 +- .../mcchat/MinecraftChatModule.java | 8 + .../playerfaker/DiscordFakePlayer.java | 1091 +++++++++-------- .../playerfaker/perm/LPInjector.java | 240 ++++ 8 files changed, 1114 insertions(+), 787 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java diff --git a/pom.xml b/pom.xml index fdc1d53..9fed5ae 100755 --- a/pom.xml +++ b/pom.xml @@ -1,45 +1,45 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.github.TBMCPlugins - DiscordPlugin - master-SNAPSHOT - jar + com.github.TBMCPlugins + DiscordPlugin + master-SNAPSHOT + jar - DiscordPlugin - http://maven.apache.org + DiscordPlugin + http://maven.apache.org - - - src/main/java - - - src - - **/*.java - - - - src/main/resources - - *.properties - *.yml - *.csv - *.txt - - true - - - DiscordPlugin - - - maven-compiler-plugin - 3.6.2 - - 1.8 - 1.8 + + + src/main/java + + + src + + **/*.java + + + + src/main/resources + + *.properties + *.yml + *.csv + *.txt + + true + + + DiscordPlugin + + + maven-compiler-plugin + 3.6.2 + + 1.8 + 1.8 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.2 - - - package - - shade - - - - - org.spigotmc:spigot-api - com.github.TBMCPlugins.ButtonCore:ButtonCore - net.ess3:Essentials - - - true - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.1 - - - copy - compile - - copy-resources - - - target - - - resources - - - - - - - - - maven-surefire-plugin + + + + org.apache.maven.plugins + maven-shade-plugin 2.4.2 - - false - - - - - + + + package + + shade + + + + + org.spigotmc:spigot-api + com.github.TBMCPlugins.ButtonCore:ButtonCore + net.ess3:Essentials + + + true + + + io.netty + buttondevteam.discordplugin.io.netty + + + + + + + +
+ + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + + copy + compile + + copy-resources + + + target + + + resources + + + + + + + + + maven-surefire-plugin + 2.4.2 + + false + + + + + - - UTF-8 + + UTF-8 master - + - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - jcenter - http://jcenter.bintray.com - - - jitpack.io - https://jitpack.io - + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + jcenter + http://jcenter.bintray.com + + + jitpack.io + https://jitpack.io + - - Essentials - http://repo.ess3.net/content/repositories/essrel/ - - - projectlombok.org - http://projectlombok.org/mavenrepo - + + Essentials + http://repo.ess3.net/content/repositories/essrel/ + + + projectlombok.org + http://projectlombok.org/mavenrepo + - + - - - junit - junit - 3.8.1 - test - - - org.spigotmc - spigot-api - 1.12-R0.1-SNAPSHOT - provided - - - org.spigotmc - spigot - 1.12.2-R0.1-SNAPSHOT - provided - - + + + junit + junit + 3.8.1 + test + + + org.spigotmc + spigot-api + 1.12-R0.1-SNAPSHOT + provided + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + com.discord4j discord4j-core 3.0.5 - - - org.slf4j - slf4j-jdk14 - 1.7.21 - - - com.github.TBMCPlugins.ButtonCore - ButtonCore - ${branch}-SNAPSHOT - provided - - - com.github.milkbowl - VaultAPI - master-SNAPSHOT - provided - - - net.ess3 - Essentials - 2.13.1 + + + org.slf4j + slf4j-jdk14 + 1.7.21 + + + com.github.TBMCPlugins.ButtonCore + ButtonCore + ${branch}-SNAPSHOT provided - - - - org.projectlombok - lombok - 1.16.16 - provided - + + + com.github.milkbowl + VaultAPI + master-SNAPSHOT + provided + + + net.ess3 + Essentials + 2.13.1 + provided + + + + org.projectlombok + lombok + 1.16.16 + provided + - - - org.objenesis - objenesis - 2.6 - test - - - com.vdurmont - emoji-java - 4.0.0 - + + + org.objenesis + objenesis + 2.6 + test + + + com.vdurmont + emoji-java + 4.0.0 + - + + com.github.lucko + LuckPerms + v4.4 + provided + + - - - ci - - - env.TRAVIS_BRANCH - - - - - ${env.TRAVIS_BRANCH} - - - + + + ci + + + env.TRAVIS_BRANCH + + + + + ${env.TRAVIS_BRANCH} + + + diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index de96b18..6e30a53 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -6,15 +6,19 @@ import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; import lombok.Getter; +import lombok.Setter; import java.util.UUID; public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer { private static int nextEntityId = 10000; private @Getter VanillaCommandListener vanillaCmdListener; + @Getter + @Setter + private boolean loggedIn = false; public DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { - super(user, channel, nextEntityId++, uuid, mcname ,module); + super(user, channel, nextEntityId++, uuid, mcname, module); vanillaCmdListener = new VanillaCommandListener<>(this); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index e43bf74..344ecf5 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -3,15 +3,12 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.player.TBMCPlayer; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.PrivateChannel; import discord4j.core.object.entity.User; import lombok.val; import org.bukkit.Bukkit; -import org.bukkit.event.Event; -import org.bukkit.event.player.PlayerQuitEvent; import java.util.ArrayList; @@ -32,11 +29,14 @@ public class MCChatPrivate { val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName(), mcm); MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence - MCListener.callLoginEvents(sender); + MCChatUtils.callLoginEvents(sender); } else { val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user); - if (p == null)// Player is offline - If the player is online, that takes precedence - callEventSync(new PlayerQuitEvent(sender, "")); + assert sender != null; + if (p == null // Player is offline - If the player is online, that takes precedence + && sender.isLoggedIn()) //Don't call the quit event if login failed + MCChatUtils.callLogoutEvent(sender, true); + sender.setLoggedIn(false); } } // ---- PermissionsEx warning is normal on logout ---- if (!start) @@ -60,11 +60,8 @@ public class MCChatPrivate { for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out - MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync + MCChatUtils.callLogoutEvent(valueEntry.getValue(), false); //This is sync MCChatUtils.ConnectedSenders.clear(); } - private static void callEventSync(Event event) { - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> MCChatUtils.callEventExcludingSome(event)); - } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index bd516c2..cbccc0d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; +import com.google.common.collect.Sets; import discord4j.core.object.entity.*; import discord4j.core.object.util.Snowflake; import io.netty.util.collection.LongObjectHashMap; @@ -15,14 +16,20 @@ import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.AuthorNagException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; import reactor.core.publisher.Mono; import javax.annotation.Nullable; +import java.net.InetAddress; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; @@ -43,6 +50,7 @@ public class MCChatUtils { static @Nullable LastMsgData lastmsgdata; static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks private static MinecraftChatModule module; + private static HashMap, HashSet> staticExcludedPlugins = new HashMap<>(); public static void updatePlayerList() { if (notEnabled()) return; @@ -74,19 +82,19 @@ public class MCChatUtils { if (s.length < 3) return; s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "") - + " online"; + + " online"; s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream() - .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); + .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); ((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } public static T addSender(HashMap> senders, - User user, T sender) { + User user, T sender) { return addSender(senders, user.getId().asString(), sender); } public static T addSender(HashMap> senders, - String did, T sender) { + String did, T sender) { var map = senders.get(did); if (map == null) map = new HashMap<>(); @@ -96,7 +104,7 @@ public class MCChatUtils { } public static T getSender(HashMap> senders, - Snowflake channel, User user) { + Snowflake channel, User user) { var map = senders.get(user.getId().asString()); if (map != null) return map.get(channel); @@ -104,7 +112,7 @@ public class MCChatUtils { } public static T removeSender(HashMap> senders, - Snowflake channel, User user) { + Snowflake channel, User user) { var map = senders.get(user.getId().asString()); if (map != null) return map.remove(channel); @@ -195,11 +203,11 @@ public class MCChatUtils { static DiscordSenderBase getSender(Snowflake channel, final User author) { //noinspection OptionalGetWithoutIsPresent return Stream.>>of( // https://stackoverflow.com/a/28833677/2703239 - () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null - () -> Optional.ofNullable(getSender(ConnectedSenders, channel, author)), // This doesn't support the public chat, but it'll always return null for it - () -> Optional.ofNullable(getSender(UnconnectedSenders, channel, author)), // - () -> Optional.of(addSender(UnconnectedSenders, author, - new DiscordSender(author, (MessageChannel) DiscordPlugin.dc.getChannelById(channel).block())))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); + () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null + () -> Optional.ofNullable(getSender(ConnectedSenders, channel, author)), // This doesn't support the public chat, but it'll always return null for it + () -> Optional.ofNullable(getSender(UnconnectedSenders, channel, author)), // + () -> Optional.of(addSender(UnconnectedSenders, author, + new DiscordSender(author, (MessageChannel) DiscordPlugin.dc.getChannelById(channel).block())))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); } /** @@ -213,7 +221,7 @@ public class MCChatUtils { System.out.println("Reset last message"); if (channel.getId().asLong() == module.chatChannel().get().asLong()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannelMono().block(), null) - : lastmsgdata).message = null; + : lastmsgdata).message = null; System.out.println("Reset done: public chat"); return; } // Don't set the whole object to null, the player and channel information should be preserved @@ -227,9 +235,23 @@ public class MCChatUtils { //If it gets here, it's sending a message to a non-chat channel } + public static void addStaticExcludedPlugin(Class event, String plugin) { + staticExcludedPlugins.compute(event, (e, hs) -> hs == null + ? Sets.newHashSet(plugin) + : (hs.add(plugin) ? hs : hs)); + } + public static void callEventExcludingSome(Event event) { if (notEnabled()) return; - callEventExcluding(event, false, module.excludedPlugins().get()); + val second = staticExcludedPlugins.get(event.getClass()); + String[] first = module.excludedPlugins().get(); + String[] both = second == null ? first + : Arrays.copyOf(first, first.length + second.size()); + int i = first.length; + if (second != null) + for (String plugin : second) + both[i++] = plugin; + callEventExcluding(event, false, both); } /** @@ -290,6 +312,50 @@ public class MCChatUtils { } } + /** + * Call it from an async thread. + */ + public static void callLoginEvents(DiscordConnectedPlayer dcp) { + Consumer> loginFail = kickMsg -> { + dcp.sendMessage("Minecraft chat disabled, as the login failed: " + kickMsg.get()); + MCChatPrivate.privateMCChat(dcp.getChannel(), false, dcp.getUser(), dcp.getChromaUser()); + }; //Probably also happens if the user is banned or so + val event = new AsyncPlayerPreLoginEvent(dcp.getName(), InetAddress.getLoopbackAddress(), dcp.getUniqueId()); + callEventExcludingSome(event); + if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { + loginFail.accept(event::getKickMessage); + return; + } + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { + val ev = new PlayerLoginEvent(dcp, "localhost", InetAddress.getLoopbackAddress()); + callEventExcludingSome(ev); + if (ev.getResult() != PlayerLoginEvent.Result.ALLOWED) { + loginFail.accept(ev::getKickMessage); + return; + } + callEventExcludingSome(new PlayerJoinEvent(dcp, "")); + dcp.setLoggedIn(true); + }); + } + + /** + * Only calls the events if the player is actually logged in + * + * @param dcp The player + * @param needsSync Whether we're in an async thread + */ + public static void callLogoutEvent(DiscordConnectedPlayer dcp, boolean needsSync) { + if (!dcp.isLoggedIn()) return; + val event = new PlayerQuitEvent(dcp, ""); + if (needsSync) callEventSync(event); + else callEventExcludingSome(event); + dcp.setLoggedIn(false); + } + + static void callEventSync(Event event) { + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> callEventExcludingSome(event)); + } + @RequiredArgsConstructor public static class LastMsgData { public Message message; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 279cc04..fe68342 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -18,12 +18,12 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.*; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.server.BroadcastMessageEvent; import reactor.core.publisher.Mono; -import java.net.InetAddress; import java.util.Objects; @RequiredArgsConstructor @@ -38,7 +38,7 @@ class MCListener implements Listener { return; MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) //Only private mcchat should be in ConnectedSenders .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); + .ifPresent(dcp -> MCChatUtils.callLogoutEvent(dcp, false)); } @EventHandler(priority = EventPriority.LOWEST) @@ -70,30 +70,13 @@ class MCListener implements Listener { Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(MCListener::callLoginEvents)); + .ifPresent(MCChatUtils::callLoginEvents)); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } - /** - * Call it from an async thread. - */ - public static void callLoginEvents(DiscordConnectedPlayer dcp) { - val event = new AsyncPlayerPreLoginEvent(dcp.getName(), InetAddress.getLoopbackAddress(), dcp.getUniqueId()); - MCChatUtils.callEventExcludingSome(event); - if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) - return; - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { - val ev = new PlayerLoginEvent(dcp, "localhost", InetAddress.getLoopbackAddress()); - MCChatUtils.callEventExcludingSome(ev); - if (ev.getResult() != Result.ALLOWED) - return; - MCChatUtils.callEventExcludingSome(new PlayerJoinEvent(dcp, "")); - }); - } - @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerKick(PlayerKickEvent e) { /*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index b4f8ec6..9e9bfd3 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -1,9 +1,11 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.core.MainPlugin; import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.playerfaker.perm.LPInjector; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; @@ -106,6 +108,12 @@ public class MinecraftChatModule extends Component { }); } } + + try { + new LPInjector(MainPlugin.Instance); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to init LuckPerms injector", e); + } } @Override diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index f197c84..6879155 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; import lombok.Getter; +import lombok.Setter; import lombok.experimental.Delegate; import org.bukkit.*; import org.bukkit.advancement.Advancement; @@ -17,6 +18,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.map.MapView; import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.ServerOperator; import org.bukkit.plugin.Plugin; import org.bukkit.scoreboard.Scoreboard; @@ -26,693 +28,706 @@ import java.util.*; @SuppressWarnings("deprecation") public class DiscordFakePlayer extends DiscordHumanEntity implements Player { protected DiscordFakePlayer(User user, MessageChannel channel, int entityId, UUID uuid, String mcname, MinecraftChatModule module) { - super(user, channel, entityId, uuid, module); - perm = new PermissibleBase(Bukkit.getOfflinePlayer(uuid)); - name = mcname; - } - - @Delegate - private PermissibleBase perm; - - private @Getter String name; - - @Override - public EntityType getType() { - return EntityType.PLAYER; - } - - @Override - public String getCustomName() { - return user.getUsername(); - } - - @Override - public void setCustomName(String name) { - } - - @Override - public boolean isConversing() { - - return false; - } - - @Override - public void acceptConversationInput(String input) { - } - - @Override - public boolean beginConversation(Conversation conversation) { - return false; - } - - @Override - public void abandonConversation(Conversation conversation) { - } - - @Override - public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { - } - - @Override - public boolean isOnline() { - return true;// Let's pretend - } - - @Override - public boolean isBanned() { - return false; - } - - @Override - public boolean isWhitelisted() { - return true; - } - - @Override - public void setWhitelisted(boolean value) { - } - - @Override - public Player getPlayer() { - return this; - } - - @Override - public long getFirstPlayed() { - return 0; - } - - @Override - public long getLastPlayed() { - return 0; - } - - @Override - public boolean hasPlayedBefore() { - return false; - } - - @Override - public Map serialize() { - return new HashMap<>(); - } - - @Override - public void sendPluginMessage(Plugin source, String channel, byte[] message) { - } - - @Override - public Set getListeningPluginChannels() { - return Collections.emptySet(); - } - - @Override - public String getDisplayName() { - return Objects.requireNonNull(user.asMember(DiscordPlugin.mainServer.getId()).block()).getDisplayName(); - } - - @Override - public void setDisplayName(String name) { - } - - @Override - public String getPlayerListName() { - return getName(); - } - - @Override - public void setPlayerListName(String name) { - } - - @Override - public void setCompassTarget(Location loc) { - } - - @Override - public Location getCompassTarget() { - return new Location(Bukkit.getWorlds().get(0), 0, 0, 0); - } - - @Override - public InetSocketAddress getAddress() { - return null; - } - - @Override - public void sendRawMessage(String message) { - sendMessage(message); - } - - @Override - public void kickPlayer(String message) { - } - - @Override - public void chat(String msg) { - Bukkit.getPluginManager() - .callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers()))); - } - - @Override - public boolean performCommand(String command) { - return Bukkit.getServer().dispatchCommand(this, command); - } - - @Override - public boolean isSneaking() { - return false; - } - - @Override - public void setSneaking(boolean sneak) { - } - - @Override - public boolean isSprinting() { - return false; - } - - @Override - public void setSprinting(boolean sprinting) { - } - - @Override - public void saveData() { - } - - @Override - public void loadData() { - } - - @Override - public void setSleepingIgnored(boolean isSleeping) { - } - - @Override - public boolean isSleepingIgnored() { - return false; - } - - @Override - public void playNote(Location loc, byte instrument, byte note) { - } - - @Override - public void playNote(Location loc, Instrument instrument, Note note) { - } - - @Override - public void playSound(Location location, Sound sound, float volume, float pitch) { - } + super(user, channel, entityId, uuid, module); + origPerm = perm = new PermissibleBase(basePlayer = Bukkit.getOfflinePlayer(uuid)); + name = mcname; + } + + @Delegate(excludes = ServerOperator.class) + private PermissibleBase origPerm; + + private @Getter String name; + + private @Getter OfflinePlayer basePlayer; + + @Getter + @Setter + private PermissibleBase perm; + + public void setOp(boolean value) { //CraftPlayer-compatible implementation + this.origPerm.setOp(value); + this.perm.recalculatePermissions(); + } + + public boolean isOp() { return this.origPerm.isOp(); } + + @Override + public EntityType getType() { + return EntityType.PLAYER; + } + + @Override + public String getCustomName() { + return user.getUsername(); + } + + @Override + public void setCustomName(String name) { + } + + @Override + public boolean isConversing() { + + return false; + } + + @Override + public void acceptConversationInput(String input) { + } + + @Override + public boolean beginConversation(Conversation conversation) { + return false; + } + + @Override + public void abandonConversation(Conversation conversation) { + } + + @Override + public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { + } + + @Override + public boolean isOnline() { + return true;// Let's pretend + } + + @Override + public boolean isBanned() { + return false; + } + + @Override + public boolean isWhitelisted() { + return true; + } + + @Override + public void setWhitelisted(boolean value) { + } + + @Override + public Player getPlayer() { + return this; + } + + @Override + public long getFirstPlayed() { + return 0; + } + + @Override + public long getLastPlayed() { + return 0; + } + + @Override + public boolean hasPlayedBefore() { + return false; + } + + @Override + public Map serialize() { + return new HashMap<>(); + } + + @Override + public void sendPluginMessage(Plugin source, String channel, byte[] message) { + } + + @Override + public Set getListeningPluginChannels() { + return Collections.emptySet(); + } + + @Override + public String getDisplayName() { + return Objects.requireNonNull(user.asMember(DiscordPlugin.mainServer.getId()).block()).getDisplayName(); + } + + @Override + public void setDisplayName(String name) { + } + + @Override + public String getPlayerListName() { + return getName(); + } + + @Override + public void setPlayerListName(String name) { + } + + @Override + public void setCompassTarget(Location loc) { + } + + @Override + public Location getCompassTarget() { + return new Location(Bukkit.getWorlds().get(0), 0, 0, 0); + } + + @Override + public InetSocketAddress getAddress() { + return null; + } + + @Override + public void sendRawMessage(String message) { + sendMessage(message); + } + + @Override + public void kickPlayer(String message) { + } + + @Override + public void chat(String msg) { + Bukkit.getPluginManager() + .callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers()))); + } + + @Override + public boolean performCommand(String command) { + return Bukkit.getServer().dispatchCommand(this, command); + } + + @Override + public boolean isSneaking() { + return false; + } + + @Override + public void setSneaking(boolean sneak) { + } + + @Override + public boolean isSprinting() { + return false; + } + + @Override + public void setSprinting(boolean sprinting) { + } + + @Override + public void saveData() { + } + + @Override + public void loadData() { + } + + @Override + public void setSleepingIgnored(boolean isSleeping) { + } + + @Override + public boolean isSleepingIgnored() { + return false; + } + + @Override + public void playNote(Location loc, byte instrument, byte note) { + } + + @Override + public void playNote(Location loc, Instrument instrument, Note note) { + } + + @Override + public void playSound(Location location, Sound sound, float volume, float pitch) { + } - @Override - public void playSound(Location location, String sound, float volume, float pitch) { - } + @Override + public void playSound(Location location, String sound, float volume, float pitch) { + } - @Override - public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) { - } + @Override + public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) { + } - @Override - public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) { - } + @Override + public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) { + } - @Override - public void stopSound(Sound sound) { - } + @Override + public void stopSound(Sound sound) { + } - @Override - public void stopSound(String sound) { - } + @Override + public void stopSound(String sound) { + } - @Override - public void stopSound(Sound sound, SoundCategory category) { - } + @Override + public void stopSound(Sound sound, SoundCategory category) { + } - @Override - public void stopSound(String sound, SoundCategory category) { - } + @Override + public void stopSound(String sound, SoundCategory category) { + } - @Override - public void playEffect(Location loc, Effect effect, int data) { - } + @Override + public void playEffect(Location loc, Effect effect, int data) { + } - @Override - public void playEffect(Location loc, Effect effect, T data) { - } + @Override + public void playEffect(Location loc, Effect effect, T data) { + } - @Override - public void sendBlockChange(Location loc, Material material, byte data) { - } + @Override + public void sendBlockChange(Location loc, Material material, byte data) { + } - @Override - public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) { - return false; - } + @Override + public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) { + return false; + } - @Override - public void sendBlockChange(Location loc, int material, byte data) { - } + @Override + public void sendBlockChange(Location loc, int material, byte data) { + } - @Override - public void sendSignChange(Location loc, String[] lines) throws IllegalArgumentException { - } + @Override + public void sendSignChange(Location loc, String[] lines) throws IllegalArgumentException { + } - @Override - public void sendMap(MapView map) { - } + @Override + public void sendMap(MapView map) { + } - @Override - public void updateInventory() { - } + @Override + public void updateInventory() { + } - @Override - public void awardAchievement(@SuppressWarnings("deprecation") Achievement achievement) { - } + @Override + public void awardAchievement(@SuppressWarnings("deprecation") Achievement achievement) { + } - @Override - public void removeAchievement(@SuppressWarnings("deprecation") Achievement achievement) { - } + @Override + public void removeAchievement(@SuppressWarnings("deprecation") Achievement achievement) { + } - @Override - public boolean hasAchievement(@SuppressWarnings("deprecation") Achievement achievement) { - return false; - } + @Override + public boolean hasAchievement(@SuppressWarnings("deprecation") Achievement achievement) { + return false; + } - @Override - public void incrementStatistic(Statistic statistic) throws IllegalArgumentException { - } + @Override + public void incrementStatistic(Statistic statistic) throws IllegalArgumentException { + } - @Override - public void decrementStatistic(Statistic statistic) throws IllegalArgumentException { - } + @Override + public void decrementStatistic(Statistic statistic) throws IllegalArgumentException { + } - @Override - public void incrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException { + @Override + public void incrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException { - } + } - @Override - public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException { + @Override + public void decrementStatistic(Statistic statistic, int amount) throws IllegalArgumentException { - } + } - @Override - public void setStatistic(Statistic statistic, int newValue) throws IllegalArgumentException { + @Override + public void setStatistic(Statistic statistic, int newValue) throws IllegalArgumentException { - } + } - @Override - public int getStatistic(Statistic statistic) throws IllegalArgumentException { + @Override + public int getStatistic(Statistic statistic) throws IllegalArgumentException { - return 0; - } + return 0; + } - @Override - public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + @Override + public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { - } + } - @Override - public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + @Override + public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { - } + } - @Override - public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException { + @Override + public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException { - return 0; - } + return 0; + } - @Override - public void incrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException { + @Override + public void incrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException { - } + } - @Override - public void decrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException { + @Override + public void decrementStatistic(Statistic statistic, Material material, int amount) throws IllegalArgumentException { - } + } - @Override - public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException { + @Override + public void setStatistic(Statistic statistic, Material material, int newValue) throws IllegalArgumentException { - } + } - @Override - public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + @Override + public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { - } + } - @Override - public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + @Override + public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { - } + } - @Override - public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { + @Override + public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { - return 0; - } + return 0; + } - @Override - public void incrementStatistic(Statistic statistic, EntityType entityType, int amount) - throws IllegalArgumentException { + @Override + public void incrementStatistic(Statistic statistic, EntityType entityType, int amount) + throws IllegalArgumentException { - } + } - @Override - public void decrementStatistic(Statistic statistic, EntityType entityType, int amount) { + @Override + public void decrementStatistic(Statistic statistic, EntityType entityType, int amount) { - } + } - @Override - public void setStatistic(Statistic statistic, EntityType entityType, int newValue) { + @Override + public void setStatistic(Statistic statistic, EntityType entityType, int newValue) { - } + } - @Override - public void setPlayerTime(long time, boolean relative) { + @Override + public void setPlayerTime(long time, boolean relative) { - } + } - @Override - public long getPlayerTime() { + @Override + public long getPlayerTime() { - return 0; - } + return 0; + } - @Override - public long getPlayerTimeOffset() { + @Override + public long getPlayerTimeOffset() { - return 0; - } + return 0; + } - @Override - public boolean isPlayerTimeRelative() { + @Override + public boolean isPlayerTimeRelative() { - return false; - } + return false; + } - @Override - public void resetPlayerTime() { + @Override + public void resetPlayerTime() { - } + } - @Override - public void setPlayerWeather(WeatherType type) { + @Override + public void setPlayerWeather(WeatherType type) { - } + } - @Override - public WeatherType getPlayerWeather() { + @Override + public WeatherType getPlayerWeather() { - return null; - } + return null; + } - @Override - public void resetPlayerWeather() { + @Override + public void resetPlayerWeather() { - } + } - @Override - public void giveExp(int amount) { + @Override + public void giveExp(int amount) { - } + } - @Override - public void giveExpLevels(int amount) { + @Override + public void giveExpLevels(int amount) { - } + } - @Override - public float getExp() { + @Override + public float getExp() { - return 0; - } + return 0; + } - @Override - public void setExp(float exp) { + @Override + public void setExp(float exp) { - } + } - @Override - public int getLevel() { + @Override + public int getLevel() { - return 0; - } + return 0; + } - @Override - public void setLevel(int level) { + @Override + public void setLevel(int level) { - } + } - @Override - public int getTotalExperience() { + @Override + public int getTotalExperience() { - return 0; - } + return 0; + } - @Override - public void setTotalExperience(int exp) { + @Override + public void setTotalExperience(int exp) { - } + } - @Override - public float getExhaustion() { + @Override + public float getExhaustion() { - return 0; - } + return 0; + } - @Override - public void setExhaustion(float value) { + @Override + public void setExhaustion(float value) { - } + } - @Override - public float getSaturation() { + @Override + public float getSaturation() { - return 0; - } + return 0; + } - @Override - public void setSaturation(float value) { + @Override + public void setSaturation(float value) { - } + } - @Override - public int getFoodLevel() { + @Override + public int getFoodLevel() { - return 0; - } + return 0; + } - @Override - public void setFoodLevel(int value) { + @Override + public void setFoodLevel(int value) { - } + } - @Override - public Location getBedSpawnLocation() { - return null; - } + @Override + public Location getBedSpawnLocation() { + return null; + } - @Override - public void setBedSpawnLocation(Location location) { - } + @Override + public void setBedSpawnLocation(Location location) { + } - @Override - public void setBedSpawnLocation(Location location, boolean force) { - } + @Override + public void setBedSpawnLocation(Location location, boolean force) { + } - @Override - public boolean getAllowFlight() { - return false; - } + @Override + public boolean getAllowFlight() { + return false; + } - @Override - public void setAllowFlight(boolean flight) { - } + @Override + public void setAllowFlight(boolean flight) { + } - @Override - public void hidePlayer(Player player) { - } + @Override + public void hidePlayer(Player player) { + } - @Override - public void showPlayer(Player player) { - } + @Override + public void showPlayer(Player player) { + } - @Override - public boolean canSee(Player player) { // Nobody can see them - return false; - } + @Override + public boolean canSee(Player player) { // Nobody can see them + return false; + } - @Override - public boolean isFlying() { - return false; - } + @Override + public boolean isFlying() { + return false; + } - @Override - public void setFlying(boolean value) { - } + @Override + public void setFlying(boolean value) { + } - @Override - public void setFlySpeed(float value) throws IllegalArgumentException { - } + @Override + public void setFlySpeed(float value) throws IllegalArgumentException { + } - @Override - public void setWalkSpeed(float value) throws IllegalArgumentException { - } + @Override + public void setWalkSpeed(float value) throws IllegalArgumentException { + } - @Override - public float getFlySpeed() { - return 0; - } + @Override + public float getFlySpeed() { + return 0; + } - @Override - public float getWalkSpeed() { - return 0; - } + @Override + public float getWalkSpeed() { + return 0; + } - @Override - public void setTexturePack(String url) { - } + @Override + public void setTexturePack(String url) { + } - @Override - public void setResourcePack(String url) { - } + @Override + public void setResourcePack(String url) { + } - @Override - public void setResourcePack(String url, byte[] hash) { - } + @Override + public void setResourcePack(String url, byte[] hash) { + } - @Override - public Scoreboard getScoreboard() { - return null; - } + @Override + public Scoreboard getScoreboard() { + return null; + } - @Override - public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException { - } + @Override + public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException { + } - @Override - public boolean isHealthScaled() { - return false; - } + @Override + public boolean isHealthScaled() { + return false; + } - @Override - public void setHealthScaled(boolean scale) { - } + @Override + public void setHealthScaled(boolean scale) { + } - @Override - public void setHealthScale(double scale) throws IllegalArgumentException { - } + @Override + public void setHealthScale(double scale) throws IllegalArgumentException { + } - @Override - public double getHealthScale() { - return 1; - } + @Override + public double getHealthScale() { + return 1; + } - @Override - public Entity getSpectatorTarget() { - return null; - } + @Override + public Entity getSpectatorTarget() { + return null; + } - @Override - public void setSpectatorTarget(Entity entity) { - } + @Override + public void setSpectatorTarget(Entity entity) { + } - @Override - public void sendTitle(String title, String subtitle) { - } + @Override + public void sendTitle(String title, String subtitle) { + } - @Override - public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) { - } + @Override + public void sendTitle(String title, String subtitle, int fadeIn, int stay, int fadeOut) { + } - @Override - public void resetTitle() { - } + @Override + public void resetTitle() { + } - @Override - public void spawnParticle(Particle particle, Location location, int count) { - } + @Override + public void spawnParticle(Particle particle, Location location, int count) { + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count) { - } + } - @Override - public void spawnParticle(Particle particle, Location location, int count, T data) { + @Override + public void spawnParticle(Particle particle, Location location, int count, T data) { - } + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, T data) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, T data) { - } + } - @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, - double offsetZ) { + @Override + public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, + double offsetZ) { - } + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, - double offsetY, double offsetZ) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, + double offsetY, double offsetZ) { - } + } - @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, - double offsetZ, T data) { + @Override + public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, + double offsetZ, T data) { - } + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, - double offsetY, double offsetZ, T data) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, + double offsetY, double offsetZ, T data) { - } + } - @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, - double offsetZ, double extra) { + @Override + public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, + double offsetZ, double extra) { - } + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, - double offsetY, double offsetZ, double extra) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, + double offsetY, double offsetZ, double extra) { - } + } - @Override - public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, - double offsetZ, double extra, T data) { + @Override + public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, + double offsetZ, double extra, T data) { - } + } - @Override - public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, - double offsetY, double offsetZ, double extra, T data) { + @Override + public void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, + double offsetY, double offsetZ, double extra, T data) { - } + } - @Override - public AdvancementProgress getAdvancementProgress(Advancement advancement) { // TODO: Test - return null; - } + @Override + public AdvancementProgress getAdvancementProgress(Advancement advancement) { // TODO: Test + return null; + } - @Override - public String getLocale() { + @Override + public String getLocale() { - return null; - } + return null; + } - @Override - public Player.Spigot spigot() { - return new Player.Spigot(); - } + @Override + public Player.Spigot spigot() { + return new Player.Spigot(); + } } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java b/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java new file mode 100644 index 0000000..de5a84b --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java @@ -0,0 +1,240 @@ +package buttondevteam.discordplugin.playerfaker.perm; + +import buttondevteam.core.MainPlugin; +import buttondevteam.discordplugin.mcchat.MCChatUtils; +import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer; +import buttondevteam.lib.TBMCCoreAPI; +import me.lucko.luckperms.bukkit.LPBukkitBootstrap; +import me.lucko.luckperms.bukkit.LPBukkitPlugin; +import me.lucko.luckperms.bukkit.inject.dummy.DummyPermissibleBase; +import me.lucko.luckperms.bukkit.inject.permissible.LPPermissible; +import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener; +import me.lucko.luckperms.common.config.ConfigKeys; +import me.lucko.luckperms.common.locale.message.Message; +import me.lucko.luckperms.common.model.User; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.PermissionAttachment; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class LPInjector implements Listener { //Disable login event for LuckPerms + private LPBukkitPlugin plugin; + private BukkitConnectionListener connectionListener; + private Set deniedLogin; + private Field detectedCraftBukkitOfflineMode; + private Method printCraftBukkitOfflineModeError; + private Field PERMISSIBLE_BASE_ATTACHMENTS_FIELD; + private Method convertAndAddAttachments; + private Method getActive; + private Method setOldPermissible; + private Method getOldPermissible; + + public LPInjector(MainPlugin mp) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException { + LPBukkitBootstrap bs = (LPBukkitBootstrap) Bukkit.getPluginManager().getPlugin("LuckPerms"); + Field field = LPBukkitBootstrap.class.getDeclaredField("plugin"); + field.setAccessible(true); + plugin = (LPBukkitPlugin) field.get(bs); + MCChatUtils.addStaticExcludedPlugin(PlayerLoginEvent.class, "LuckPerms"); + MCChatUtils.addStaticExcludedPlugin(PlayerQuitEvent.class, "LuckPerms"); + + field = LPBukkitPlugin.class.getDeclaredField("connectionListener"); + field.setAccessible(true); + connectionListener = (BukkitConnectionListener) field.get(plugin); + field = connectionListener.getClass().getDeclaredField("deniedLogin"); + field.setAccessible(true); + //noinspection unchecked + deniedLogin = (Set) field.get(connectionListener); + field = connectionListener.getClass().getDeclaredField("detectedCraftBukkitOfflineMode"); + field.setAccessible(true); + detectedCraftBukkitOfflineMode = field; + printCraftBukkitOfflineModeError = connectionListener.getClass().getDeclaredMethod("printCraftBukkitOfflineModeError"); + printCraftBukkitOfflineModeError.setAccessible(true); + + //PERMISSIBLE_FIELD = DiscordFakePlayer.class.getDeclaredField("perm"); + //PERMISSIBLE_FIELD.setAccessible(true); //Hacking my own plugin, while we're at it + PERMISSIBLE_BASE_ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments"); + PERMISSIBLE_BASE_ATTACHMENTS_FIELD.setAccessible(true); + + convertAndAddAttachments = LPPermissible.class.getDeclaredMethod("convertAndAddAttachments", Collection.class); + convertAndAddAttachments.setAccessible(true); + getActive = LPPermissible.class.getDeclaredMethod("getActive"); + getActive.setAccessible(true); + setOldPermissible = LPPermissible.class.getDeclaredMethod("setOldPermissible", PermissibleBase.class); + setOldPermissible.setAccessible(true); + getOldPermissible = LPPermissible.class.getDeclaredMethod("getOldPermissible"); + getOldPermissible.setAccessible(true); + + TBMCCoreAPI.RegisterEventsForExceptions(this, mp); + } + + + //Code copied from LuckPerms - me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerLoginEvent e) { + /* Called when the player starts logging into the server. + At this point, the users data should be present and loaded. */ + + if (!(e.getPlayer() instanceof DiscordFakePlayer)) + return; //Normal players must be handled by the plugin + + final DiscordFakePlayer player = (DiscordFakePlayer) e.getPlayer(); + + if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) { + plugin.getLogger().info("Processing login for " + player.getUniqueId() + " - " + player.getName()); + } + + final User user = plugin.getUserManager().getIfLoaded(player.getUniqueId()); + + /* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */ + if (user == null) { + deniedLogin.add(player.getUniqueId()); + + if (!connectionListener.getUniqueConnections().contains(player.getUniqueId())) { + + plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() + + " doesn't have data pre-loaded, they have never been processed during pre-login in this session." + + " - denying login."); + + try { + if ((Boolean) detectedCraftBukkitOfflineMode.get(connectionListener)) { + printCraftBukkitOfflineModeError.invoke(connectionListener); + e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_STATE_ERROR_CB_OFFLINE_MODE.asString(plugin.getLocaleManager())); + return; + } + } catch (IllegalAccessException | InvocationTargetException ex) { + ex.printStackTrace(); + } + + } else { + plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() + + " doesn't currently have data pre-loaded, but they have been processed before in this session." + + " - denying login."); + } + + e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_STATE_ERROR.asString(plugin.getLocaleManager())); + return; + } + + // User instance is there, now we can inject our custom Permissible into the player. + // Care should be taken at this stage to ensure that async tasks which manipulate bukkit data check that the player is still online. + try { + // get the existing PermissibleBase held by the player + PermissibleBase oldPermissible = player.getPerm(); + + // Make a new permissible for the user + LPPermissible lpPermissible = new LPPermissible(player, user, plugin); + + // Inject into the player + inject(player, lpPermissible, oldPermissible); + + } catch (Throwable t) { + plugin.getLogger().warn("Exception thrown when setting up permissions for " + + player.getUniqueId() + " - " + player.getName() + " - denying login."); + t.printStackTrace(); + + e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_SETUP_ERROR.asString(plugin.getLocaleManager())); + return; + } + + plugin.refreshAutoOp(player, true); + } + + // Wait until the last priority to unload, so plugins can still perform permission checks on this event + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent e) { + if (!(e.getPlayer() instanceof DiscordFakePlayer)) + return; + + final DiscordFakePlayer player = (DiscordFakePlayer) e.getPlayer(); + + connectionListener.handleDisconnect(player.getUniqueId()); + + // perform unhooking from bukkit objects 1 tick later. + // this allows plugins listening after us on MONITOR to still have intact permissions data + this.plugin.getBootstrap().getServer().getScheduler().runTaskLaterAsynchronously(this.plugin.getBootstrap(), () -> { + // Remove the custom permissible + try { + uninject(player, true); + } catch (Exception ex) { + ex.printStackTrace(); + } + + // Handle auto op + if (this.plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) { + player.setOp(false); + } + + // remove their contexts cache + this.plugin.getContextManager().onPlayerQuit(player); + }, 1L); + } + + //me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector + private void inject(DiscordFakePlayer player, LPPermissible newPermissible, PermissibleBase oldPermissible) throws IllegalAccessException, InvocationTargetException { + + // seems we have already injected into this player. + if (oldPermissible instanceof LPPermissible) { + throw new IllegalStateException("LPPermissible already injected into player " + player.toString()); + } + + // Move attachments over from the old permissible + + //noinspection unchecked + List attachments = (List) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(oldPermissible); + + convertAndAddAttachments.invoke(newPermissible, attachments); + attachments.clear(); + oldPermissible.clearPermissions(); + + // Setup the new permissible + ((AtomicBoolean) getActive.invoke(newPermissible)).set(true); + setOldPermissible.invoke(newPermissible, oldPermissible); + + // inject the new instance + player.setPerm(newPermissible); + } + + private void uninject(DiscordFakePlayer player, boolean dummy) throws Exception { + + // gets the players current permissible. + PermissibleBase permissible = player.getPerm(); + + // only uninject if the permissible was a luckperms one. + if (permissible instanceof LPPermissible) { + LPPermissible lpPermissible = ((LPPermissible) permissible); + + // clear all permissions + lpPermissible.clearPermissions(); + + // set to inactive + ((AtomicBoolean) getActive.invoke(lpPermissible)).set(false); + + // handle the replacement permissible. + if (dummy) { + // just inject a dummy class. this is used when we know the player is about to quit the server. + player.setPerm(DummyPermissibleBase.INSTANCE); + + } else { + PermissibleBase newPb = (PermissibleBase) getOldPermissible.invoke(lpPermissible); + if (newPb == null) { + newPb = new PermissibleBase(player); + } + + player.setPerm(newPb); + } + } + } +} From 545b8130e01745668a6d8fd47200d859a8ba53a2 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 30 May 2019 18:45:44 +0200 Subject: [PATCH 20/24] Added timings and a line that solves everything cb.setStoreService(new JdkStoreService()); --- pom.xml | 2 +- .../discordplugin/DiscordPlugin.java | 31 +++++++++++-------- .../listeners/CommandListener.java | 17 +++++----- .../listeners/CommonListeners.java | 17 +++++----- .../discordplugin/mcchat/MCChatListener.java | 11 ++++--- .../discordplugin/mcchat/MCChatUtils.java | 3 -- .../discordplugin/util/Timings.java | 16 ++++++++++ 7 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/util/Timings.java diff --git a/pom.xml b/pom.xml index 9fed5ae..987ff82 100755 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,7 @@ com.discord4j discord4j-core - 3.0.5 + 3.0.6 diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index c812860..b357f11 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -12,6 +12,7 @@ import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommand; import buttondevteam.discordplugin.role.GameRoleModule; +import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; @@ -29,6 +30,7 @@ import discord4j.core.object.presence.Activity; import discord4j.core.object.presence.Presence; import discord4j.core.object.reaction.ReactionEmoji; import discord4j.core.object.util.Snowflake; +import discord4j.store.jdk.JdkStoreService; import lombok.Getter; import lombok.val; import net.milkbowl.vault.permission.Permission; @@ -108,6 +110,7 @@ public class DiscordPlugin extends ButtonPlugin { } val cb = new DiscordClientBuilder(token); cb.setInitialPresence(Presence.doNotDisturb(Activity.playing("booting"))); + cb.setStoreService(new JdkStoreService()); //The default doesn't work for some reason - it's waaay faster now dc = cb.build(); dc.getEventDispatcher().on(ReadyEvent.class) // Listen for ReadyEvent(s) .map(event -> event.getGuilds().size()) // Get how many guilds the bot is in @@ -138,11 +141,6 @@ public class DiscordPlugin extends ButtonPlugin { getLogger().warning("Main server set to first one: " + mainServer.getName()); mainServer().set(mainServer); //Save in config } - if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); - } else { - dc.updatePresence(Presence.online(Activity.playing("testing"))).subscribe(); - } SafeMode = false; DPUtils.disableIfConfigError(null, commandChannel(), modRole()); //Won't disable, just prints the warning here @@ -196,6 +194,11 @@ public class DiscordPlugin extends ButtonPlugin { setupProviders(); IHaveConfig.pregenConfig(this, null); + if (!TBMCCoreAPI.IsTestServer()) { + dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); + } else { + dc.updatePresence(Presence.online(Activity.playing("testing"))).subscribe(); + } } catch (Exception e) { TBMCCoreAPI.SendException("An error occurred while enabling DiscordPlugin!", e); } @@ -209,9 +212,10 @@ public class DiscordPlugin extends ButtonPlugin { @Override public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load - System.out.println("Disable start"); + Timings timings = new Timings(); + timings.printElapsed("Disable start"); MCChatUtils.forCustomAndAllMCChat(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> { - System.out.println("Sending message to " + ch.getMention()); + timings.printElapsed("Sending message to " + ch.getMention()); if (DiscordMCCommand.resetting) ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting"); else @@ -226,16 +230,17 @@ public class DiscordPlugin extends ButtonPlugin { + "kicked the hell out.") //TODO: Make configurable : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled })).subscribe(), ChannelconBroadcast.RESTART, false); - System.out.println("Updating player list"); + timings.printElapsed("Updating player list"); ChromaBot.getInstance().updatePlayerList(); - System.out.println("Done"); + timings.printElapsed("Done"); } @Override public void pluginDisable() { - System.out.println("Actual disable start (logout)"); + Timings timings = new Timings(); + timings.printElapsed("Actual disable start (logout)"); MCChatPrivate.logoutAll(); - System.out.println("Config setup"); + timings.printElapsed("Config setup"); getConfig().set("serverup", false); if (ChromaBot.getInstance() == null) return; //Failed to load @@ -243,9 +248,9 @@ public class DiscordPlugin extends ButtonPlugin { try { SafeMode = true; // Stop interacting with Discord ChromaBot.delete(); - System.out.println("Updating presence..."); + timings.printElapsed("Updating presence..."); dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing - System.out.println("Logging out..."); + timings.printElapsed("Logging out..."); dc.logout().block(); //Configs are emptied so channels and servers are fetched again } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 011885a..4448f6e 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.Command2DCSender; +import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.TBMCCoreAPI; import discord4j.core.object.entity.Message; import discord4j.core.object.entity.MessageChannel; @@ -22,44 +23,44 @@ public class CommandListener { * @return Whether it did not run the command */ public static Mono runCommand(Message message, MessageChannel commandChannel, boolean mentionedonly) { + Timings timings = CommonListeners.timings; Mono ret = Mono.just(true); if (!message.getContent().isPresent()) return ret; //Pin messages and such, let the mcchat listener deal with it val content = message.getContent().get(); - System.out.println("A"); + timings.printElapsed("A"); return message.getChannel().flatMap(channel -> { Mono tmp = ret; if (!mentionedonly) { //mentionedonly conditions are in CommonListeners - System.out.println("B"); - //System.out.println("Channel type: " + commandChannel.getClass().getSimpleName()); - //System.out.println("Guild: " + ((TextChannel) commandChannel).getGuildId()); + timings.printElapsed("B"); if (!(channel instanceof PrivateChannel) && !(content.charAt(0) == DiscordPlugin.getPrefix() && channel.getId().asLong() == commandChannel.getId().asLong())) // return ret; - System.out.println("C"); + timings.printElapsed("C"); tmp = ret.then(channel.type()).thenReturn(true); // Fun (this true is ignored - x) } final StringBuilder cmdwithargs = new StringBuilder(content); val gotmention = new AtomicBoolean(); + timings.printElapsed("Before self"); return tmp.flatMapMany(x -> DiscordPlugin.dc.getSelf().flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) .flatMapMany(self -> { - System.out.println("D"); + timings.printElapsed("D"); gotmention.set(checkanddeletemention(cmdwithargs, self.getMention(), message)); gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention(), message) || gotmention.get()); val mentions = message.getRoleMentions(); return self.getRoles().filterWhen(r -> mentions.any(rr -> rr.getName().equals(r.getName()))) .map(Role::getMention); }).map(mentionRole -> { - System.out.println("E"); + timings.printElapsed("E"); gotmention.set(checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention.get()); // Delete all mentions return !mentionedonly || gotmention.get(); //Stops here if false }).switchIfEmpty(Mono.fromSupplier(() -> !mentionedonly || gotmention.get()))) .filter(b -> b).last(false).filter(b -> b).doOnNext(b -> channel.type().subscribe()).flatMap(b -> { String cmdwithargsString = cmdwithargs.toString(); try { - System.out.println("F"); + timings.printElapsed("F"); if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index e6275df..727c9f8 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.role.GameRoleModule; +import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import discord4j.core.event.EventDispatcher; @@ -19,6 +20,8 @@ import reactor.core.publisher.Mono; public class CommonListeners { + public static final Timings timings = new Timings(); + /* MentionEvent: - CommandListener (starts with mention, only 'channelcon' and not in #bot) @@ -30,14 +33,13 @@ public class CommonListeners { */ public static void register(EventDispatcher dispatcher) { dispatcher.on(MessageCreateEvent.class).flatMap(event -> { + timings.printElapsed("Message received"); val def = Mono.empty(); if (DiscordPlugin.SafeMode) return def; val author = event.getMessage().getAuthor(); if (!author.isPresent() || author.get().isBot()) return def; - //System.out.println("Author: "+author.get()); - //System.out.println("Bot: "+author.get().isBot()); if (FunModule.executeMemes(event.getMessage())) return def; val commandChannel = DiscordPlugin.plugin.commandChannel().get(); @@ -47,25 +49,20 @@ public class CommonListeners { || mch instanceof PrivateChannel || event.getMessage().getContent().orElse("").contains("channelcon"))) //Only 'channelcon' is allowed in other channels .filterWhen(ch -> { //Only continue if this doesn't handle the event - System.out.println("Run command 1"); + timings.printElapsed("Run command 1"); return CommandListener.runCommand(event.getMessage(), ch, true); //#bot is handled here }).filterWhen(ch -> { - System.out.println("mcchat"); + timings.printElapsed("mcchat"); val mcchat = Component.getComponents().get(MinecraftChatModule.class); if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again return ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels return Mono.empty(); //Wasn't handled, continue }).filterWhen(ch -> { - System.out.println("Run command 2"); + timings.printElapsed("Run command 2"); return CommandListener.runCommand(event.getMessage(), ch, false); }); }).onErrorContinue((err, obj) -> TBMCCoreAPI.SendException("An error occured while handling a message!", err)) .subscribe(); - /*dispatcher.on(MessageCreateEvent.class).doOnNext(x -> System.out.println("Got message")) - .flatMap(MessageCreateEvent::getGuild) - .flatMap(guild -> DiscordPlugin.dc.getSelf()) - .flatMap(self -> self.asMember(DiscordPlugin.mainServer.getId())) - .flatMap(Member::getRoles).subscribe(roles -> System.out.println("Roles: " + roles));*/ dispatcher.on(PresenceUpdateEvent.class).subscribe(event -> { if (DiscordPlugin.SafeMode) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 0dc7be8..f9429a9 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -8,7 +8,9 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordSender; import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.discordplugin.listeners.CommandListener; +import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; +import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.*; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.TBMCChatAPI; @@ -222,17 +224,18 @@ public class MCChatListener implements Listener { val ret = Mono.just(true); if (!ComponentManager.isEnabled(MinecraftChatModule.class)) return ret; - System.out.println("Chat event"); + Timings timings = CommonListeners.timings; + timings.printElapsed("Chat event"); val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId()); return ev.getMessage().getChannel().filter(channel -> { - System.out.println("Filter 1"); + timings.printElapsed("Filter 1"); return !(ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong() && !(channel instanceof PrivateChannel && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false) && !hasCustomChat)); //Chat isn't enabled on this channel }).filter(channel -> { - System.out.println("Filter 2"); + timings.printElapsed("Filter 2"); return !(channel instanceof PrivateChannel //Only in private chat && ev.getMessage().getContent().isPresent() && ev.getMessage().getContent().get().length() < "/mcchat<>".length() @@ -244,7 +247,7 @@ public class MCChatListener implements Listener { .filter(channel -> { MCChatUtils.resetLastMessage(channel); recevents.add(ev); - System.out.println("Message event added"); + timings.printElapsed("Message event added"); if (rectask != null) return true; recrun = () -> { //Don't return in a while loop next time diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index cbccc0d..31b625e 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -218,17 +218,14 @@ public class MCChatUtils { */ public static void resetLastMessage(Channel channel) { if (notEnabled()) return; - System.out.println("Reset last message"); if (channel.getId().asLong() == module.chatChannel().get().asLong()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(module.chatChannelMono().block(), null) : lastmsgdata).message = null; - System.out.println("Reset done: public chat"); return; } // Don't set the whole object to null, the player and channel information should be preserved for (LastMsgData data : channel instanceof PrivateChannel ? MCChatPrivate.lastmsgPerUser : MCChatCustom.lastmsgCustom) { if (data.channel.getId().asLong() == channel.getId().asLong()) { data.message = null; - System.out.println("Reset done: private/custom chat"); return; } } diff --git a/src/main/java/buttondevteam/discordplugin/util/Timings.java b/src/main/java/buttondevteam/discordplugin/util/Timings.java new file mode 100644 index 0000000..70697cf --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/util/Timings.java @@ -0,0 +1,16 @@ +package buttondevteam.discordplugin.util; + +import buttondevteam.discordplugin.DPUtils; + +public class Timings { + private long start; + + public Timings() { + start = System.nanoTime(); + } + + public void printElapsed(String message) { + DPUtils.getLogger().info(message + " (" + (System.nanoTime() - start) / 1000000L + ")"); + start = System.nanoTime(); + } +} From 547292911343a15a164cb223dc4dcc6d4383763a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 31 May 2019 00:38:28 +0200 Subject: [PATCH 21/24] Added, 5xFixed Added mcchat login/logout messages Only printing timings messages if debug is on Fixed #93 F i x e d Fixed command handled status Fixed debug command Fixed error reporting limit Fixed Discord YEEHAW --- pom.xml | 2 +- .../discordplugin/commands/DebugCommand.java | 6 +++++- .../discordplugin/exceptions/ExceptionListenerModule.java | 4 ++-- .../java/buttondevteam/discordplugin/fun/FunModule.java | 3 +++ .../discordplugin/listeners/CommandListener.java | 7 ++++--- .../discordplugin/listeners/CommonListeners.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 8 -------- .../buttondevteam/discordplugin/mcchat/MCChatUtils.java | 2 ++ .../buttondevteam/discordplugin/mcchat/MCListener.java | 6 ++++-- .../java/buttondevteam/discordplugin/util/Timings.java | 4 ++-- 10 files changed, 24 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index 987ff82..f0c321a 100755 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ io.netty - buttondevteam.discordplugin.io.netty + btndvtm.dp.io.netty diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index b678e62..b8c6b64 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -4,14 +4,18 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; +import reactor.core.publisher.Mono; @CommandClass(helpText = { "Switches debug mode." }) public class DebugCommand extends ICommand2DC { @Command2.Subcommand - public boolean def(Command2DCSender sender, String args) { + public boolean def(Command2DCSender sender) { sender.getMessage().getAuthorAsMember() + .switchIfEmpty(sender.getMessage().getAuthor() //Support DMs + .map(u -> u.asMember(DiscordPlugin.mainServer.getId())) + .orElse(Mono.empty())) .flatMap(m -> DiscordPlugin.plugin.modRole().get() .map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId())))) .subscribe(success -> { diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 45ac2c7..d57c313 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -66,8 +66,8 @@ public class ExceptionListenerModule extends Component implements String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) .filter(s -> !s.contains("\tat ") || s.contains("\tat buttondevteam.")) .collect(Collectors.joining("\n")); - if (sb.length() + stackTrace.length() >= 2000) - stackTrace = stackTrace.substring(0, 1999 - sb.length()); + if (sb.length() + stackTrace.length() >= 1980) + stackTrace = stackTrace.substring(0, 1980 - sb.length()); sb.append(stackTrace).append("\n"); sb.append("```"); return channel.flatMap(ch -> ch.createMessage(sb.toString())); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index c37536d..14b8a9b 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -25,6 +25,9 @@ import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; +/** + * The YEEHAW event uses an emoji named :YEEHAW: if available + */ public class FunModule extends Component implements Listener { private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali "Between now and the heat-death of the universe.", // Ghostise diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 4448f6e..45aa261 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -62,12 +62,13 @@ public class CommandListener { try { timings.printElapsed("F"); if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) - return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); + return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString) + .map(m -> false); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); } - return Mono.empty(); - }).map(m -> false).defaultIfEmpty(true); + return Mono.just(false); //If the command succeeded or there was an error, return false + }).defaultIfEmpty(true); }); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 727c9f8..08ed9ec 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -45,7 +45,7 @@ public class CommonListeners { val commandChannel = DiscordPlugin.plugin.commandChannel().get(); val commandCh = DPUtils.getMessageChannel(DiscordPlugin.plugin.commandChannel()); return commandCh.filterWhen(ch -> event.getMessage().getChannel().map(mch -> - commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong() //If mentioned, that's higher than chat + (commandChannel != null && mch.getId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat || mch instanceof PrivateChannel || event.getMessage().getContent().orElse("").contains("channelcon"))) //Only 'channelcon' is allowed in other channels .filterWhen(ch -> { //Only continue if this doesn't handle the event diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index f9429a9..aa7e278 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -269,14 +269,12 @@ public class MCChatListener implements Listener { rectask.cancel(); return; } - System.out.println("Processing..."); val sender = event.getMessage().getAuthor().orElse(null); String dmessage = event.getMessage().getContent().orElse(""); try { final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannelId(), sender); val user = dsender.getChromaUser(); - System.out.println("Mentions start"); for (User u : event.getMessage().getUserMentions().toIterable()) { //TODO: Role mentions dmessage = dmessage.replace(u.getMention(), "@" + u.getUsername()); // TODO: IG Formatting val m = u.asMember(DiscordPlugin.mainServer.getId()).block(); @@ -288,7 +286,6 @@ public class MCChatListener implements Listener { for (GuildChannel ch : event.getGuild().flux().flatMap(Guild::getChannels).toIterable()) { dmessage = dmessage.replace(ch.getMention(), "#" + ch.getName()); // TODO: IG Formatting } - System.out.println("Mentions end"); dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE); //Converts emoji to text- TODO: Add option to disable (resource pack?) dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:"); //Convert to Discord's format so it still shows up @@ -302,9 +299,7 @@ public class MCChatListener implements Listener { boolean react = false; - System.out.println("Getting channel..."); val sendChannel = event.getMessage().getChannel().block(); - System.out.println("Got channel"); boolean isPrivate = sendChannel instanceof PrivateChannel; if (dmessage.startsWith("/")) { // Ingame command if (!isPrivate) @@ -380,7 +375,6 @@ public class MCChatListener implements Listener { } } } else {// Not a command - System.out.println("Not a command"); if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 && !isPrivate && event.getMessage().getType() == Message.Type.CHANNEL_PINNED_MESSAGE) { val rtr = clmd != null ? clmd.mcchannel.getRTR(clmd.dcp) @@ -390,13 +384,11 @@ public class MCChatListener implements Listener { : dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL); } else { val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); - System.out.println("Message created"); if (clmd != null) TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel); else TBMCChatAPI.SendChatMessage(cmb.build()); react = true; - System.out.println("Message sent"); } } if (react) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 31b625e..92af87d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -332,6 +332,7 @@ public class MCChatUtils { } callEventExcludingSome(new PlayerJoinEvent(dcp, "")); dcp.setLoggedIn(true); + DPUtils.getLogger().info(dcp.getName() + " (" + dcp.getUniqueId() + ") logged in from Discord"); }); } @@ -347,6 +348,7 @@ public class MCChatUtils { if (needsSync) callEventSync(event); else callEventExcludingSome(event); dcp.setLoggedIn(false); + DPUtils.getLogger().info(dcp.getName() + " (" + dcp.getUniqueId() + ") logged out from Discord"); } static void callEventSync(Event event) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index fe68342..7c44627 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -25,6 +25,7 @@ import org.bukkit.event.server.BroadcastMessageEvent; import reactor.core.publisher.Mono; import java.util.Objects; +import java.util.Optional; @RequiredArgsConstructor class MCListener implements Listener { @@ -144,8 +145,9 @@ class MCListener implements Listener { String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO - DiscordPlugin.mainServer.getEmojis().filter(e -> "YEEHAW".equals(e.getName())).subscribe(yeehaw -> - MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getId().asString() + ">s" : " YEEHAWs")))); + DiscordPlugin.mainServer.getEmojis().filter(e -> "YEEHAW".equals(e.getName())) + .take(1).singleOrEmpty().map(Optional::of).defaultIfEmpty(Optional.empty()).subscribe(yeehaw -> + MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw.map(guildEmoji -> " <:YEEHAW:" + guildEmoji.getId().asString() + ">s").orElse(" YEEHAWs"))))); } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/util/Timings.java b/src/main/java/buttondevteam/discordplugin/util/Timings.java index 70697cf..12c12f2 100644 --- a/src/main/java/buttondevteam/discordplugin/util/Timings.java +++ b/src/main/java/buttondevteam/discordplugin/util/Timings.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin.util; -import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.listeners.CommonListeners; public class Timings { private long start; @@ -10,7 +10,7 @@ public class Timings { } public void printElapsed(String message) { - DPUtils.getLogger().info(message + " (" + (System.nanoTime() - start) / 1000000L + ")"); + CommonListeners.debug(message + " (" + (System.nanoTime() - start) / 1000000L + ")"); start = System.nanoTime(); } } From 939c6f4970c4dda17ce263e67a4abf06238b4f58 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 1 Jun 2019 02:27:40 +0200 Subject: [PATCH 22/24] Server ready fix & main server fix attempt --- .../buttondevteam/discordplugin/DiscordPlugin.java | 11 +++++++---- .../buttondevteam/discordplugin/fun/FunModule.java | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index b357f11..e08dbf3 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -65,8 +65,11 @@ public class DiscordPlugin extends ButtonPlugin { return plugin.prefix().get(); } - private ConfigData mainServer() { - return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong()); + private ConfigData> mainServer() { + return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, + id -> dc.getGuildById(Snowflake.of((long) id)) + .onErrorContinue((t, o) -> getLogger().warning("Failed to get guild: " + t)).blockOptional(), + g -> g.map(gg -> gg.getId().asLong()).orElse(0L)); } public ConfigData commandChannel() { @@ -130,7 +133,7 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { - mainServer = mainServer().get(); //Shouldn't change afterwards + mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); @@ -139,7 +142,7 @@ public class DiscordPlugin extends ButtonPlugin { } mainServer = event.get(0).getGuild(); getLogger().warning("Main server set to first one: " + mainServer.getName()); - mainServer().set(mainServer); //Save in config + mainServer().set(Optional.of(mainServer)); //Save in config } SafeMode = false; DPUtils.disableIfConfigError(null, commandChannel(), modRole()); //Won't disable, just prints the warning here diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 14b8a9b..fa5e7d3 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -108,7 +108,7 @@ public class FunModule extends Component implements Listener { if (usableServerReadyStrings.size() == 0) fm.createUsableServerReadyStrings(); next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); - DPUtils.reply(message, null, serverReadyStrings[next]).subscribe(); + DPUtils.reply(message, null, fm.serverReadyAnswers().get().get(next)).subscribe(); return false; //Still process it as a command/mcchat if needed } return false; From 9edfcf6a3d3bec85729a19337e55f7c782d73d96 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 5 Jun 2019 00:29:34 +0200 Subject: [PATCH 23/24] Main server fix, clean test OK WTF ID fixed --- .../buttondevteam/discordplugin/DPUtils.java | 38 +++++++++++++------ .../discordplugin/DiscordPlugin.java | 19 +++++++--- .../mcchat/MinecraftChatModule.java | 5 ++- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index a2902c3..616b750 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -102,20 +102,34 @@ public final class DPUtils { public static boolean disableIfConfigError(@Nullable Component component, ConfigData... configs) { for (val config : configs) { Object v = config.get(); - //noinspection ConstantConditions - if (v == null || (v instanceof Mono && !((Mono) v).hasElement().block())) { - String path = null; - try { - if (component != null) - Component.setComponentEnabled(component, false); - path = config.getPath(); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to disable component after config error!", e); - } - getLogger().warning("The config value " + path + " isn't set correctly " + (component == null ? "in global settings!" : "for component " + component.getClass().getSimpleName() + "!")); - getLogger().warning("Set the correct ID in the config" + (component == null ? "" : " or disable this component") + " to remove this message."); + if (disableIfConfigErrorRes(component, config, v)) return true; + } + return false; + } + + /** + * Disables the component if one of the given configs return null. Useful for channel/role configs. + * + * @param component The component to disable if needed + * @param config The (snowflake) config to check for null + * @param result The result of getting the value + * @return Whether the component got disabled and a warning logged + */ + public static boolean disableIfConfigErrorRes(@Nullable Component component, ConfigData config, Object result) { + //noinspection ConstantConditions + if (result == null || (result instanceof Mono && !((Mono) result).hasElement().block())) { + String path = null; + try { + if (component != null) + Component.setComponentEnabled(component, false); + path = config.getPath(); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to disable component after config error!", e); } + getLogger().warning("The config value " + path + " isn't set correctly " + (component == null ? "in global settings!" : "for component " + component.getClass().getSimpleName() + "!")); + getLogger().warning("Set the correct ID in the config" + (component == null ? "" : " or disable this component") + " to remove this message."); + return true; } return false; } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index e08dbf3..91dd6d1 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -66,9 +66,14 @@ public class DiscordPlugin extends ButtonPlugin { } private ConfigData> mainServer() { - return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, - id -> dc.getGuildById(Snowflake.of((long) id)) - .onErrorContinue((t, o) -> getLogger().warning("Failed to get guild: " + t)).blockOptional(), + return getIConfig().getDataPrimDef("mainServer", 0L, + id -> { + System.out.println("WTF ID: " + id); //TODO: It attempts to get the default as well + if ((long) id == 0L) + return Optional.empty(); //Hack? + return dc.getGuildById(Snowflake.of((long) id)) + .onErrorResume(t -> Mono.fromRunnable(() -> getLogger().warning("Failed to get guild: " + t.getMessage()))).blockOptional(); + }, g -> g.map(gg -> gg.getId().asLong()).orElse(0L)); } @@ -102,7 +107,7 @@ public class DiscordPlugin extends ButtonPlugin { File privateFile = new File(getDataFolder(), "private.yml"); val conf = YamlConfiguration.loadConfiguration(privateFile); token = conf.getString("token"); - if (token == null) { + if (token == null || token.equalsIgnoreCase("Token goes here")) { conf.set("token", "Token goes here"); conf.save(privateFile); @@ -133,7 +138,10 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { + System.out.println("w t f: " + mainServer); mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards + System.out.println("Main server: " + mainServer); + System.out.println("wtf: " + mainServer().get()); if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); @@ -182,7 +190,8 @@ public class DiscordPlugin extends ButtonPlugin { TBMCCoreAPI.SendException( "Won't load because we're in testing mode and not using a separate account.", new Exception( - "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in its name.)")); + "The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in its name.)" + + "\nYou can disable test mode in ThorpeCore config.")); Bukkit.getPluginManager().disablePlugin(this); } TBMCCoreAPI.SendUnsentExceptions(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 9e9bfd3..28e1e72 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -79,7 +79,8 @@ public class MinecraftChatModule extends Component { @Override protected void enable() { - if (DPUtils.disableIfConfigError(this, chatChannel())) return; + if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) + return; listener = new MCChatListener(this); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled @@ -113,6 +114,8 @@ public class MinecraftChatModule extends Component { new LPInjector(MainPlugin.Instance); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to init LuckPerms injector", e); + } catch (NoClassDefFoundError e) { + getPlugin().getLogger().info("No LuckPerms, not injecting"); } } From 34e3bb0ead4d910ac243e10a8675a3d72fe53889 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 6 Jun 2019 19:40:15 +0200 Subject: [PATCH 24/24] Debug cmd fix, mcchat fix, config error fix Also removed debug messages The Minecraft chat didn't run if the command channel was different The debug command didn't run if the mod role didn't exist --- .../discordplugin/DiscordPlugin.java | 11 ++++---- .../discordplugin/commands/DebugCommand.java | 3 ++- .../listeners/CommonListeners.java | 26 ++++++++++--------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 91dd6d1..b5a0efc 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -68,7 +68,7 @@ public class DiscordPlugin extends ButtonPlugin { private ConfigData> mainServer() { return getIConfig().getDataPrimDef("mainServer", 0L, id -> { - System.out.println("WTF ID: " + id); //TODO: It attempts to get the default as well + //It attempts to get the default as well if ((long) id == 0L) return Optional.empty(); //Hack? return dc.getGuildById(Snowflake.of((long) id)) @@ -81,6 +81,9 @@ public class DiscordPlugin extends ButtonPlugin { return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L); } + /** + * If the role doesn't exist, then it will only allow for the owner. + */ public ConfigData> modRole() { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); } @@ -138,10 +141,7 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { - System.out.println("w t f: " + mainServer); mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards - System.out.println("Main server: " + mainServer); - System.out.println("wtf: " + mainServer().get()); if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); @@ -153,7 +153,8 @@ public class DiscordPlugin extends ButtonPlugin { mainServer().set(Optional.of(mainServer)); //Save in config } SafeMode = false; - DPUtils.disableIfConfigError(null, commandChannel(), modRole()); //Won't disable, just prints the warning here + DPUtils.disableIfConfigErrorRes(null, commandChannel(), DPUtils.getMessageChannel(commandChannel())); + DPUtils.disableIfConfigError(null, modRole()); //Won't disable, just prints the warning here Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new MinecraftChatModule()); diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index b8c6b64..e1c0686 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -17,7 +17,8 @@ public class DebugCommand extends ICommand2DC { .map(u -> u.asMember(DiscordPlugin.mainServer.getId())) .orElse(Mono.empty())) .flatMap(m -> DiscordPlugin.plugin.modRole().get() - .map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId())))) + .map(mr -> m.getRoleIds().stream().anyMatch(r -> r.equals(mr.getId()))) + .switchIfEmpty(Mono.fromSupplier(() -> DiscordPlugin.mainServer.getOwnerId().asLong() == m.getId().asLong()))) //Role not found .subscribe(success -> { if (success) sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 08ed9ec..510e71a 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -47,20 +47,22 @@ public class CommonListeners { return commandCh.filterWhen(ch -> event.getMessage().getChannel().map(mch -> (commandChannel != null && mch.getId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat || mch instanceof PrivateChannel - || event.getMessage().getContent().orElse("").contains("channelcon"))) //Only 'channelcon' is allowed in other channels - .filterWhen(ch -> { //Only continue if this doesn't handle the event + || event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels + .flatMap(shouldRun -> { //Only continue if this doesn't handle the event + if (!shouldRun) + return Mono.just(true); //The condition is only for the first command execution, not mcchat timings.printElapsed("Run command 1"); return CommandListener.runCommand(event.getMessage(), ch, true); //#bot is handled here - }).filterWhen(ch -> { - timings.printElapsed("mcchat"); - val mcchat = Component.getComponents().get(MinecraftChatModule.class); - if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again - return ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels - return Mono.empty(); //Wasn't handled, continue - }).filterWhen(ch -> { - timings.printElapsed("Run command 2"); - return CommandListener.runCommand(event.getMessage(), ch, false); - }); + })).filterWhen(ch -> { + timings.printElapsed("mcchat"); + val mcchat = Component.getComponents().get(MinecraftChatModule.class); + if (mcchat != null && mcchat.isEnabled()) //ComponentManager.isEnabled() searches the component again + return ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); //Also runs Discord commands in chat channels + return Mono.empty(); //Wasn't handled, continue + }).filterWhen(ch -> { + timings.printElapsed("Run command 2"); + return CommandListener.runCommand(event.getMessage(), ch, false); + }); }).onErrorContinue((err, obj) -> TBMCCoreAPI.SendException("An error occured while handling a message!", err)) .subscribe(); dispatcher.on(PresenceUpdateEvent.class).subscribe(event -> {