From 2229f1dd9b36c8bb515a48a2acab9c3b57a3bdd1 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 7 Jun 2018 21:33:35 +0200 Subject: [PATCH 001/108] Update Discord4J --- pom.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 43ce4d1..a6477af 100644 --- a/pom.xml +++ b/pom.xml @@ -151,12 +151,11 @@ 1.12.2-R0.1-SNAPSHOT provided + - com.github.austinv11 - Discord4j - master-SNAPSHOT - + com.discord4j + Discord4J + 2.10.1 -- 2.30.2 From 23d7e3437281d77a4f15a27f14d85cff9ec2c0b9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 15 Jun 2018 20:07:24 +0200 Subject: [PATCH 002/108] Fix update dir --- deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.sh b/deploy.sh index a40b486..82c8e92 100755 --- a/deploy.sh +++ b/deploy.sh @@ -6,5 +6,5 @@ if [ $1 = 'production' ]; then echo Production mode echo $UPLOAD_KEY > upload_key chmod 400 upload_key -yes | scp -B -i upload_key -o StrictHostKeyChecking=no $FILENAME travis@server.figytuna.com:/minecraft/main/pluginupdates +yes | scp -B -i upload_key -o StrictHostKeyChecking=no $FILENAME travis@server.figytuna.com:/minecraft/main/TBMC/pluginupdates fi -- 2.30.2 From 862fdcb4e6da3e50d7e73fea167eac19e729834c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Jun 2018 23:08:47 +0200 Subject: [PATCH 003/108] Create ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..0ed954a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,9 @@ +**Description:** + +**Steps to Reproduce:** + +1. + +**Result:** + +**Expected Result:** -- 2.30.2 From 5c6a62f34de2688b3e4d2cfb8444a428d75e81f9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 22 Jun 2018 11:45:15 +0200 Subject: [PATCH 004/108] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 701765f..59aa0de 100755 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ # DiscordPlugin -A plugin that controls the Chroma Bot Discord bot. +A plugin that controls the ChromaBot Discord bot and provides Minecraft chat functionality and other features. ## Features ### Announce new posts from /r/ChromaGamers If it's a (distinguished) moderator post, it'll be posted to the \#announcements channel, otherwise it'll be posted and pinned to \#general. ### Announce server restarts -Currently it only says when the server starts up but that's about to change soon... +It announces server starts/stops and restarts, as well as if the server shut down unexpectedly. -## Planned and work-in-progress features -See [here](https://github.com/TBMCPlugins/DiscordPlugin/projects/1). +**For more, see:** http://chromapedia.wikia.com/wiki/ChromaBot -- 2.30.2 From 735f6d408599fc5cac1b3ee77e80dddcbbed36c7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 23 Jun 2018 21:53:52 +0200 Subject: [PATCH 005/108] Fix #59 --- .../buttondevteam/discordplugin/listeners/CommandListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 76ae457..1db1fdc 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -144,6 +144,8 @@ public class CommandListener { if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); } else { + if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + return; boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color if (removed) -- 2.30.2 From 38ef88f10d20b8e8175efe517dd56d14a155c552 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 2 Jul 2018 15:56:36 +0200 Subject: [PATCH 006/108] Add ButtonCore dependency And remove PEX dependency --- pom.xml | 32 ++++++++++++++++---------------- src/main/resources/plugin.yml | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index a6e0b14..5c69674 100755 --- a/pom.xml +++ b/pom.xml @@ -126,10 +126,10 @@ projectlombok.org http://projectlombok.org/mavenrepo - - pex-repo - http://pex-repo.aoeu.xyz - + @@ -193,18 +193,18 @@ 1.16.16 provided - - ru.tehkode - PermissionsEx - 1.23.1 - provided - - - org.bukkit - bukkit - - - + org.objenesis diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 85bbe30..5b218e7 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,6 +2,6 @@ name: DiscordPlugin main: buttondevteam.discordplugin.DiscordPlugin version: 1.0 author: TBMCPlugins -depend: [] +depend: [ButtonCore] commands: discord: -- 2.30.2 From e718fafd52dfe2d1f5396b7c21da6990901b3ea9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 15 Jul 2018 01:14:04 +0200 Subject: [PATCH 007/108] Added API changes --- .../discordplugin/listeners/MCChatListener.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index d4a3ce9..b5ff177 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -7,6 +7,7 @@ import buttondevteam.lib.TBMCChatPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Channel; +import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; @@ -478,10 +479,11 @@ public class MCChatListener implements Listener, IListener + DPUtils.sanitizeString(dsender.getMcchannel().DisplayName)); } else { // Send single message final String msg = event.getMessage().getContent().substring(spi + 2); + val cmb = ChatMessage.builder(chc, dsender, user, getChatMessage.apply(msg)).fromCommand(true); if (clmd == null) - TBMCChatAPI.SendChatMessage(chc, dsender, getChatMessage.apply(msg), true); + TBMCChatAPI.SendChatMessage(cmb.build()); else - TBMCChatAPI.SendChatMessageDontCheckSender(chc, dsender, getChatMessage.apply(msg), true, clmd.dcp); + TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build()); react = true; } } @@ -495,10 +497,11 @@ public class MCChatListener implements Listener, IListener (dsender instanceof Player ? ((Player) dsender).getDisplayName() : dsender.getName()) + " pinned a message on Discord."); else { + val cmb = ChatMessage.builder(dsender.getMcchannel(), dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); if (clmd != null) - TBMCChatAPI.SendChatMessageDontCheckSender(clmd.mcchannel, dsender, getChatMessage.apply(dmessage), false, clmd.dcp); + TBMCChatAPI.SendChatMessage(cmb.channel(clmd.mcchannel).permCheck(clmd.dcp).build()); else - TBMCChatAPI.SendChatMessage(dsender.getMcchannel(), dsender, getChatMessage.apply(dmessage)); + TBMCChatAPI.SendChatMessage(cmb.build()); react = true; } } @@ -546,7 +549,8 @@ public class MCChatListener implements Listener, IListener cmd = dmessage.substring(0, index); for (Channel channel : Channel.getChannels()) { if (cmd.equalsIgnoreCase(channel.ID) || (channel.IDs != null && Arrays.stream(channel.IDs).anyMatch(cmd::equalsIgnoreCase))) { - TBMCChatAPI.SendChatMessage(channel, dsender, dmessage.substring(index + 1)); + val dp = DiscordPlayer.getUser(dsender.getUser().getStringID(), DiscordPlayer.class); + TBMCChatAPI.SendChatMessage(ChatMessage.builder(channel, dsender, dp, dmessage.substring(index + 1)).build()); return true; } } -- 2.30.2 From de857fef0bfa4953f23744b7bccbb2c5f7365313 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 19 Jul 2018 00:39:17 +0200 Subject: [PATCH 008/108] Channelcon&chat&other fixes #58 fixed Made checkmarks stored separately per channel #55 fixed Correctly handling interrupt events, a local bug might have been fixed where the server didn't always stop. Added a reset command Needs testing --- .../buttondevteam/discordplugin/DPUtils.java | 11 +--- .../discordplugin/DiscordPlugin.java | 62 +++++++++-------- .../commands/ConnectCommand.java | 2 +- .../listeners/MCChatListener.java | 66 ++++++++++++++----- .../mccommands/ResetMCCommand.java | 35 ++++++++++ 5 files changed, 121 insertions(+), 55 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index abc1f8f..25adff8 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -1,6 +1,5 @@ package buttondevteam.discordplugin; -import buttondevteam.lib.TBMCCoreAPI; import org.bukkit.Bukkit; import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.RequestBuffer; @@ -9,6 +8,7 @@ import sx.blah.discord.util.RequestBuffer.IVoidRequest; import javax.annotation.Nullable; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public final class DPUtils { @@ -39,18 +39,13 @@ public final class DPUtils { * 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) { + public static T perform(IRequest action, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { if (DiscordPlugin.SafeMode) return null; if (Thread.currentThread() == DiscordPlugin.mainThread) // TODO: Ignore shutdown message <-- // throw new RuntimeException("Tried to wait for a Discord request on the main thread. This could cause lag."); Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!"); - try { - return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this - } catch (Exception e) { - TBMCCoreAPI.SendException("Couldn't perform Discord action!", e); - return null; - } + return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 170c789..c5e6ded 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -15,6 +15,7 @@ import com.google.gson.JsonParser; import lombok.val; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -35,6 +36,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; public class DiscordPlugin extends JavaPlugin implements IListener { @@ -210,16 +212,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - new Thread(this::AnnouncementGetterThreadMethod).start(); + new Thread(this::AnnouncementGetterThreadMethod).start(); //TODO: Handle relogging (test) setupProviders(); - /* - * IDiscordOAuth doa = new DiscordOAuthBuilder(dc).withClientID("226443037893591041") .withClientSecret(getConfig().getString("appsecret")) .withRedirectUrl("https://" + - * (TBMCCoreAPI.IsTestServer() ? "localhost" : "server.figytuna.com") + ":8081/callback") .withScopes(Scope.IDENTIFY).withHttpServerOptions(new HttpServerOptions().setPort(8081)) - * .withSuccessHandler((rc, user) -> { rc.response().headers().add("Location", "https://" + (TBMCCoreAPI.IsTestServer() ? "localhost" : "server.figytuna.com") + ":8080/login?type=discord&" - * + rc.request().query()); rc.response().setStatusCode(303); rc.response().end("Redirecting"); rc.response().close(); }).withFailureHandler(rc -> { rc.response().headers().add("Location", - * "https://" + (TBMCCoreAPI.IsTestServer() ? "localhost" : "server.figytuna.com") + ":8080/login?type=discord&" + rc.request().query()); rc.response().setStatusCode(303); - * rc.response().end("Redirecting"); rc.response().close(); }).build(); getLogger().info("Auth URL: " + doa.buildAuthUrl()); - */ } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); } @@ -260,22 +254,28 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } saveConfig(); - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannelWait(ch, "", - 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(p -> p.getDisplayName()).collect(Collectors.joining(", "))) - + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") - + "asked *politely* to leave the server for a bit.") - : "") - .build(), 5, TimeUnit.SECONDS)); + MCChatListener.forAllMCChat(ch -> { + try { + DiscordPlugin.sendMessageToChannelWait(ch, "", + 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 ") + + "asked *politely* to leave the server for a bit.") + : "") + .build(), 5, TimeUnit.SECONDS); + } catch (TimeoutException | InterruptedException e) { + e.printStackTrace(); + } + }); ChromaBot.getInstance().updatePlayerList(); try { SafeMode = true; // Stop interacting with Discord - MCChatListener.stop(); + MCChatListener.stop(true); ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); @@ -359,26 +359,30 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } public static void sendMessageToChannel(IChannel channel, String message, EmbedObject embed) { - sendMessageToChannel(channel, message, embed, false); + try { + sendMessageToChannel(channel, message, embed, false); + } catch (TimeoutException | InterruptedException e) { + e.printStackTrace(); //Shouldn't happen, as we're not waiting on the result + } } - public static IMessage sendMessageToChannelWait(IChannel channel, String message) { + 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) { + 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) { + 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) { + 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) { + 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); Bukkit.getLogger() @@ -404,6 +408,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { DPUtils.performNoWait(r); return null; } + } catch (TimeoutException | InterruptedException e) { + throw e; } catch (Exception e) { Bukkit.getLogger().warning( "Failed to deliver message to Discord! Channel: " + channel.getName() + " Message: " + message); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index 670b522..a339c4d 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -27,7 +27,7 @@ public class ConnectCommand extends DiscordCommandBase { @Override public boolean run(IMessage message, String args) { if (args.length() == 0) - return true; + return false; if (args.contains(" ")) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "Too many arguments.\nUsage: connect "); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index b5ff177..12d706b 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -12,6 +12,7 @@ import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; +import io.netty.util.collection.LongObjectHashMap; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.val; @@ -38,6 +39,7 @@ import java.time.Instant; import java.util.*; import java.util.List; 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; @@ -53,7 +55,7 @@ public class MCChatListener implements Listener, IListener @EventHandler // Minecraft public void onMCChat(TBMCChatEvent ev) { - if (ev.isCancelled()) + if (DiscordPlugin.SafeMode || ev.isCancelled()) //SafeMode: Needed so it doesn't restart after server shutdown return; sendevents.add(new AbstractMap.SimpleEntry<>(ev, Instant.now())); if (sendtask != null) @@ -71,15 +73,10 @@ public class MCChatListener implements Listener, IListener try { TBMCChatEvent e; Instant time; - try { - val se = sendevents.take(); // Wait until an element is available - e = se.getKey(); - time = se.getValue(); - } catch (InterruptedException ex) { - sendtask.cancel(); - sendtask = null; - return; - } + val se = sendevents.take(); // Wait until an element is available + e = se.getKey(); + time = se.getValue(); + final String authorPlayer = "[" + DPUtils.sanitizeString(e.getChannel().DisplayName) + "] " // + (e.getSender() instanceof DiscordSenderBase ? "[D]" : "") // + (DPUtils.sanitizeString(e.getSender() instanceof Player // @@ -102,7 +99,7 @@ public class MCChatListener implements Listener, IListener // embed.withFooterText(e.getChannel().DisplayName); embed.withTimestamp(time); final long nanoTime = System.nanoTime(); - Consumer doit = lastmsgdata -> { + InterruptibleConsumer doit = lastmsgdata -> { final EmbedObject embedObject = embed.build(); if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) @@ -144,14 +141,19 @@ public class MCChatListener implements Listener, IListener while (iterator.hasNext()) { //TODO: Add cmd to fix mcchat val lmd = iterator.next(); if ((e.isFromcmd() || 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 - if (e.shouldSendTo(lmd.dcp) && e.getGroupID().equals(lmd.groupID)) //Check original user's permissions + && 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); } @@ -216,6 +218,7 @@ public class MCChatListener implements Listener, IListener * Used for town or nation chats or anything else */ private static ArrayList lastmsgCustom = new ArrayList<>(); + private static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) { TBMCPlayer mcp = dp.getAs(TBMCPlayer.class); @@ -233,6 +236,8 @@ public class MCChatListener implements Listener, IListener MCListener.callEventExcludingSome(new PlayerQuitEvent(sender, "")); } } + if (!start) + lastmsgfromd.remove(channel.getLongID()); return start // ? lastmsgPerUser.add(new LastMsgData(channel, user, dp)) // Doesn't support group DMs : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); @@ -273,6 +278,7 @@ public class MCChatListener implements Listener, IListener } public static boolean removeCustomChat(IChannel channel) { + lastmsgfromd.remove(channel.getLongID()); return lastmsgCustom.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); } @@ -337,14 +343,32 @@ public class MCChatListener implements Listener, IListener .map(data -> data.channel).forEach(action); } - public static void stop() { + /** + * 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); + } + } catch (InterruptedException e) { + e.printStackTrace(); //This thread shouldn't be interrupted + } } private BukkitTask rectask; private LinkedBlockingQueue recevents = new LinkedBlockingQueue<>(); - private IMessage lastmsgfromd; // Last message sent by a Discord user, used for clearing checkmarks private Runnable recrun; private static Thread recthread; @@ -507,14 +531,15 @@ public class MCChatListener implements Listener, IListener } if (react) { try { - if (lastmsgfromd != null) { - DPUtils.perform(() -> lastmsgfromd.removeReaction(DiscordPlugin.dc.getOurUser(), + val lmfd = 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); } - lastmsgfromd = event.getMessage(); + lastmsgfromd.put(event.getChannel().getLongID(), event.getMessage()); DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION)); } } catch (Exception e) { @@ -573,4 +598,9 @@ public class MCChatListener implements Listener, IListener return Optional.of(dsender); }).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); } + + @FunctionalInterface + private interface InterruptibleConsumer { + void accept(T value) throws TimeoutException, InterruptedException; + } } diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java new file mode 100644 index 0000000..5d571a7 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java @@ -0,0 +1,35 @@ +package buttondevteam.discordplugin.mccommands; + +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.listeners.MCChatListener; +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 + @Override + public boolean OnCommand(CommandSender sender, String s, String[] strings) { + Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { + sender.sendMessage("§bStopping MCChatListener..."); + DiscordPlugin.SafeMode = true; + MCChatListener.stop(true); + if (DiscordPlugin.dc.isLoggedIn()) { + sender.sendMessage("§bLogging out..."); + DiscordPlugin.dc.logout(); + } else + sender.sendMessage("§bWe're not logged in."); + sender.sendMessage("§bLogging in..."); + DiscordPlugin.dc.login(); + DiscordPlugin.SafeMode = false; + sender.sendMessage("§bChromaBot has been reset!"); + }); + return false; + } + + @Override + public String[] GetHelpText(String s) { + return new String[0]; + } +} -- 2.30.2 From 557eac2292620cf9fc3e8dc723478acbd1a06d79 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 20 Jul 2018 12:43:17 +0200 Subject: [PATCH 009/108] Reset command fixes Now it's disabling and enabling the plugin Some changes were made to handle this as well Fixed main thread checks, the plugin may not be enabled in the main thread --- .../buttondevteam/discordplugin/DPUtils.java | 6 +-- .../discordplugin/DiscordPlugin.java | 45 ++++++++++++------- .../listeners/MCChatListener.java | 10 ++++- .../mccommands/ResetMCCommand.java | 27 +++++------ 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 25adff8..89c0b82 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -42,7 +42,7 @@ public final class DPUtils { public static T perform(IRequest action, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { if (DiscordPlugin.SafeMode) return null; - if (Thread.currentThread() == DiscordPlugin.mainThread) // TODO: Ignore shutdown message <-- + 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."); Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!"); return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this @@ -55,7 +55,7 @@ public final class DPUtils { public static T perform(IRequest action) { if (DiscordPlugin.SafeMode) return null; - if (Thread.currentThread() == DiscordPlugin.mainThread) // TODO: Ignore shutdown message <-- + 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."); Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!"); return RequestBuffer.request(action).get(); // Let the pros handle this @@ -67,7 +67,7 @@ public final class DPUtils { public static Void perform(IVoidRequest action) { if (DiscordPlugin.SafeMode) return null; - if (Thread.currentThread() == DiscordPlugin.mainThread) + 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 } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index c5e6ded..9ed6232 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.listeners.*; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; +import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.TBMCChatAPI; @@ -42,7 +43,6 @@ import java.util.stream.Collectors; public class DiscordPlugin extends JavaPlugin implements IListener { private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; private static boolean stop = false; - static Thread mainThread; public static IDiscordClient dc; public static DiscordPlugin plugin; public static boolean SafeMode = true; @@ -52,6 +52,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { @SuppressWarnings("unchecked") @Override public void onEnable() { + stop = false; //If not the first time try { Bukkit.getLogger().info("Initializing DiscordPlugin..."); try { @@ -69,7 +70,6 @@ public class DiscordPlugin extends JavaPlugin implements IListener { cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); dc = cb.login(); dc.getDispatcher().registerListener(this); - mainThread = Thread.currentThread(); } catch (Exception e) { e.printStackTrace(); Bukkit.getPluginManager().disablePlugin(this); @@ -105,7 +105,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } if (mainServer == null || devServer == null) return; // Retry - if (!TBMCCoreAPI.IsTestServer()) { + if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() botchannel = mainServer.getChannelByID(209720707188260864L); // bot annchannel = mainServer.getChannelByID(126795071927353344L); // announcements genchannel = mainServer.getChannelByID(125813020357165056L); // general @@ -157,7 +157,10 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } DiscordCommandBase.registerCommands(); - if (getConfig().getBoolean("serverup", false)) { + if (ResetMCCommand.resetting) + ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.CYAN) + .withTitle("Discord plugin restarted - chat connected.").build()); //Really important to note the chat, hmm + else if (getConfig().getBoolean("serverup", false)) { ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.YELLOW) .withTitle("Server recovered from a crash - chat connected.").build()); val thr = new Throwable( @@ -167,6 +170,9 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } else ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.GREEN) .withTitle("Server started - chat connected.").build()); + + ResetMCCommand.resetting = false; //This is the last event handling this flag + getConfig().set("serverup", true); saveConfig(); DPUtils.performNoWait(() -> { @@ -237,6 +243,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { stop = true; for (val entry : MCChatListener.ConnectedSenders.entrySet()) MCListener.callEventExcludingSome(new PlayerQuitEvent(entry.getValue(), "")); + MCChatListener.ConnectedSenders.clear(); getConfig().set("lastannouncementtime", lastannouncementtime); getConfig().set("lastseentime", lastseentime); getConfig().set("serverup", false); @@ -256,18 +263,22 @@ public class DiscordPlugin extends JavaPlugin implements IListener { saveConfig(); MCChatListener.forAllMCChat(ch -> { try { - DiscordPlugin.sendMessageToChannelWait(ch, "", - 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 ") - + "asked *politely* to leave the server for a bit.") - : "") - .build(), 5, TimeUnit.SECONDS); + if (ResetMCCommand.resetting) + DiscordPlugin.sendMessageToChannelWait(ch, "", + new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build()); + else + DiscordPlugin.sendMessageToChannelWait(ch, "", + 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 ") + + "asked *politely* to leave the server for a bit.") + : "") + .build(), 5, TimeUnit.SECONDS); } catch (TimeoutException | InterruptedException e) { e.printStackTrace(); } @@ -279,6 +290,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); + mainServer = devServer = null; //Fetch servers and channels again + sent = false; } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 12d706b..49bcf63 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -138,7 +138,7 @@ public class MCChatListener implements Listener, IListener } val iterator = lastmsgCustom.iterator(); - while (iterator.hasNext()) { //TODO: Add cmd to fix mcchat + while (iterator.hasNext()) { val lmd = iterator.next(); if ((e.isFromcmd() || 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 @@ -362,6 +362,14 @@ public class MCChatListener implements Listener, IListener if (wait) recthread.join(5000); } + lastmsgdata = null; + lastmsgPerUser.clear(); + lastmsgCustom.clear(); + lastmsgfromd.clear(); + ConnectedSenders.clear(); + lastlist = lastlistp = ListC = 0; + UnconnectedSenders.clear(); + recthread = sendthread = null; } catch (InterruptedException e) { e.printStackTrace(); //This thread shouldn't be interrupted } diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java index 5d571a7..dcfd00d 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java @@ -1,7 +1,6 @@ package buttondevteam.discordplugin.mccommands; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.TBMCCommandBase; import org.bukkit.Bukkit; @@ -9,27 +8,25 @@ 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, () -> { - sender.sendMessage("§bStopping MCChatListener..."); - DiscordPlugin.SafeMode = true; - MCChatListener.stop(true); - if (DiscordPlugin.dc.isLoggedIn()) { - sender.sendMessage("§bLogging out..."); - DiscordPlugin.dc.logout(); - } else - sender.sendMessage("§bWe're not logged in."); - sender.sendMessage("§bLogging in..."); - DiscordPlugin.dc.login(); - DiscordPlugin.SafeMode = false; - sender.sendMessage("§bChromaBot has been reset!"); + resetting = true; //Turned off after sending enable message (ReadyEvent) + sender.sendMessage("§bDisabling DiscordPlugin..."); + Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); + sender.sendMessage("§bEnabling DiscordPlugin..."); + Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin); + sender.sendMessage("§bReset finished!"); }); - return false; + return true; } @Override public String[] GetHelpText(String s) { - return new String[0]; + return new String[]{ // + "§6---- Reset ChromaBot ----", // + "This command stops the Minecraft chat and relogs the bot." // + }; } } -- 2.30.2 From 4f6612c21bb818d5ca21a17888c1d830d38869ce Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 20 Jul 2018 13:18:33 +0200 Subject: [PATCH 010/108] Updated help text --- src/main/java/buttondevteam/discordplugin/DiscordPlugin.java | 2 +- .../buttondevteam/discordplugin/mccommands/ResetMCCommand.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 9ed6232..34669c4 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -218,7 +218,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - new Thread(this::AnnouncementGetterThreadMethod).start(); //TODO: Handle relogging (test) + new Thread(this::AnnouncementGetterThreadMethod).start(); setupProviders(); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java index dcfd00d..fce8d04 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java @@ -26,7 +26,7 @@ public class ResetMCCommand extends TBMCCommandBase { //Not player-only, so not public String[] GetHelpText(String s) { return new String[]{ // "§6---- Reset ChromaBot ----", // - "This command stops the Minecraft chat and relogs the bot." // + "This command disables and then enables the plugin." // }; } } -- 2.30.2 From d22b6dec8094eb571ce7ac25e20f5d297f4e1fee Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 22 Jul 2018 00:26:22 +0200 Subject: [PATCH 011/108] Only sending join/leave events to custom chats Also sending server start/stop messages still #57 I need to look over this freshly --- .../discordplugin/ChromaBot.java | 12 +++++++++- .../discordplugin/DiscordPlugin.java | 8 +++---- .../listeners/MCChatListener.java | 22 ++++++++++++++----- .../discordplugin/listeners/MCListener.java | 10 +++++++-- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index e597095..2db1a17 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -47,7 +47,7 @@ public class ChromaBot { /** * Send a message to the chat channels and private chats. - * + * * @param message * The message to send, duh * @param embed @@ -57,6 +57,16 @@ public class ChromaBot { MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); } + /** + * 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 + */ + public void sendMessageCustomAsWell(String message, EmbedObject embed) { + MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); + } + /** * Send a message to an arbitrary channel. This will not send it to the private chats. * diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 34669c4..d126523 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -158,17 +158,17 @@ public class DiscordPlugin extends JavaPlugin implements IListener { DiscordCommandBase.registerCommands(); if (ResetMCCommand.resetting) - ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.CYAN) + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) .withTitle("Discord plugin restarted - chat connected.").build()); //Really important to note the chat, hmm else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.YELLOW) + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.YELLOW) .withTitle("Server recovered from a crash - chat connected.").build()); 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().sendMessage("", new EmbedBuilder().withColor(Color.GREEN) + ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.GREEN) .withTitle("Server started - chat connected.").build()); ResetMCCommand.resetting = false; //This is the last event handling this flag @@ -261,7 +261,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { } saveConfig(); - MCChatListener.forAllMCChat(ch -> { + MCChatListener.forCustomAndAllMCChat(ch -> { try { if (ResetMCCommand.resetting) DiscordPlugin.sendMessageToChannelWait(ch, "", diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 49bcf63..89f02be 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -2,10 +2,7 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; -import buttondevteam.lib.TBMCChatEvent; -import buttondevteam.lib.TBMCChatPreprocessEvent; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.*; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; @@ -17,6 +14,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -255,8 +253,7 @@ public class MCChatListener implements Listener, IListener // The maps may not contain the senders for UnconnectedSenders public static boolean isMinecraftChatEnabled(DiscordPlayer dp) { - return lastmsgPerUser.stream().anyMatch( - lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(dp.getDiscordID())); + return isMinecraftChatEnabled(dp.getDiscordID()); } public static boolean isMinecraftChatEnabled(String did) { // Don't load the player data just for this @@ -330,9 +327,22 @@ public class MCChatListener implements Listener, IListener action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : lastmsgPerUser) action.accept(data.channel); + // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat + } + + public static void forCustomAndAllMCChat(Consumer action) { + forAllMCChat(action); lastmsgCustom.forEach(cc -> action.accept(cc.channel)); } + public static void forAllowedCustomMCChat(Consumer action, CommandSender sender) { + lastmsgCustom.stream().filter(clmd -> { + //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple + val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); + return clmd.groupID.equals(e.getGroupID(sender)); + }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect + } + private static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) action.accept(DiscordPlugin.chatchannel); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 74ee6a2..2a86220 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -62,8 +62,10 @@ public class MCListener implements Listener { + " do /discord accept"); p.sendMessage("§bIf it wasn't you, do /discord decline"); } + final String message = e.GetPlayer().PlayerName().get() + " joined the game"; if (!DiscordPlugin.hooked) - MCChatListener.sendSystemMessageToChat(e.GetPlayer().PlayerName().get() + " joined the game"); + MCChatListener.sendSystemMessageToChat(message); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer()); MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); }); @@ -81,6 +83,10 @@ public class MCListener implements Listener { .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); + final String message = e.GetPlayer().PlayerName().get() + " left the game"; + if (!DiscordPlugin.hooked) + MCChatListener.sendSystemMessageToChat(message); //TODO: Probably double sends if kicked and unhooked + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer()); } @EventHandler(priority = EventPriority.HIGHEST) @@ -111,7 +117,7 @@ public class MCListener implements Listener { } @EventHandler - public void onPlayerAFK(AfkStatusChangeEvent e) { + public void onPlayerAFK(AfkStatusChangeEvent e) { //TODO: Add AFK to custom chats? if (e.isCancelled() || !e.getAffected().getBase().isOnline()) return; MCChatListener.sendSystemMessageToChat(DPUtils.sanitizeString(e.getAffected().getBase().getDisplayName()) -- 2.30.2 From 4507cf38a9377a578ca6b2baf4d754c69f90099e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 22 Jul 2018 13:11:24 +0200 Subject: [PATCH 012/108] Fixed channelcon echo The senders are now stored per-channel #56 This one took a bit to track down --- lombok.config | 1 + .../discordplugin/DiscordPlugin.java | 3 +- .../listeners/MCChatListener.java | 55 +- .../discordplugin/listeners/MCListener.java | 12 +- .../mccommands/AcceptMCCommand.java | 2 +- .../playerfaker/DiscordFakePlayer.java | 1079 +++++++++-------- 6 files changed, 593 insertions(+), 559 deletions(-) create mode 100644 lombok.config diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..4f55f03 --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.var.flagUsage = ALLOW \ No newline at end of file diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index d126523..1b91494 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -242,7 +242,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { public void onDisable() { stop = true; for (val entry : MCChatListener.ConnectedSenders.entrySet()) - MCListener.callEventExcludingSome(new PlayerQuitEvent(entry.getValue(), "")); + for (val valueEntry : entry.getValue().entrySet()) + MCListener.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); MCChatListener.ConnectedSenders.clear(); getConfig().set("lastannouncementtime", lastannouncementtime); getConfig().set("lastseentime", lastseentime); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 89f02be..393221a 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -12,6 +12,7 @@ import com.vdurmont.emoji.EmojiParser; import io.netty.util.collection.LongObjectHashMap; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.experimental.var; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -225,11 +226,11 @@ public class MCChatListener implements Listener, IListener val op = Bukkit.getOfflinePlayer(mcp.getUUID()); if (start) { val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); - ConnectedSenders.put(user.getStringID(), sender); + addSender(ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence MCListener.callEventExcludingSome(new PlayerJoinEvent(sender, "")); } else { - val sender = ConnectedSenders.remove(user.getStringID()); + val sender = removeSender(ConnectedSenders, channel, user); if (p == null)// Player is offline - If the player is online, that takes precedence MCListener.callEventExcludingSome(new PlayerQuitEvent(sender, "")); } @@ -241,6 +242,37 @@ public class MCChatListener implements Listener, IListener : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); } + public static T addSender(HashMap> senders, + IUser user, T sender) { + return addSender(senders, user.getStringID(), sender); + } + + 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); + senders.put(did, map); + return sender; + } + + public static T getSender(HashMap> senders, + IChannel channel, IUser user) { + var map = senders.get(user.getStringID()); + 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()); + if (map != null) + return map.remove(channel); + return null; + } + // ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender // Offline public chat......x............................................ // Online public chat.......x...........................................x @@ -286,12 +318,12 @@ public class MCChatListener implements Listener, IListener /** * 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<>(); public static short ListC = 0; public static void resetLastMessage() { @@ -606,14 +638,13 @@ public class MCChatListener implements Listener, IListener * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. */ private static DiscordSenderBase getSender(IChannel channel, final IUser author) { - val key = (channel.isPrivate() ? "" : "P") + author.getStringID(); + val key = author.getStringID(); return Stream.>>of( // https://stackoverflow.com/a/28833677/2703239 - () -> Optional.ofNullable(OnlineSenders.get(key)), // Find first non-null - () -> Optional.ofNullable(ConnectedSenders.get(key)), // This doesn't support the public chat, but it'll always return null for it - () -> Optional.ofNullable(UnconnectedSenders.get(key)), () -> { - val dsender = new DiscordSender(author, channel); - UnconnectedSenders.put(key, dsender); - return Optional.of(dsender); + () -> 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(OnlineSenders, channel, author)), () -> { + return Optional.of(addSender(UnconnectedSenders, author, + new DiscordSender(author, channel))); }).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 2a86220..8eab392 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -36,7 +36,7 @@ public class MCListener implements Listener { public void onPlayerLogin(PlayerLoginEvent e) { if (e.getResult() != Result.ALLOWED) return; - MCChatListener.ConnectedSenders.values().stream() + MCChatListener.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 -> callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); } @@ -50,10 +50,10 @@ public class MCListener implements Listener { DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); if (dp != null) { val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); - MCChatListener.OnlineSenders.put(dp.getDiscordID(), + MCChatListener.addSender(MCChatListener.OnlineSenders, dp.getDiscordID(), new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); - MCChatListener.OnlineSenders.put("P" + dp.getDiscordID(), - new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); + MCChatListener.addSender(MCChatListener.OnlineSenders, dp.getDiscordID(), + new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel } if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { IUser user = DiscordPlugin.dc @@ -76,9 +76,9 @@ public class MCListener implements Listener { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Only care about real users MCChatListener.OnlineSenders.entrySet() - .removeIf(entry -> entry.getValue().getUniqueId().equals(e.getPlayer().getUniqueId())); + .removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()))); Bukkit.getScheduler().runTask(DiscordPlugin.plugin, - () -> MCChatListener.ConnectedSenders.values().stream() + () -> MCChatListener.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java index 13b3095..f695dba 100755 --- a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java @@ -35,7 +35,7 @@ public class AcceptMCCommand extends DiscordMCCommandBase { dp.save(); mcp.save(); ConnectCommand.WaitingToConnect.remove(player.getName()); - MCChatListener.UnconnectedSenders.remove(did); + MCChatListener.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/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index c5b2c5c..a2b4a13 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -22,695 +22,696 @@ import sx.blah.discord.handle.obj.IUser; 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) { - super(user, channel, entityId, uuid); - 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.getName(); - } - - @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 user.getDisplayName(DiscordPlugin.mainServer); - } - - @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) { - } + protected DiscordFakePlayer(IUser user, IChannel channel, int entityId, UUID uuid, String mcname) { + super(user, channel, entityId, uuid); + 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.getName(); + } + + @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 user.getDisplayName(DiscordPlugin.mainServer); + } + + @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(); + } } -- 2.30.2 From 12a21461c0c47c3f0edd3160c8ebc7ea3ab536c2 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 3 Aug 2018 23:23:55 +0200 Subject: [PATCH 013/108] Added escaping & fixed reset stuff Escaping everything, including names (#47) Player list unhooking added (#73) Also removed autoupdater stuff and did other smaller changes --- .../buttondevteam/discordplugin/DPUtils.java | 58 +++++++++++-------- .../discordplugin/DiscordPlugin.java | 20 +++++-- .../discordplugin/PlayerListWatcher.java | 19 ++++++ .../listeners/AutoUpdaterListener.java | 24 -------- .../listeners/CommandListener.java | 2 +- .../listeners/MCChatListener.java | 4 +- .../discordplugin/listeners/MCListener.java | 3 +- 7 files changed, 75 insertions(+), 55 deletions(-) delete mode 100755 src/main/java/buttondevteam/discordplugin/listeners/AutoUpdaterListener.java diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 89c0b82..ea4d14d 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -9,6 +9,7 @@ import sx.blah.discord.util.RequestBuffer.IVoidRequest; import javax.annotation.Nullable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; public final class DPUtils { @@ -16,24 +17,31 @@ public final class DPUtils { return builder.withAuthorIcon("https://minotar.net/avatar/" + playername + "/32.png"); } - /** Removes §[char] colour codes from strings */ - public static String sanitizeString(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" - if (string.charAt(i) == 'k') - random = true; - else - random = false; - } else { - if (!random) // Skip random/obfuscated characters - sanitizedString += string.charAt(i); - } - } - return sanitizedString; - } + /** + * 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; + } /** * Performs Discord actions, retrying when ratelimited. May return null if action fails too many times or in safe mode. @@ -78,10 +86,14 @@ public final class DPUtils { RequestBuffer.request(action); } - public static void performNoWait(IRequest 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"); + } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 1b91494..431f212 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,7 +1,10 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; -import buttondevteam.discordplugin.listeners.*; +import buttondevteam.discordplugin.listeners.CommandListener; +import buttondevteam.discordplugin.listeners.ExceptionListener; +import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.listeners.MCListener; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.lib.TBMCCoreAPI; @@ -188,9 +191,9 @@ public class DiscordPlugin extends JavaPlugin implements IListener { 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 the separate account.", + "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 the testing account.")); + "The plugin refuses to load until you change the token to a testing account.")); Bukkit.getPluginManager().disablePlugin(this); } TBMCCoreAPI.SendUnsentExceptions(); @@ -213,7 +216,6 @@ public class DiscordPlugin extends JavaPlugin implements IListener { MCChatListener mcchat = new MCChatListener(); dc.getDispatcher().registerListener(mcchat); TBMCCoreAPI.RegisterEventsForExceptions(mcchat, this); - TBMCCoreAPI.RegisterEventsForExceptions(new AutoUpdaterListener(), this); Bukkit.getPluginManager().registerEvents(new ExceptionListener(), this); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); @@ -288,6 +290,16 @@ public class DiscordPlugin extends JavaPlugin implements IListener { try { SafeMode = true; // Stop interacting with Discord MCChatListener.stop(true); + try { + if (PlayerListWatcher.hookDown()) + System.out.println("Finished unhooking the player list!"); + else + System.out.println("Didn't have the player list hooked."); + hooked = false; + } catch (Throwable e) { + e.printStackTrace(); + Bukkit.getLogger().warning("Couldn't unhook the player list!"); + } ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); diff --git a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java index e056737..c2c878c 100755 --- a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java @@ -82,6 +82,25 @@ public class PlayerListWatcher extends DedicatedPlayerList { } } + public static boolean hookDown() { + try { + Field conf = CraftServer.class.getDeclaredField("console"); + conf.setAccessible(true); + val server = (MinecraftServer) conf.get(Bukkit.getServer()); + val plist = (DedicatedPlayerList) server.getPlayerList(); + if (!(plist instanceof PlayerListWatcher)) + return false; + server.a(((PlayerListWatcher) plist).plist); + Field pllf = CraftServer.class.getDeclaredField("playerList"); + pllf.setAccessible(true); + pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist); + return true; + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while hacking the player list!", e); + return true; + } + } + public void a(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) { plist.a(entityhuman, ichatbasecomponent); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/AutoUpdaterListener.java b/src/main/java/buttondevteam/discordplugin/listeners/AutoUpdaterListener.java deleted file mode 100755 index a6d0150..0000000 --- a/src/main/java/buttondevteam/discordplugin/listeners/AutoUpdaterListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package buttondevteam.discordplugin.listeners; - -import buttondevteam.discordplugin.DPUtils; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.PluginUpdater; -import buttondevteam.lib.TBMCCoreAPI; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -public class AutoUpdaterListener implements Listener { - @EventHandler - public void handle(PluginUpdater.UpdatedEvent event) { - if (DiscordPlugin.SafeMode) - return; - try { - DPUtils.performNoWait(() -> DiscordPlugin.officechannel.getMessageHistory(10).stream() - .filter(m -> m.getWebhookLongID() == 239123781401051138L && m.getEmbeds().get(0).getTitle() - .contains(event.getData().get("repository").getAsJsonObject().get("name").getAsString())) - .findFirst().get().addReaction(DiscordPlugin.DELIVERED_REACTION)); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while reacting to plugin update!", e); - } - } -} diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 1db1fdc..9384c6e 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -213,7 +213,7 @@ public class CommandListener { private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text if (cmdwithargs.length() > mention.length() + 1) - cmdwithargs = cmdwithargs.delete(0, + cmdwithargs.delete(0, cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length()); else cmdwithargs.replace(0, cmdwithargs.length(), "help"); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 393221a..e42085f 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -76,9 +76,9 @@ public class MCChatListener implements Listener, IListener e = se.getKey(); time = se.getValue(); - final String authorPlayer = "[" + DPUtils.sanitizeString(e.getChannel().DisplayName) + "] " // + final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName) + "] " // + (e.getSender() instanceof DiscordSenderBase ? "[D]" : "") // - + (DPUtils.sanitizeString(e.getSender() instanceof Player // + + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // ? ((Player) e.getSender()).getDisplayName() // : e.getSender().getName())); final EmbedBuilder embed = new EmbedBuilder().withAuthorName(authorPlayer) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 8eab392..49e337a 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -66,6 +66,7 @@ public class MCListener implements Listener { if (!DiscordPlugin.hooked) MCChatListener.sendSystemMessageToChat(message); MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer()); + //System.out.println("Does this appear more than once?"); //No MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); }); @@ -120,7 +121,7 @@ public class MCListener implements Listener { public void onPlayerAFK(AfkStatusChangeEvent e) { //TODO: Add AFK to custom chats? if (e.isCancelled() || !e.getAffected().getBase().isOnline()) return; - MCChatListener.sendSystemMessageToChat(DPUtils.sanitizeString(e.getAffected().getBase().getDisplayName()) + MCChatListener.sendSystemMessageToChat(e.getAffected().getBase().getDisplayName() + " is " + (e.getValue() ? "now" : "no longer") + " AFK."); } -- 2.30.2 From d79b1674eb0f0297d7ae00fd3cb912c26d89def4 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 9 Sep 2018 13:29:43 +0200 Subject: [PATCH 014/108] Fixed lowercase cmds & channel mentions Fixed commands from private mcchat being lowercased Added channel mention support (#51) Added version command (#51) --- .../commands/DiscordCommandBase.java | 1 + .../commands/VersionCommand.java | 31 +++++++++++++++++++ .../listeners/MCChatListener.java | 10 ++++-- .../discordplugin/listeners/MCListener.java | 5 +++ .../mccommands/VersionMCCommand.java | 20 ++++++++++++ src/main/resources/plugin.yml | 5 +-- 6 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java create mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index 8fd3145..34790b6 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -27,6 +27,7 @@ public abstract class DiscordCommandBase { commands.put("mcchat", new MCChatCommand()); commands.put("channelcon", new ChannelconCommand()); commands.put("debug", new DebugCommand()); + commands.put("version", new VersionCommand()); } public static void runCommand(String cmd, String args, IMessage message) { diff --git a/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java new file mode 100644 index 0000000..5908495 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java @@ -0,0 +1,31 @@ +package buttondevteam.discordplugin.commands; + +import buttondevteam.discordplugin.DiscordPlugin; +import lombok.val; +import sx.blah.discord.handle.obj.IMessage; + +public class VersionCommand extends DiscordCommandBase { + @Override + public String getCommandName() { + return "version"; + } + + @Override + public boolean run(IMessage message, String args) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), String.join("\n", getVersion())); + return true; + } + + @Override + public String[] getHelpText() { + return VersionCommand.getVersion(); //Heh + } + + public static String[] getVersion() { + val desc = DiscordPlugin.plugin.getDescription(); + return new String[]{ // + desc.getFullName(), // + desc.getWebsite() // + }; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index e42085f..d1838be 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -477,6 +477,9 @@ public class MCChatListener implements Listener, IListener final String nick = u.getNicknameForGuild(DiscordPlugin.mainServer); dmessage = dmessage.replace(u.mention(true), "@" + (nick != null ? nick : u.getName())); } + for (IChannel ch : event.getMessage().getChannelMentions()) { + 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 @@ -496,7 +499,8 @@ public class MCChatListener implements Listener, IListener event.getMessage().delete(); }); //preprocessChat(dsender, dmessage); - Same is done below - final String cmdlowercased = dmessage.substring(1).toLowerCase(); + final String cmd = dmessage.substring(1); + final String cmdlowercased = cmd.toLowerCase(); if (dsender instanceof DiscordSender && Arrays.stream(UnconnectedCmds) .noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) { // Command not whitelisted @@ -529,7 +533,7 @@ public class MCChatListener implements Listener, IListener if (!ch.isPresent()) Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { - VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmdlowercased); + VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); }); else { @@ -552,7 +556,7 @@ public class MCChatListener implements Listener, IListener dsender.sendMessage("You're now talking in: " + DPUtils.sanitizeString(dsender.getMcchannel().DisplayName)); } else { // Send single message - final String msg = event.getMessage().getContent().substring(spi + 2); + final String msg = cmd.substring(spi + 1); val cmb = ChatMessage.builder(chc, dsender, user, getChatMessage.apply(msg)).fromCommand(true); if (clmd == null) TBMCChatAPI.SendChatMessage(cmb.build()); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 49e337a..d6e64e3 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -162,6 +162,11 @@ public class MCListener implements Listener { MCChatListener.sendSystemMessageToChat(event.getMessage()); } + /*@EventHandler + public void onYEEHAW(TBMCYEEHAWEvent event) { + MCChatListener.forAllowedCustomMCChat();event.getSender().getName()+" <:YEEHAW:"+DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID()+">s"//TODO: :YEEHAW:s - Change from broadcastMessage() in ButtonChat + }*/ + private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; public static void callEventExcludingSome(Event event) { diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java new file mode 100644 index 0000000..a2cacba --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mccommands/VersionMCCommand.java @@ -0,0 +1,20 @@ +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 + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5b218e7..1c74854 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,8 @@ name: DiscordPlugin main: buttondevteam.discordplugin.DiscordPlugin version: 1.0 -author: TBMCPlugins +author: NorbiPeti depend: [ButtonCore] commands: - discord: + discord: +website: 'https://github.com/TBMCPlugins/DiscordPlugin' -- 2.30.2 From 774186a60096c3140a94bdfa6132d457361b2de0 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 22 Oct 2018 01:50:09 +0200 Subject: [PATCH 015/108] Can't toggle toggles yet #75 Also allowing any text after "remove" --- .../discordplugin/ChannelconBroadcast.java | 7 +++++++ .../commands/ChannelconCommand.java | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java diff --git a/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java new file mode 100644 index 0000000..aa06d43 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java @@ -0,0 +1,7 @@ +package buttondevteam.discordplugin; + +public enum ChannelconBroadcast { + JOINLEAVE, + AFK, + RESTART +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index d9a1c8f..783651c 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.commands; +import buttondevteam.discordplugin.ChannelconBroadcast; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.listeners.MCChatListener; @@ -13,6 +14,8 @@ import sx.blah.discord.handle.obj.Permissions; import sx.blah.discord.util.PermissionUtils; import java.util.Arrays; +import java.util.function.Supplier; +import java.util.stream.Collectors; public class ChannelconCommand extends DiscordCommandBase { @Override @@ -29,13 +32,28 @@ public class ChannelconCommand extends DiscordCommandBase { return true; } if (MCChatListener.hasCustomChat(message.getChannel())) { - if (args.equalsIgnoreCase("remove")) { + if (args.toLowerCase().startsWith("remove")) { if (MCChatListener.removeCustomChat(message.getChannel())) message.reply("channel connection removed."); else message.reply("wait what, couldn't remove channel connection."); return true; } + if (args.toLowerCase().startsWith("toggle")) { + Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase()).collect(Collectors.joining(", ")); + String[] argsa = args.split(" "); + if (argsa.length < 2) { + message.reply("Toggles: " + togglesString.get()); + return true; + } + String arg = argsa[1].toUpperCase(); + val b = Arrays.stream(ChannelconBroadcast.values()).filter(t -> t.toString().equals(arg)).findAny(); + if (!b.isPresent()) { + message.reply("Cannot find toggle. Toggles: " + togglesString.get()); + return true; + } + //TODO: Toggle that toggle + } message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); return true; } -- 2.30.2 From 18fdbc5770f6bcc980abe40a492970f1c094b7c1 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 23 Oct 2018 03:06:34 +0200 Subject: [PATCH 016/108] More work on toggles #75 Most channel toggles should work Needs testing --- .../discordplugin/ChannelconBroadcast.java | 10 +++++++++- .../commands/ChannelconCommand.java | 11 +++++++++++ .../discordplugin/listeners/MCChatListener.java | 15 ++++++++++++++- .../discordplugin/listeners/MCListener.java | 16 +++++++++++----- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java index aa06d43..e5187e2 100644 --- a/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java +++ b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java @@ -3,5 +3,13 @@ package buttondevteam.discordplugin; public enum ChannelconBroadcast { JOINLEAVE, AFK, - RESTART + RESTART, //TODO + DEATH, + BROADCAST; + + public final int flag; + + ChannelconBroadcast() { + this.flag = 1 << this.ordinal(); + } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index 783651c..daf8e5b 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -53,6 +53,17 @@ public class ChannelconCommand extends DiscordCommandBase { return true; } //TODO: Toggle that toggle + val cc = MCChatListener.getCustomChat(message.getChannel()); + //A B | F + //------- A: original - B: mask - F: new + //0 0 | 0 + //0 1 | 1 + //1 0 | 1 + //1 1 | 0 + // XOR + cc.toggles ^= b.get().flag; + message.reply("'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")); + return true; } message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); return true; diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index d1838be..d94b32a 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -33,6 +33,7 @@ import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.MissingPermissionsException; +import javax.annotation.Nullable; import java.awt.*; import java.time.Instant; import java.util.*; @@ -173,6 +174,7 @@ public class MCChatListener implements Listener, IListener public final String groupID; public final Channel mcchannel; public final DiscordConnectedPlayer dcp; + public int toggles; public CustomLMD(@NonNull IChannel channel, @NonNull IUser user, @NonNull DiscordPlayer dp, @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp) { @@ -367,9 +369,20 @@ public class MCChatListener implements Listener, IListener lastmsgCustom.forEach(cc -> action.accept(cc.channel)); } - public static void forAllowedCustomMCChat(Consumer action, CommandSender sender) { + /** + * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. + * + * @param action The action to do + * @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) { lastmsgCustom.stream().filter(clmd -> { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple + if (toggle != null && (clmd.toggles & toggle.flag) == 0) + return false; //If null then allow + if (sender == null) + return true; val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); return clmd.groupID.equals(e.getGroupID(sender)); }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index d6e64e3..9d5cdb0 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -65,7 +65,7 @@ public class MCListener implements Listener { final String message = e.GetPlayer().PlayerName().get() + " joined the game"; if (!DiscordPlugin.hooked) MCChatListener.sendSystemMessageToChat(message); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer()); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE); //System.out.println("Does this appear more than once?"); //No MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); @@ -87,7 +87,7 @@ public class MCListener implements Listener { final String message = e.GetPlayer().PlayerName().get() + " left the game"; if (!DiscordPlugin.hooked) MCChatListener.sendSystemMessageToChat(message); //TODO: Probably double sends if kicked and unhooked - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer()); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE); } @EventHandler(priority = EventPriority.HIGHEST) @@ -115,14 +115,18 @@ public class MCListener implements Listener { public void onPlayerDeath(PlayerDeathEvent e) { if (!DiscordPlugin.hooked) MCChatListener.sendSystemMessageToChat(e.getDeathMessage()); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH); } @EventHandler public void onPlayerAFK(AfkStatusChangeEvent e) { //TODO: Add AFK to custom chats? - if (e.isCancelled() || !e.getAffected().getBase().isOnline()) + final Player base = e.getAffected().getBase(); + if (e.isCancelled() || !base.isOnline()) return; - MCChatListener.sendSystemMessageToChat(e.getAffected().getBase().getDisplayName() - + " is " + (e.getValue() ? "now" : "no longer") + " AFK."); + final String msg = base.getDisplayName() + + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; + MCChatListener.sendSystemMessageToChat(msg); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, msg), base, ChannelconBroadcast.AFK); } @EventHandler @@ -155,11 +159,13 @@ public class MCListener implements Listener { @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { MCChatListener.sendSystemMessageToChat(event); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), null, ChannelconBroadcast.BROADCAST); //TODO: Method to send message } @EventHandler public void onBroadcastMessage(BroadcastMessageEvent event) { MCChatListener.sendSystemMessageToChat(event.getMessage()); + MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), null, ChannelconBroadcast.BROADCAST); } /*@EventHandler -- 2.30.2 From 9e827d14d094aede2ccc41b295d3a862ea102bf4 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Oct 2018 00:07:07 +0200 Subject: [PATCH 017/108] Toggles work! Other changes #75 - Changed shutdown kick message - Added timeout for resetting as well - Last message handling fixed (#71) - Some restructuring related to mcchat --- .../discordplugin/ChromaBot.java | 6 +- .../discordplugin/DiscordPlugin.java | 48 +++---- .../discordplugin/PlayerListWatcher.java | 2 +- .../commands/ChannelconCommand.java | 11 +- .../listeners/MCChatListener.java | 134 +++++++++++------- .../discordplugin/listeners/MCListener.java | 27 ++-- .../playerfaker/DiscordInventory.java | 4 +- 7 files changed, 124 insertions(+), 108 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index 2db1a17..79a0514 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -9,6 +9,7 @@ import sx.blah.discord.api.internal.json.objects.EmbedObject; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.util.EmbedBuilder; +import javax.annotation.Nullable; import java.awt.*; import java.util.Arrays; import java.util.stream.Collectors; @@ -62,9 +63,10 @@ public class ChromaBot { * * @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) { - MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); + public void sendMessageCustomAsWell(String message, EmbedObject embed, @Nullable ChannelconBroadcast toggle) { + MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed), toggle, false); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 431f212..4008779 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -153,26 +153,27 @@ public class DiscordPlugin extends JavaPlugin implements IListener { val user = dc.fetchUser(did); val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname")); val groupid = chcon.getString("groupid"); + val toggles = chcon.getInt("toggles"); if (!mcch.isPresent() || ch == null || user == null || groupid == null) continue; - MCChatListener.addCustomChat(ch, groupid, mcch.get(), dp, user, dcp); + MCChatListener.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles); } } DiscordCommandBase.registerCommands(); if (ResetMCCommand.resetting) ChromaBot.getInstance().sendMessageCustomAsWell("", new EmbedBuilder().withColor(Color.CYAN) - .withTitle("Discord plugin restarted - chat connected.").build()); //Really important to note the chat, hmm + .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()); + .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()); + .withTitle("Server started - chat connected.").build(), ChannelconBroadcast.RESTART); ResetMCCommand.resetting = false; //This is the last event handling this flag @@ -261,31 +262,33 @@ public class DiscordPlugin extends JavaPlugin implements IListener { chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); chconc.set("mcname", chcon.dcp.getName()); chconc.set("groupid", chcon.groupID); + chconc.set("toggles", chcon.toggles); } saveConfig(); + EmbedObject embed; + if (ResetMCCommand.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(); MCChatListener.forCustomAndAllMCChat(ch -> { try { - if (ResetMCCommand.resetting) DiscordPlugin.sendMessageToChannelWait(ch, "", - new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build()); - else - DiscordPlugin.sendMessageToChannelWait(ch, "", - 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 ") - + "asked *politely* to leave the server for a bit.") - : "") - .build(), 5, TimeUnit.SECONDS); + embed, 5, TimeUnit.SECONDS); } catch (TimeoutException | InterruptedException e) { e.printStackTrace(); } - }); + }, ChannelconBroadcast.RESTART, false); ChromaBot.getInstance().updatePlayerList(); try { SafeMode = true; // Stop interacting with Discord @@ -415,10 +418,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { .warning("Message was too long to send to discord and got truncated. In " + channel.getName()); } try { - if (channel == chatchannel) - MCChatListener.resetLastMessage(); // If this is a chat message, it'll be set again - else if (channel.isPrivate()) - MCChatListener.resetLastMessage(channel); + MCChatListener.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); diff --git a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java index c2c878c..432b75c 100755 --- a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java @@ -30,7 +30,7 @@ public class PlayerListWatcher extends DedicatedPlayerList { if (packet instanceof PacketPlayOutChat) { Field msgf = PacketPlayOutChat.class.getDeclaredField("a"); msgf.setAccessible(true); - MCChatListener.sendSystemMessageToChat(((IChatBaseComponent) msgf.get(packet)).toPlainText()); + MCChatListener.forAllMCChat(MCChatListener.send(((IChatBaseComponent) msgf.get(packet)).toPlainText())); } } catch (Exception e) { TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index daf8e5b..ec2a04b 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -40,20 +40,19 @@ public class ChannelconCommand extends DiscordCommandBase { return true; } if (args.toLowerCase().startsWith("toggle")) { - Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase()).collect(Collectors.joining(", ")); + val cc = MCChatListener.getCustomChat(message.getChannel()); + Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")); String[] argsa = args.split(" "); if (argsa.length < 2) { - message.reply("Toggles: " + togglesString.get()); + message.reply("toggles:\n" + togglesString.get()); return true; } String arg = argsa[1].toUpperCase(); val b = Arrays.stream(ChannelconBroadcast.values()).filter(t -> t.toString().equals(arg)).findAny(); if (!b.isPresent()) { - message.reply("Cannot find toggle. Toggles: " + togglesString.get()); + message.reply("cannot find toggle. Toggles:\n" + togglesString.get()); return true; } - //TODO: Toggle that toggle - val cc = MCChatListener.getCustomChat(message.getChannel()); //A B | F //------- A: original - B: mask - F: new //0 0 | 0 @@ -91,7 +90,7 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("sorry, this MC chat is already connected to a different channel, multiple channels are not supported atm."); return true; } - MCChatListener.addCustomChat(message.getChannel(), groupid, ev.getChannel(), dp, message.getAuthor(), dcp); + MCChatListener.addCustomChat(message.getChannel(), groupid, ev.getChannel(), message.getAuthor(), dcp, 0); message.reply("alright, connection made to group `" + groupid + "`!"); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index d94b32a..943554a 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -128,11 +128,11 @@ public class MCChatListener implements Listener, IListener if ((e.getChannel() == Channel.GlobalChat || e.getChannel().ID.equals("rp")) && (e.isFromcmd() || isdifferentchannel.test(DiscordPlugin.chatchannel))) doit.accept(lastmsgdata == null - ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null, null) + ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null) : lastmsgdata); for (LastMsgData data : lastmsgPerUser) { - if (data.dp.isMinecraftChatEnabled() && (e.isFromcmd() || isdifferentchannel.test(data.channel)) + if ((e.isFromcmd() || isdifferentchannel.test(data.channel)) && e.shouldSendTo(getSender(data.channel, data.user))) doit.accept(data); } @@ -167,7 +167,6 @@ public class MCChatListener implements Listener, IListener public final IChannel channel; public Channel mcchannel; public final IUser user; - public final DiscordPlayer dp; } public static class CustomLMD extends LastMsgData { @@ -176,12 +175,13 @@ public class MCChatListener implements Listener, IListener public final DiscordConnectedPlayer dcp; public int toggles; - public CustomLMD(@NonNull IChannel channel, @NonNull IUser user, @NonNull DiscordPlayer dp, - @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp) { - super(channel, user, dp); + private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, + @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles) { + super(channel, user); groupID = groupid; this.mcchannel = mcchannel; this.dcp = dcp; + this.toggles = toggles; } } @@ -240,7 +240,7 @@ public class MCChatListener implements Listener, IListener if (!start) lastmsgfromd.remove(channel.getLongID()); return start // - ? lastmsgPerUser.add(new LastMsgData(channel, user, dp)) // Doesn't support group DMs + ? lastmsgPerUser.add(new LastMsgData(channel, user)) // Doesn't support group DMs : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); } @@ -295,8 +295,8 @@ public class MCChatListener implements Listener, IListener .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did)); } - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, DiscordPlayer dp, IUser user, DiscordConnectedPlayer dcp) { - val lmd = new CustomLMD(channel, user, dp, groupid, mcchannel, dcp); + public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles) { + val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles); lastmsgCustom.add(lmd); } @@ -328,33 +328,25 @@ public class MCChatListener implements Listener, IListener public static final HashMap> OnlineSenders = new HashMap<>(); public static short ListC = 0; - public static void resetLastMessage() { - (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null, null) - : lastmsgdata).message = null; - } // Don't set the whole object to null, the player and channel information should be preserved - - public static void resetLastMessage(IChannel channel) { - for (LastMsgData data : lastmsgPerUser) - if (data.channel.getLongID() == channel.getLongID()) - data.message = null; // Since only private channels are stored, only those will work anyways - } - - public static void resetLastMessageCustom(IChannel channel) { - for (LastMsgData data : lastmsgCustom) - if (data.channel.getLongID() == channel.getLongID()) - data.message = null; - } - /** - * This overload sends it to the global chat. + * Resets the last message, so it will start a new one instead of appending to it. + * This is used when someone (even the bot) sends a message to the channel. + * + * @param channel The channel to reset in - the process is slightly different for the public, private and custom chats */ - public static void sendSystemMessageToChat(String msg) { - forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(msg))); - } - - public static void sendSystemMessageToChat(TBMCSystemChatEvent event) { - forAllowedMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(event.getMessage())), - event); + public static void resetLastMessage(IChannel channel) { + if (channel.getLongID() == DiscordPlugin.chatchannel.getLongID()) { + (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, 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() ? lastmsgPerUser : lastmsgCustom) { + if (data.channel.getLongID() == channel.getLongID()) { + data.message = null; + return; + } + } + //If it gets here, it's sending a message to a non-chat channel } public static void forAllMCChat(Consumer action) { @@ -364,30 +356,67 @@ public class MCChatListener implements Listener, IListener // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat } - public static void forCustomAndAllMCChat(Consumer action) { - forAllMCChat(action); - lastmsgCustom.forEach(cc -> action.accept(cc.channel)); + /** + * For custom and all MC chat + * + * @param action The action to act + * @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) { + if (!DiscordPlugin.hooked || !hookmsg) + forAllMCChat(action); + final Consumer customLMDConsumer = cc -> action.accept(cc.channel); + if (toggle == null) + lastmsgCustom.forEach(customLMDConsumer); + else + lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).forEach(customLMDConsumer); } - /** - * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. - * - * @param action The action to do - * @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) { + /** + * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. + * + * @param action The action to do + * @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) { lastmsgCustom.stream().filter(clmd -> { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple - if (toggle != null && (clmd.toggles & toggle.flag) == 0) - return false; //If null then allow - if (sender == null) - return true; + if (toggle != null && (clmd.toggles & toggle.flag) == 0) + return false; //If null then allow + if (sender == null) + return true; val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); return clmd.groupID.equals(e.getGroupID(sender)); }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect } + /** + * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. + * + * @param action The action to do + * @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 + * @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) { + if (!DiscordPlugin.hooked || !hookmsg) + forAllMCChat(action); + lastmsgCustom.stream().filter(clmd -> { + if (toggle != null && (clmd.toggles & toggle.flag) == 0) + return false; //If null then allow + if (sender == null) + return true; + val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); + return clmd.groupID.equals(e.getGroupID(sender)); + }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect + } + + public static Consumer send(String message) { + return ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(message)); + } + private static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) action.accept(DiscordPlugin.chatchannel); @@ -451,12 +480,7 @@ public class MCChatListener implements Listener, IListener return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommandListener) if (CommandListener.runCommand(ev.getMessage(), true)) return; - if (!ev.getMessage().getChannel().isPrivate()) - resetLastMessage(); - else if (hasCustomChat) - resetLastMessageCustom(ev.getChannel()); - else - resetLastMessage(ev.getMessage().getChannel()); + resetLastMessage(ev.getChannel()); lastlist++; recevents.add(ev); if (rectask != null) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 9d5cdb0..0f16ad5 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -63,9 +63,7 @@ public class MCListener implements Listener { p.sendMessage("§bIf it wasn't you, do /discord decline"); } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; - if (!DiscordPlugin.hooked) - MCChatListener.sendSystemMessageToChat(message); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE); + MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); //System.out.println("Does this appear more than once?"); //No MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); @@ -85,16 +83,14 @@ public class MCListener implements Listener { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; - if (!DiscordPlugin.hooked) - MCChatListener.sendSystemMessageToChat(message); //TODO: Probably double sends if kicked and unhooked - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE); + MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerKick(PlayerKickEvent e) { - if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") + /*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") && !e.getReason().equals("Server closed")) // The leave messages errored with the previous setup, I could make it wait since I moved it here, but instead I have a special - MCChatListener.sendSystemMessageToChat(e.getPlayer().getName() + " left the game"); // message for this - Oh wait this doesn't even send normally because of the hook + MCChatListener.forAllowedCustomAndAllMCChat(e.getPlayer().getName() + " left the game"); // message for this - Oh wait this doesn't even send normally because of the hook*/ } @EventHandler @@ -113,20 +109,17 @@ public class MCListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerDeath(PlayerDeathEvent e) { - if (!DiscordPlugin.hooked) - MCChatListener.sendSystemMessageToChat(e.getDeathMessage()); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH); + MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); } @EventHandler - public void onPlayerAFK(AfkStatusChangeEvent e) { //TODO: Add AFK to custom chats? + public void onPlayerAFK(AfkStatusChangeEvent e) { final Player base = e.getAffected().getBase(); if (e.isCancelled() || !base.isOnline()) return; final String msg = base.getDisplayName() + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; - MCChatListener.sendSystemMessageToChat(msg); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, msg), base, ChannelconBroadcast.AFK); + MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(msg), base, ChannelconBroadcast.AFK, false); } @EventHandler @@ -158,14 +151,12 @@ public class MCListener implements Listener { @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { - MCChatListener.sendSystemMessageToChat(event); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), null, ChannelconBroadcast.BROADCAST); //TODO: Method to send message + MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), ChannelconBroadcast.BROADCAST, false); } @EventHandler public void onBroadcastMessage(BroadcastMessageEvent event) { - MCChatListener.sendSystemMessageToChat(event.getMessage()); - MCChatListener.forAllowedCustomMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), null, ChannelconBroadcast.BROADCAST); + MCChatListener.forCustomAndAllMCChat(MCChatListener.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); } /*@EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java index a97f715..365f968 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java @@ -46,13 +46,13 @@ public class DiscordInventory implements Inventory { @Override public HashMap addItem(ItemStack... items) throws IllegalArgumentException { // Can't add anything return new HashMap<>( - IntStream.range(0, items.length).mapToObj(i -> i).collect(Collectors.toMap(i -> i, i -> items[i]))); + IntStream.range(0, items.length).boxed().collect(Collectors.toMap(i -> i, i -> items[i]))); } @Override public HashMap removeItem(ItemStack... items) throws IllegalArgumentException { return new HashMap<>( - IntStream.range(0, items.length).mapToObj(i -> i).collect(Collectors.toMap(i -> i, i -> items[i]))); + IntStream.range(0, items.length).boxed().collect(Collectors.toMap(i -> i, i -> items[i]))); } @Override -- 2.30.2 From 7d624816f2c2169ae7c588799643f84d1f86fa49 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Oct 2018 14:19:50 +0200 Subject: [PATCH 018/108] Performance improvements (user data) CommandSender (DiscordSenderBase) level of caching implemented (not perfect but much better than before) Various mcchat improvements --- .../discordplugin/DiscordPlugin.java | 4 +- .../discordplugin/DiscordSenderBase.java | 22 +++-- .../listeners/CommandListener.java | 4 +- .../listeners/MCChatListener.java | 89 +++++-------------- .../discordplugin/listeners/MCListener.java | 2 +- 5 files changed, 42 insertions(+), 79 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 4008779..02b9f12 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -38,6 +38,7 @@ import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -149,7 +150,6 @@ public class DiscordPlugin extends JavaPlugin implements IListener { val mcch = Channel.getChannels().stream().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); val ch = dc.getChannelByID(chcon.getLong("chid")); val did = chcon.getLong("did"); - val dp = DiscordPlayer.getUser(Long.toString(did), DiscordPlayer.class); val user = dc.fetchUser(did); val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname")); val groupid = chcon.getString("groupid"); @@ -221,6 +221,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); + ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase + ? ((DiscordSenderBase) sender).getChromaUser() : null)); new Thread(this::AnnouncementGetterThreadMethod).start(); setupProviders(); } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index 0a6e392..14c7fc4 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -1,26 +1,18 @@ package buttondevteam.discordplugin; import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.IDiscordSender; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IUser; -import java.util.Arrays; -import java.util.stream.Collectors; - public abstract class DiscordSenderBase implements IDiscordSender { /** * May be null. */ protected IUser user; protected IChannel channel; - private @Getter @Setter @NonNull Channel mcchannel = Channel.GlobalChat; protected DiscordSenderBase(IUser user, IChannel channel) { this.user = user; @@ -43,6 +35,18 @@ public abstract class DiscordSenderBase implements IDiscordSender { return channel; } + private DiscordPlayer chromaUser; + + /** + * Loads the user data on first query. + * + * @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); + return chromaUser; + } + @Override public void sendMessage(String message) { try { @@ -65,6 +69,6 @@ public abstract class DiscordSenderBase implements IDiscordSender { @Override public void sendMessage(String[] messages) { - sendMessage(Arrays.stream(messages).collect(Collectors.joining("\n"))); + sendMessage(String.join("\n", messages)); } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 9384c6e..f46abff 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -1,6 +1,5 @@ package buttondevteam.discordplugin.listeners; -import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.lib.TBMCCoreAPI; @@ -99,8 +98,7 @@ public class CommandListener { && !(event.getMessage().getContent().startsWith("/") && event.getChannel().getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // return; - if (DiscordPlayer.getUser(event.getAuthor().getStringID(), DiscordPlayer.class) - .isMinecraftChatEnabled()) + if (MCChatListener.isMinecraftChatEnabled(event.getAuthor().toString())) if (!event.getMessage().getContent().equalsIgnoreCase("mcchat")) return; if (event.getMessage().getAuthor().isBot()) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 943554a..18c7bf2 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -7,6 +7,7 @@ import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; +import buttondevteam.lib.player.PlayerData; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; import io.netty.util.collection.LongObjectHashMap; @@ -403,28 +404,24 @@ public class MCChatListener implements Listener, IListener public static void forAllowedCustomAndAllMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (!DiscordPlugin.hooked || !hookmsg) forAllMCChat(action); - lastmsgCustom.stream().filter(clmd -> { - if (toggle != null && (clmd.toggles & toggle.flag) == 0) - return false; //If null then allow - if (sender == null) - return true; - val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); - return clmd.groupID.equals(e.getGroupID(sender)); - }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect + forAllowedCustomMCChat(action, sender, toggle); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect } public static Consumer send(String message) { return ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(message)); } - private static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { + public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { //TODO if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : lastmsgPerUser) if (event.shouldSendTo(getSender(data.channel, data.user))) action.accept(data.channel); - lastmsgCustom.stream().filter(data -> event.shouldSendTo(data.dcp)) - .map(data -> data.channel).forEach(action); + lastmsgCustom.stream().filter(clmd -> { + if ((clmd.toggles & ChannelconBroadcast.BROADCAST.flag) == 0) + return false; + return event.shouldSendTo(clmd.dcp); + }).map(clmd -> clmd.channel).forEach(action); } /** @@ -504,10 +501,10 @@ public class MCChatListener implements Listener, IListener return; } val sender = event.getMessage().getAuthor(); - val user = DiscordPlayer.getUser(sender.getStringID(), DiscordPlayer.class); String dmessage = event.getMessage().getContent(); try { final DiscordSenderBase dsender = 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 @@ -523,7 +520,7 @@ public class MCChatListener implements Listener, IListener Function getChatMessage = msg -> // msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() - .getAttachments().stream().map(a -> a.getUrl()).collect(Collectors.joining("\n")) + .getAttachments().stream().map(IMessage.Attachment::getUrl).collect(Collectors.joining("\n")) : ""); CustomLMD clmd = getCustomChat(event.getChannel()); @@ -535,7 +532,6 @@ public class MCChatListener implements Listener, IListener if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) event.getMessage().delete(); }); - //preprocessChat(dsender, dmessage); - Same is done below final String cmd = dmessage.substring(1); final String cmdlowercased = cmd.toLowerCase(); if (dsender instanceof DiscordSender && Arrays.stream(UnconnectedCmds) @@ -581,24 +577,25 @@ public class MCChatListener implements Listener, IListener else { if (spi == -1) // Switch channels { - val oldch = dsender.getMcchannel(); + final PlayerData channel = dsender.getChromaUser().channel(); + val oldch = channel.get(); if (oldch instanceof ChatRoom) ((ChatRoom) oldch).leaveRoom(dsender); if (!oldch.ID.equals(chc.ID)) { - dsender.setMcchannel(chc); + channel.set(chc); if (chc instanceof ChatRoom) ((ChatRoom) chc).joinRoom(dsender); } else - dsender.setMcchannel(Channel.GlobalChat); + channel.set(Channel.GlobalChat); dsender.sendMessage("You're now talking in: " - + DPUtils.sanitizeString(dsender.getMcchannel().DisplayName)); + + DPUtils.sanitizeString(channel.get().DisplayName)); } else { // Send single message final String msg = cmd.substring(spi + 1); - val cmb = ChatMessage.builder(chc, dsender, user, getChatMessage.apply(msg)).fromCommand(true); + val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(msg)).fromCommand(true); if (clmd == null) - TBMCChatAPI.SendChatMessage(cmb.build()); + TBMCChatAPI.SendChatMessage(cmb.build(), chc); else - TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build()); + TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), chc); react = true; } } @@ -612,9 +609,9 @@ public class MCChatListener implements Listener, IListener (dsender instanceof Player ? ((Player) dsender).getDisplayName() : dsender.getName()) + " pinned a message on Discord."); else { - val cmb = ChatMessage.builder(dsender.getMcchannel(), dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); + val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); if (clmd != null) - TBMCChatAPI.SendChatMessage(cmb.channel(clmd.mcchannel).permCheck(clmd.dcp).build()); + TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build(), clmd.mcchannel); else TBMCChatAPI.SendChatMessage(cmb.build()); react = true; @@ -638,55 +635,17 @@ public class MCChatListener implements Listener, IListener } } - private boolean preprocessChat(DiscordSenderBase dsender, String dmessage) { - if (dmessage.length() < 2) - return false; - int index = dmessage.indexOf(" "); - String cmd; - if (index == -1) { // Only the command is run - cmd = dmessage; - for (Channel channel : Channel.getChannels()) { - if (cmd.equalsIgnoreCase(channel.ID) || (channel.IDs != null && Arrays.stream(channel.IDs).anyMatch(cmd::equalsIgnoreCase))) { - Channel oldch = dsender.getMcchannel(); - if (oldch instanceof ChatRoom) - ((ChatRoom) oldch).leaveRoom(dsender); - if (oldch.equals(channel)) - dsender.setMcchannel(Channel.GlobalChat); - else { - dsender.setMcchannel(channel); - if (channel instanceof ChatRoom) - ((ChatRoom) channel).joinRoom(dsender); - } - dsender.sendMessage("You are now talking in: " + dsender.getMcchannel().DisplayName); - return true; - } - } - } else { // We have arguments - cmd = dmessage.substring(0, index); - for (Channel channel : Channel.getChannels()) { - if (cmd.equalsIgnoreCase(channel.ID) || (channel.IDs != null && Arrays.stream(channel.IDs).anyMatch(cmd::equalsIgnoreCase))) { - val dp = DiscordPlayer.getUser(dsender.getUser().getStringID(), DiscordPlayer.class); - TBMCChatAPI.SendChatMessage(ChatMessage.builder(channel, dsender, dp, dmessage.substring(index + 1)).build()); - return true; - } - } - // TODO: Target selectors - } - return false; - } - /** * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. */ private static DiscordSenderBase getSender(IChannel channel, final IUser author) { - val key = author.getStringID(); + //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(OnlineSenders, channel, author)), () -> { - return Optional.of(addSender(UnconnectedSenders, author, - new DiscordSender(author, channel))); - }).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); + () -> Optional.ofNullable(getSender(OnlineSenders, channel, author)), // + () -> Optional.of(addSender(UnconnectedSenders, author, + new DiscordSender(author, channel)))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); } @FunctionalInterface diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 0f16ad5..03b5c43 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -151,7 +151,7 @@ public class MCListener implements Listener { @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { - MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, event.getMessage()), ChannelconBroadcast.BROADCAST, false); + MCChatListener.forAllowedMCChat(MCChatListener.send(event.getMessage()), event); } @EventHandler -- 2.30.2 From a0e08901608028b743428c43740fe76b64887964 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Oct 2018 23:54:16 +0200 Subject: [PATCH 019/108] YEEHAW, small fixes (mcchat) Working on #70 --- .../buttondevteam/discordplugin/DiscordSender.java | 5 +++-- .../discordplugin/listeners/MCChatListener.java | 11 ++++++++--- .../discordplugin/listeners/MCListener.java | 10 ++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index f2f829b..5cd4df6 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -16,10 +16,11 @@ import java.util.Set; public class DiscordSender extends DiscordSenderBase implements CommandSender { private PermissibleBase perm = new PermissibleBase(this); - private String name = null; + private String name; public DiscordSender(IUser user, IChannel channel) { super(user, channel); + name = user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer); } public DiscordSender(IUser user, IChannel channel, String name) { @@ -100,7 +101,7 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { @Override public String getName() { - return name == null ? user == null ? "Discord user" : user.getDisplayName(DiscordPlugin.mainServer) : name; + return name; } @Override diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 18c7bf2..6db4a81 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -7,7 +7,6 @@ import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.PlayerData; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; import io.netty.util.collection.LongObjectHashMap; @@ -411,7 +410,7 @@ public class MCChatListener implements Listener, IListener return ch -> DiscordPlugin.sendMessageToChannel(ch, DPUtils.sanitizeString(message)); } - public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { //TODO + public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : lastmsgPerUser) @@ -566,8 +565,14 @@ public class MCChatListener implements Listener, IListener if (!ch.isPresent()) Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { + val channel = dsender.getChromaUser().channel(); //TODO: Save? + val chtmp = channel.get(); + if (clmd != null) + channel.set(clmd.mcchannel); //Hack to send command in the channel 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(); @@ -577,7 +582,7 @@ public class MCChatListener implements Listener, IListener else { if (spi == -1) // Switch channels { - final PlayerData channel = dsender.getChromaUser().channel(); + val channel = dsender.getChromaUser().channel(); val oldch = channel.get(); if (oldch instanceof ChatRoom) ((ChatRoom) oldch).leaveRoom(dsender); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 03b5c43..e7d57ec 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -159,10 +159,12 @@ public class MCListener implements Listener { MCChatListener.forCustomAndAllMCChat(MCChatListener.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); } - /*@EventHandler - public void onYEEHAW(TBMCYEEHAWEvent event) { - MCChatListener.forAllowedCustomMCChat();event.getSender().getName()+" <:YEEHAW:"+DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID()+">s"//TODO: :YEEHAW:s - Change from broadcastMessage() in ButtonChat - }*/ + @EventHandler + public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support + String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() + : event.getSender().getName(); + MCChatListener.forAllMCChat(MCChatListener.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); + } private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; -- 2.30.2 From 17887707cbd8c71151f3dd0722cf12b8c1ab1199 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 1 Nov 2018 01:34:36 +0100 Subject: [PATCH 020/108] Bunch of channel stuff #70 is technically fixed but there's another issue #61 and #71 are definitely fixed Allowing multiple channels to be connected --- pom.xml | 7 +++ .../discordplugin/ChannelconBroadcast.java | 2 +- .../discordplugin/DiscordPlugin.java | 8 ++- .../discordplugin/DiscordSender.java | 4 +- .../commands/ChannelconCommand.java | 10 ++-- .../listeners/MCChatListener.java | 55 +++++++++++-------- .../discordplugin/listeners/MCListener.java | 3 +- 7 files changed, 55 insertions(+), 34 deletions(-) diff --git a/pom.xml b/pom.xml index 5c69674..f283fc7 100755 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,13 @@ testDelombok false src/test/java --> + + maven-surefire-plugin + + false + + + diff --git a/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java index e5187e2..994c8ed 100644 --- a/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java +++ b/src/main/java/buttondevteam/discordplugin/ChannelconBroadcast.java @@ -3,7 +3,7 @@ package buttondevteam.discordplugin; public enum ChannelconBroadcast { JOINLEAVE, AFK, - RESTART, //TODO + RESTART, DEATH, BROADCAST; diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 02b9f12..be7e8a9 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -221,8 +221,12 @@ public class DiscordPlugin extends JavaPlugin implements IListener { TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase - ? ((DiscordSenderBase) sender).getChromaUser() : null)); + ChromaGamerBase.addConverter(sender -> { + //System.out.println("Discord converter queried: "+sender+" "+sender.getName()); - TODO: Remove + //System.out.println(((DiscordSenderBase) sender).getChromaUser().channel().get().ID); //TODO: TMP + return Optional.ofNullable(sender instanceof DiscordSenderBase + ? ((DiscordSenderBase) sender).getChromaUser() : null); + }); new Thread(this::AnnouncementGetterThreadMethod).start(); setupProviders(); } catch (Exception e) { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index 5cd4df6..8ad7445 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -86,12 +86,12 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { } @Override - public boolean isOp() { // TODO: Connect with TBMC acc + public boolean isOp() { return false; } @Override - public void setOp(boolean value) { // TODO: Connect with TBMC acc + public void setOp(boolean value) { } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index ec2a04b..73eefd1 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -4,7 +4,6 @@ import buttondevteam.discordplugin.ChannelconBroadcast; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.listeners.MCChatListener; -import buttondevteam.lib.TBMCChannelConnectFakeEvent; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; @@ -79,18 +78,17 @@ public class ChannelconCommand extends DiscordCommandBase { return true; } DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()); - val ev = new TBMCChannelConnectFakeEvent(dcp, chan.get()); //Using a fake player with no login/logout, should be fine for this event - String groupid = ev.getGroupID(ev.getSender()); //We're not trying to send in a specific group, we want to know which group the user belongs to (so not getGroupID()) + String groupid = chan.get().getGroupID(dcp); if (groupid == null) { message.reply("sorry, that didn't work. You cannot use that Minecraft channel."); return true; } - if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) { + /*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."); return true; - } - MCChatListener.addCustomChat(message.getChannel(), groupid, ev.getChannel(), message.getAuthor(), dcp, 0); + }*/ //TODO: "Channel admins" that can connect channels? + MCChatListener.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0); message.reply("alright, connection made to group `" + groupid + "`!"); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 6db4a81..4d73c83 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -2,7 +2,10 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; -import buttondevteam.lib.*; +import buttondevteam.lib.TBMCChatEvent; +import buttondevteam.lib.TBMCChatPreprocessEvent; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; @@ -125,7 +128,7 @@ public class MCChatListener implements Listener, IListener Predicate isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase) || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); - if ((e.getChannel() == Channel.GlobalChat || e.getChannel().ID.equals("rp")) + if (e.getChannel().isGlobal() && (e.isFromcmd() || isdifferentchannel.test(DiscordPlugin.chatchannel))) doit.accept(lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null) @@ -304,9 +307,10 @@ public class MCChatListener implements Listener, IListener return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID()); } - public static CustomLMD getCustomChat(IChannel channel) { - return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); - } + @Nullable + public static CustomLMD getCustomChat(IChannel channel) { + return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); + } public static boolean removeCustomChat(IChannel channel) { lastmsgfromd.remove(channel.getLongID()); @@ -387,9 +391,8 @@ public class MCChatListener implements Listener, IListener return false; //If null then allow if (sender == null) return true; - val e = new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel); - return clmd.groupID.equals(e.getGroupID(sender)); - }).forEach(cc -> action.accept(cc.channel)); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect + return clmd.groupID.equals(clmd.mcchannel.getGroupID(sender)); + }).forEach(cc -> action.accept(cc.channel)); //TODO: Send error messages on channel connect } /** @@ -403,7 +406,7 @@ public class MCChatListener implements Listener, IListener public static void forAllowedCustomAndAllMCChat(Consumer action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { if (!DiscordPlugin.hooked || !hookmsg) forAllMCChat(action); - forAllowedCustomMCChat(action, sender, toggle); //TODO: Use getScore and getGroupID in fake event constructor - This should also send error messages on channel connect + forAllowedCustomMCChat(action, sender, toggle); } public static Consumer send(String message) { @@ -411,7 +414,7 @@ public class MCChatListener implements Listener, IListener } public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { - if (Channel.GlobalChat.ID.equals(event.getChannel().ID)) + if (event.getChannel().isGlobal()) action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : lastmsgPerUser) if (event.shouldSendTo(getSender(data.channel, data.user))) @@ -562,23 +565,29 @@ public class MCChatListener implements Listener, IListener .filter(c -> c.ID.equalsIgnoreCase(topcmd) || (c.IDs != null && c.IDs.length > 0 && Arrays.stream(c.IDs).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny(); - if (!ch.isPresent()) - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, - () -> { - val channel = dsender.getChromaUser().channel(); //TODO: Save? + 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 + //System.out.println("1: "+chtmp.ID); + //System.out.println("clmd: "+clmd); + if (clmd != null) { + channel.set(clmd.mcchannel); //Hack to send command in the channel + //System.out.println("clmd chan: "+clmd.mcchannel.ID); + } //TODO: Permcheck isn't implemented for commands + //System.out.println("2: "+channel.get().ID); VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); if (clmd != null) channel.set(chtmp); + //System.out.println("3: "+channel.get().ID); - TODO: Remove }); else { Channel chc = ch.get(); - if (!chc.ID.equals(Channel.GlobalChat.ID) && !chc.ID.equals("rp") && !event.getMessage().getChannel().isPrivate()) + if (!chc.isGlobal() && !event.getMessage().getChannel().isPrivate()) dsender.sendMessage( - "You can only talk in global in the public chat. DM `mcchat` to enable private chat to talk in the other channels."); + "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 { @@ -609,10 +618,12 @@ public class MCChatListener implements Listener, IListener lastlistp = (short) Bukkit.getOnlinePlayers().size(); } else {// Not a command if (dmessage.length() == 0 && event.getMessage().getAttachments().size() == 0 - && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, 0, "everyone", - (dsender instanceof Player ? ((Player) dsender).getDisplayName() - : dsender.getName()) + " pinned a message on Discord."); + && !event.getChannel().isPrivate() && event.getMessage().isSystemMessage()) { + val rtr = clmd != null ? clmd.mcchannel.filteranderrormsg.apply(clmd.dcp) : dsender.getChromaUser().channel().get().filteranderrormsg.apply(dsender); + TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr.score, rtr.groupID, + (dsender instanceof Player ? ((Player) dsender).getDisplayName() + : dsender.getName()) + " pinned a message on Discord."); + } else { val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); if (clmd != null) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index e7d57ec..6f9b3c9 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -137,7 +137,7 @@ public class MCListener implements Listener { return; final IUser user = DiscordPlugin.dc.getUserByID( Long.parseLong(TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) - .getAs(DiscordPlayer.class).getDiscordID())); // TODO: Use long + .getAs(DiscordPlayer.class).getDiscordID())); if (e.getValue()) user.addRole(role); else @@ -163,6 +163,7 @@ public class MCListener implements Listener { public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() : event.getSender().getName(); + //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatListener.forAllMCChat(MCChatListener.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } -- 2.30.2 From 8721b623cb83393495acd050decb6ab8719f0b34 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 1 Nov 2018 21:47:40 +0100 Subject: [PATCH 021/108] Fix --- .../discordplugin/commands/RoleCommand.java | 10 +++++----- .../discordplugin/mccommands/ResetMCCommand.java | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java index dbe8988..3978c6a 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java @@ -59,19 +59,19 @@ public class RoleCommand extends DiscordCommandBase { DiscordPlugin.sendMessageToChannel(message.getChannel(), usage + "\nUsage: " + argsa[0] + " "); return null; } - String rolename = argsa[1]; + StringBuilder rolename = new StringBuilder(argsa[1]); for (int i = 2; i < argsa.length; i++) - rolename += " " + argsa[i]; - if (!DiscordPlugin.GameRoles.contains(rolename)) { + rolename.append(" ").append(argsa[i]); + if (!DiscordPlugin.GameRoles.contains(rolename.toString())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "That game role cannot be found."); listRoles(message); return null; } - final List roles = DiscordPlugin.mainServer.getRolesByName(rolename); + final List roles = DiscordPlugin.mainServer.getRolesByName(rolename.toString()); if (roles.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified role cannot be found on Discord! Removing from the list."); - DiscordPlugin.GameRoles.remove(rolename); + DiscordPlugin.GameRoles.remove(rolename.toString()); return null; } if (roles.size() > 1) { diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java index fce8d04..1f4855f 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/ResetMCCommand.java @@ -1,6 +1,7 @@ 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; @@ -15,9 +16,11 @@ public class ResetMCCommand extends TBMCCommandBase { //Not player-only, so not resetting = true; //Turned off after sending enable message (ReadyEvent) sender.sendMessage("§bDisabling DiscordPlugin..."); Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); - sender.sendMessage("§bEnabling DiscordPlugin..."); + if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors + sender.sendMessage("§bEnabling DiscordPlugin..."); Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin); - sender.sendMessage("§bReset finished!"); + if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors + sender.sendMessage("§bReset finished!"); }); return true; } -- 2.30.2 From d12fe961c03e8e608b81714c53429be759277aee Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 22 Nov 2018 01:02:20 +0100 Subject: [PATCH 022/108] No Origins --- pom.xml | 2 +- .../java/buttondevteam/discordplugin/DiscordSenderBase.java | 4 ++-- .../buttondevteam/discordplugin/listeners/MCChatListener.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index f283fc7..c9f7680 100755 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ com.github.TBMCPlugins.ButtonCore ButtonCore - master-SNAPSHOT + ${env.TRAVIS_BRANCH}-SNAPSHOT provided diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index 14c7fc4..ea2f1a7 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -1,13 +1,13 @@ package buttondevteam.discordplugin; import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.IDiscordSender; 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; -public abstract class DiscordSenderBase implements IDiscordSender { +public abstract class DiscordSenderBase implements CommandSender { /** * May be null. */ diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 4d73c83..5f1792d 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -81,7 +81,7 @@ public class MCChatListener implements Listener, IListener time = se.getValue(); final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName) + "] " // - + (e.getSender() instanceof DiscordSenderBase ? "[D]" : "") // + + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin() + "]") // + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // ? ((Player) e.getSender()).getDisplayName() // : e.getSender().getName())); -- 2.30.2 From 9527be99d11d2dea0ece2e7d7a96393e8f307fe5 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 22 Nov 2018 23:11:19 +0100 Subject: [PATCH 023/108] Fixed 122 errors - by fixing the pom Also other fixes --- pom.xml | 18 +++++++++++++++++- .../discordplugin/DiscordSenderBase.java | 1 + .../listeners/MCChatListener.java | 4 ++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c9f7680..030db19 100755 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,7 @@ UTF-8 + master @@ -173,7 +174,7 @@ com.github.TBMCPlugins.ButtonCore ButtonCore - ${env.TRAVIS_BRANCH}-SNAPSHOT + ${branch}-SNAPSHOT provided @@ -225,4 +226,19 @@ 4.0.0 + + + + ci + + + env.TRAVIS_BRANCH + + + + + ${env.TRAVIS_BRANCH} + + + diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index ea2f1a7..b031bcb 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -51,6 +51,7 @@ public abstract class DiscordSenderBase implements CommandSender { public void sendMessage(String message) { try { final boolean broadcast = new Exception().getStackTrace()[2].getMethodName().contains("broadcast"); + //if (broadcast && DiscordPlugin.hooked) - TODO: What should happen if unhooked if (broadcast) return; final String sendmsg = DPUtils.sanitizeString(message); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 5f1792d..98a0b75 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -39,8 +39,8 @@ import sx.blah.discord.util.MissingPermissionsException; import javax.annotation.Nullable; import java.awt.*; import java.time.Instant; -import java.util.*; import java.util.List; +import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; @@ -81,7 +81,7 @@ public class MCChatListener implements Listener, IListener time = se.getValue(); final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName) + "] " // - + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin() + "]") // + + ("Minecraft".equals(e.getOrigin()) ? "" : "[" + e.getOrigin().substring(0, 1) + "]") // + (DPUtils.sanitizeStringNoEscape(e.getSender() instanceof Player // ? ((Player) e.getSender()).getDisplayName() // : e.getSender().getName())); -- 2.30.2 From 38b45299c0fa6679315df6d63e4a406842de3fa9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 14 Dec 2018 23:58:24 +0100 Subject: [PATCH 024/108] Adding two modules GeneralEventBroadcaster Minecraft chat #51 --- .../discordplugin/DiscordPlugin.java | 32 ++------- .../GeneralEventBroadcasterModule.java | 34 +++++++++ .../{ => broadcaster}/PlayerListWatcher.java | 71 ++++++++----------- .../discordplugin/commands/DebugCommand.java | 4 +- .../commands/DiscordCommandBase.java | 2 +- ...mandListener.java => CommonListeners.java} | 4 +- .../listeners/MCChatListener.java | 17 +++-- .../mcchat/MinecraftChatModule.java | 20 ++++++ 8 files changed, 107 insertions(+), 77 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java rename src/main/java/buttondevteam/discordplugin/{ => broadcaster}/PlayerListWatcher.java (82%) rename src/main/java/buttondevteam/discordplugin/listeners/{CommandListener.java => CommonListeners.java} (97%) create mode 100644 src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index be7e8a9..e486a5d 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,13 +1,16 @@ package buttondevteam.discordplugin; +import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.DiscordCommandBase; -import buttondevteam.discordplugin.listeners.CommandListener; +import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.ExceptionListener; import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.discordplugin.listeners.MCListener; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; @@ -51,22 +54,12 @@ public class DiscordPlugin extends JavaPlugin implements IListener { public static DiscordPlugin plugin; public static boolean SafeMode = true; public static List GameRoles; - public static boolean hooked = false; - @SuppressWarnings("unchecked") @Override public void onEnable() { stop = false; //If not the first time try { Bukkit.getLogger().info("Initializing DiscordPlugin..."); - try { - PlayerListWatcher.hookUp(); - hooked = true; - Bukkit.getLogger().info("Finished hooking into the player list"); - } catch (Throwable e) { - e.printStackTrace(); - Bukkit.getLogger().warning("Couldn't hook into the player list!"); - } plugin = this; lastannouncementtime = getConfig().getLong("lastannouncementtime"); lastseentime = getConfig().getLong("lastseentime"); @@ -212,11 +205,10 @@ public class DiscordPlugin extends JavaPlugin implements IListener { }*/ } }, 0, 10); - for (IListener listener : CommandListener.getListeners()) + for (IListener listener : CommonListeners.getListeners()) dc.getDispatcher().registerListener(listener); - MCChatListener mcchat = new MCChatListener(); - dc.getDispatcher().registerListener(mcchat); - TBMCCoreAPI.RegisterEventsForExceptions(mcchat, this); + Component.registerComponent(this, new GeneralEventBroadcasterModule()); + Component.registerComponent(this, new MinecraftChatModule()); Bukkit.getPluginManager().registerEvents(new ExceptionListener(), this); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); @@ -299,16 +291,6 @@ public class DiscordPlugin extends JavaPlugin implements IListener { try { SafeMode = true; // Stop interacting with Discord MCChatListener.stop(true); - try { - if (PlayerListWatcher.hookDown()) - System.out.println("Finished unhooking the player list!"); - else - System.out.println("Didn't have the player list hooked."); - hooked = false; - } catch (Throwable e) { - e.printStackTrace(); - Bukkit.getLogger().warning("Couldn't unhook the player list!"); - } ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java new file mode 100644 index 0000000..471a56f --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -0,0 +1,34 @@ +package buttondevteam.discordplugin.broadcaster; + +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; +import lombok.Getter; +import org.bukkit.Bukkit; + +public class GeneralEventBroadcasterModule extends Component { + private static @Getter boolean hooked = false; + + @Override + protected void enable() { + try { + PlayerListWatcher.hookUp(); + Bukkit.getLogger().info("Finished hooking into the player list"); + hooked = true; + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while hacking the player list!", e); + } + } + + @Override + protected void disable() { + try { + if (PlayerListWatcher.hookDown()) + System.out.println("Finished unhooking the player list!"); + else + System.out.println("Didn't have the player list hooked."); + hooked = false; + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while hacking the player list!", e); + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java similarity index 82% rename from src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java rename to src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index 432b75c..1eb9a42 100755 --- a/src/main/java/buttondevteam/discordplugin/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -1,4 +1,4 @@ -package buttondevteam.discordplugin; +package buttondevteam.discordplugin.broadcaster; import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.lib.TBMCCoreAPI; @@ -53,52 +53,43 @@ public class PlayerListWatcher extends DedicatedPlayerList { } @Override - public void sendMessage(IChatBaseComponent[] iChatBaseComponents) { // Needed so it calls the overriden method + public void sendMessage(IChatBaseComponent[] iChatBaseComponents) { // Needed so it calls the overridden method for (IChatBaseComponent component : iChatBaseComponents) { sendMessage(component, true); } } - public static void hookUp() { - try { - Field conf = CraftServer.class.getDeclaredField("console"); - conf.setAccessible(true); - val server = (MinecraftServer) conf.get(Bukkit.getServer()); - val plw = new ObjenesisStd().newInstance(PlayerListWatcher.class); // Cannot call super constructor - plw.plist = (DedicatedPlayerList) server.getPlayerList(); - plw.maxPlayers = plw.plist.getMaxPlayers(); - Field plf = plw.getClass().getField("players"); - plf.setAccessible(true); - Field modf = plf.getClass().getDeclaredField("modifiers"); - modf.setAccessible(true); - modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); - plf.set(plw, plw.plist.players); - server.a(plw); - Field pllf = CraftServer.class.getDeclaredField("playerList"); - pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), plw); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while hacking the player list!", e); - } + static void hookUp() throws Exception { + Field conf = CraftServer.class.getDeclaredField("console"); + conf.setAccessible(true); + val server = (MinecraftServer) conf.get(Bukkit.getServer()); + val plw = new ObjenesisStd().newInstance(PlayerListWatcher.class); // Cannot call super constructor + plw.plist = (DedicatedPlayerList) server.getPlayerList(); + plw.maxPlayers = plw.plist.getMaxPlayers(); + Field plf = plw.getClass().getField("players"); + plf.setAccessible(true); + Field modf = plf.getClass().getDeclaredField("modifiers"); + modf.setAccessible(true); + modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); + plf.set(plw, plw.plist.players); + server.a(plw); + Field pllf = CraftServer.class.getDeclaredField("playerList"); + pllf.setAccessible(true); + pllf.set(Bukkit.getServer(), plw); } - public static boolean hookDown() { - try { - Field conf = CraftServer.class.getDeclaredField("console"); - conf.setAccessible(true); - val server = (MinecraftServer) conf.get(Bukkit.getServer()); - val plist = (DedicatedPlayerList) server.getPlayerList(); - if (!(plist instanceof PlayerListWatcher)) - return false; - server.a(((PlayerListWatcher) plist).plist); - Field pllf = CraftServer.class.getDeclaredField("playerList"); - pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist); - return true; - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while hacking the player list!", e); - return true; - } + static boolean hookDown() throws Exception { + Field conf = CraftServer.class.getDeclaredField("console"); + conf.setAccessible(true); + val server = (MinecraftServer) conf.get(Bukkit.getServer()); + val plist = (DedicatedPlayerList) server.getPlayerList(); + if (!(plist instanceof PlayerListWatcher)) + return false; + server.a(((PlayerListWatcher) plist).plist); + Field pllf = CraftServer.class.getDeclaredField("playerList"); + pllf.setAccessible(true); + pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist); + return true; } public void a(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) { diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index 1b6a605..b37e2b8 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -1,7 +1,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.listeners.CommandListener; +import buttondevteam.discordplugin.listeners.CommonListeners; import sx.blah.discord.handle.obj.IMessage; public class DebugCommand extends DiscordCommandBase { @@ -13,7 +13,7 @@ public class DebugCommand extends DiscordCommandBase { @Override public boolean run(IMessage message, String args) { if (message.getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L))) - message.reply("Debug " + (CommandListener.debug() ? "enabled" : "disabled")); + message.reply("Debug " + (CommonListeners.debug() ? "enabled" : "disabled")); else message.reply("You need to be a moderator to use this command."); return true; diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index 34790b6..a4da021 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -8,7 +8,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.stream.Collectors; -import static buttondevteam.discordplugin.listeners.CommandListener.debug; +import static buttondevteam.discordplugin.listeners.CommonListeners.debug; public abstract class DiscordCommandBase { public abstract String getCommandName(); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java similarity index 97% rename from src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java rename to src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index f46abff..ba5b6e0 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -23,7 +23,7 @@ import java.util.Calendar; import java.util.Random; import java.util.concurrent.TimeUnit; -public class CommandListener { +public class CommonListeners { private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali "Between now and the heat-death of the universe.", // Ghostise @@ -200,7 +200,7 @@ public class CommandListener { private static boolean debug = false; public static void debug(String debug) { - if (CommandListener.debug) //Debug + if (CommonListeners.debug) //Debug System.out.println(debug); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 98a0b75..0860efd 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -1,6 +1,9 @@ package buttondevteam.discordplugin.listeners; +import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.*; +import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; @@ -58,7 +61,7 @@ public class MCChatListener implements Listener, IListener @EventHandler // Minecraft public void onMCChat(TBMCChatEvent ev) { - if (DiscordPlugin.SafeMode || ev.isCancelled()) //SafeMode: Needed so it doesn't restart after server shutdown + 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) @@ -368,7 +371,7 @@ public class MCChatListener implements Listener, IListener * @param hookmsg Whether the message is also sent from the hook */ public static void forCustomAndAllMCChat(Consumer action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { - if (!DiscordPlugin.hooked || !hookmsg) + if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); final Consumer customLMDConsumer = cc -> action.accept(cc.channel); if (toggle == null) @@ -404,7 +407,7 @@ public class MCChatListener implements Listener, IListener * @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) { - if (!DiscordPlugin.hooked || !hookmsg) + if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); forAllowedCustomMCChat(action, sender, toggle); } @@ -463,9 +466,9 @@ public class MCChatListener implements Listener, IListener private Runnable recrun; private static Thread recthread; - @Override // Discord + @Override // Discord - TODO: Call from the common listener public void handle(MessageReceivedEvent ev) { - if (DiscordPlugin.SafeMode) + if (!ComponentManager.isEnabled(MinecraftChatModule.class)) return; val author = ev.getMessage().getAuthor(); if (author.isBot()) @@ -476,8 +479,8 @@ public class MCChatListener implements Listener, IListener && !hasCustomChat) return; if (ev.getMessage().getContent().equalsIgnoreCase("mcchat")) - return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommandListener) - if (CommandListener.runCommand(ev.getMessage(), true)) + return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommonListeners) + if (CommonListeners.runCommand(ev.getMessage(), true)) return; resetLastMessage(ev.getChannel()); lastlist++; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java new file mode 100644 index 0000000..709b055 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -0,0 +1,20 @@ +package buttondevteam.discordplugin.mcchat; + +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; + +public class MinecraftChatModule extends Component { + @Override + protected void enable() { + MCChatListener mcchat = new MCChatListener(); + DiscordPlugin.dc.getDispatcher().registerListener(mcchat); + TBMCCoreAPI.RegisterEventsForExceptions(mcchat, getPlugin()); + } + + @Override + protected void disable() { + //These get undone if restarting/resetting - it will ignore events if disabled + } //TODO: Use ComponentManager.isEnabled() at other places too, instead of SafeMode +} -- 2.30.2 From 1878a46041c57d01606720ee769050295ef9b8f5 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 17 Dec 2018 21:33:55 +0100 Subject: [PATCH 025/108] Cleanup, organizing (MCChatListener) Removed all sysouts Split MCChatListener into utils, private and custom (and the existing one) Using fixed version of Discord4J (fixes issues with local testing) --- pom.xml | 19 +- .../discordplugin/ChromaBot.java | 16 +- .../buttondevteam/discordplugin/DPUtils.java | 7 + .../discordplugin/DiscordPlayer.java | 6 +- .../discordplugin/DiscordPlugin.java | 24 +- .../GeneralEventBroadcasterModule.java | 5 +- .../broadcaster/PlayerListWatcher.java | 4 +- .../commands/ChannelconCommand.java | 10 +- .../discordplugin/commands/MCChatCommand.java | 4 +- .../listeners/CommonListeners.java | 9 +- .../discordplugin/listeners/MCListener.java | 27 +- .../discordplugin/mcchat/MCChatCustom.java | 59 ++++ .../{listeners => mcchat}/MCChatListener.java | 313 ++---------------- .../discordplugin/mcchat/MCChatPrivate.java | 55 +++ .../discordplugin/mcchat/MCChatUtils.java | 182 ++++++++++ .../mcchat/MinecraftChatModule.java | 1 - .../mccommands/AcceptMCCommand.java | 4 +- 17 files changed, 402 insertions(+), 343 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java rename src/main/java/buttondevteam/discordplugin/{listeners => mcchat}/MCChatListener.java (60%) create mode 100644 src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java create mode 100644 src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java diff --git a/pom.xml b/pom.xml index 030db19..0ccfe46 100755 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,9 @@ UTF-8 - master + + master + @@ -160,11 +162,16 @@ provided - - com.discord4j - Discord4J - 2.10.1 - + + + com.github.SizableShrimp + Discord4J + httprequestchange-SNAPSHOT + org.slf4j diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index 79a0514..90e5afb 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -43,7 +43,7 @@ public class ChromaBot { * The message to send, duh */ public void sendMessage(String message) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message)); + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message)); } /** @@ -55,7 +55,7 @@ public class ChromaBot { * Custom fancy stuff, use {@link EmbedBuilder} to create one */ public void sendMessage(String message, EmbedObject embed) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed)); } /** @@ -66,7 +66,7 @@ public class ChromaBot { * @param toggle The toggle type for channelcon */ public void sendMessageCustomAsWell(String message, EmbedObject embed, @Nullable ChannelconBroadcast toggle) { - MCChatListener.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed), toggle, false); + MCChatUtils.forCustomAndAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, embed), toggle, false); } /** @@ -92,7 +92,7 @@ public class ChromaBot { * The color of the line before the text */ public void sendMessage(String message, Color color) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, new EmbedBuilder().withTitle(message).withColor(color).build())); } @@ -107,7 +107,7 @@ public class ChromaBot { * The name of the Minecraft player who is the author of this message */ public void sendMessage(String message, Color color, String mcauthor) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, DPUtils.embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), mcauthor).build())); } @@ -124,7 +124,7 @@ public class ChromaBot { * The URL of the avatar image for this message's author */ public void sendMessage(String message, Color color, String authorname, String authorimg) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, new EmbedBuilder() + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, new EmbedBuilder() .withTitle(message).withColor(color).withAuthorName(authorname).withAuthorIcon(authorimg).build())); } @@ -139,7 +139,7 @@ public class ChromaBot { * The player who sends this message */ public void sendMessage(String message, Color color, Player sender) { - MCChatListener.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, DPUtils + MCChatUtils.forAllMCChat(ch -> DiscordPlugin.sendMessageToChannel(ch, message, DPUtils .embedWithHead(new EmbedBuilder().withTitle(message).withColor(color), sender.getName()).build())); } diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index ea4d14d..f68053a 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -9,6 +9,7 @@ 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; public final class DPUtils { @@ -96,4 +97,10 @@ public final class DPUtils { return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\")+"$1"); } + public static Logger getLogger() { + if (DiscordPlugin.plugin == null || DiscordPlugin.plugin.getLogger() == null) + return Logger.getLogger("DiscordPlugin"); + return DiscordPlugin.plugin.getLogger(); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java index ec7863c..0055792 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.UserClass; @@ -20,9 +20,9 @@ public class DiscordPlayer extends ChromaGamerBase { /** * Returns true if player has the private Minecraft chat enabled. For setting the value, see - * {@link MCChatListener#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)} + * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.IChannel, boolean, sx.blah.discord.handle.obj.IUser, DiscordPlayer)} */ public boolean isMinecraftChatEnabled() { - return MCChatListener.isMinecraftChatEnabled(this); + return MCChatPrivate.isMinecraftChatEnabled(this); } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index e486a5d..02709d1 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -4,8 +4,10 @@ import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.ExceptionListener; -import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.discordplugin.listeners.MCListener; +import buttondevteam.discordplugin.mcchat.MCChatCustom; +import buttondevteam.discordplugin.mcchat.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; @@ -149,7 +151,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { val toggles = chcon.getInt("toggles"); if (!mcch.isPresent() || ch == null || user == null || groupid == null) continue; - MCChatListener.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles); + MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles); } } @@ -213,12 +215,8 @@ public class DiscordPlugin extends JavaPlugin implements IListener { TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - ChromaGamerBase.addConverter(sender -> { - //System.out.println("Discord converter queried: "+sender+" "+sender.getName()); - TODO: Remove - //System.out.println(((DiscordSenderBase) sender).getChromaUser().channel().get().ID); //TODO: TMP - return Optional.ofNullable(sender instanceof DiscordSenderBase - ? ((DiscordSenderBase) sender).getChromaUser() : null); - }); + ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase + ? ((DiscordSenderBase) sender).getChromaUser() : null)); new Thread(this::AnnouncementGetterThreadMethod).start(); setupProviders(); } catch (Exception e) { @@ -242,15 +240,15 @@ public class DiscordPlugin extends JavaPlugin implements IListener { @Override public void onDisable() { stop = true; - for (val entry : MCChatListener.ConnectedSenders.entrySet()) + for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) MCListener.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); - MCChatListener.ConnectedSenders.clear(); + MCChatUtils.ConnectedSenders.clear(); getConfig().set("lastannouncementtime", lastannouncementtime); getConfig().set("lastseentime", lastseentime); getConfig().set("serverup", false); - val chcons = MCChatListener.getCustomChats(); + val chcons = MCChatCustom.getCustomChats(); val chconsc = getConfig().createSection("chcons"); for (val chcon : chcons) { val chconc = chconsc.createSection(chcon.channel.getStringID()); @@ -279,7 +277,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { + "kicked the hell out.") //TODO: Make configurable : "") //If 'restart' is disabled then this isn't shown even if joinleave is enabled .build(); - MCChatListener.forCustomAndAllMCChat(ch -> { + MCChatUtils.forCustomAndAllMCChat(ch -> { try { DiscordPlugin.sendMessageToChannelWait(ch, "", embed, 5, TimeUnit.SECONDS); @@ -406,7 +404,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { .warning("Message was too long to send to discord and got truncated. In " + channel.getName()); } try { - MCChatListener.resetLastMessage(channel); // If this is a chat message, it'll be set again + 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); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 471a56f..8830f37 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.broadcaster; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import lombok.Getter; @@ -23,9 +24,9 @@ public class GeneralEventBroadcasterModule extends Component { protected void disable() { try { if (PlayerListWatcher.hookDown()) - System.out.println("Finished unhooking the player list!"); + DPUtils.getLogger().info("Finished unhooking the player list!"); else - System.out.println("Didn't have the player list hooked."); + DPUtils.getLogger().info("Didn't have the player list hooked."); hooked = false; } catch (Exception e) { TBMCCoreAPI.SendException("Error while hacking the player list!", e); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index 1eb9a42..eafe7f5 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin.broadcaster; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.TBMCCoreAPI; import com.mojang.authlib.GameProfile; import lombok.val; @@ -30,7 +30,7 @@ public class PlayerListWatcher extends DedicatedPlayerList { if (packet instanceof PacketPlayOutChat) { Field msgf = PacketPlayOutChat.class.getDeclaredField("a"); msgf.setAccessible(true); - MCChatListener.forAllMCChat(MCChatListener.send(((IChatBaseComponent) msgf.get(packet)).toPlainText())); + MCChatUtils.forAllMCChat(MCChatUtils.send(((IChatBaseComponent) msgf.get(packet)).toPlainText())); } } catch (Exception e) { TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index 73eefd1..a018a1e 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -3,7 +3,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.ChannelconBroadcast; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatCustom; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; @@ -30,16 +30,16 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("you need to have manage permissions for this channel!"); return true; } - if (MCChatListener.hasCustomChat(message.getChannel())) { + if (MCChatCustom.hasCustomChat(message.getChannel())) { if (args.toLowerCase().startsWith("remove")) { - if (MCChatListener.removeCustomChat(message.getChannel())) + if (MCChatCustom.removeCustomChat(message.getChannel())) message.reply("channel connection removed."); else message.reply("wait what, couldn't remove channel connection."); return true; } if (args.toLowerCase().startsWith("toggle")) { - val cc = MCChatListener.getCustomChat(message.getChannel()); + val cc = MCChatCustom.getCustomChat(message.getChannel()); Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")); String[] argsa = args.split(" "); if (argsa.length < 2) { @@ -88,7 +88,7 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("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? - MCChatListener.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0); + MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0); message.reply("alright, connection made to group `" + groupid + "`!"); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java index e2ca2ca..7a5b7c8 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java @@ -2,7 +2,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.lib.TBMCCoreAPI; import sx.blah.discord.handle.obj.IMessage; @@ -22,7 +22,7 @@ public class MCChatCommand extends DiscordCommandBase { } try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); - MCChatListener.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); + MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); DiscordPlugin.sendMessageToChannel(message.getChannel(), "Minecraft chat " + (mcchat // ? "enabled. Use '/mcchat' again to turn it off." // diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index ba5b6e0..737e5cf 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -1,7 +1,10 @@ package buttondevteam.discordplugin.listeners; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.mcchat.MCChatCustom; +import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.lib.TBMCCoreAPI; import lombok.val; import org.bukkit.Bukkit; @@ -72,7 +75,7 @@ public class CommonListeners { return; final IChannel channel = event.getMessage().getChannel(); if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()) - && (!event.getMessage().getContent().contains("channelcon") || MCChatListener.hasCustomChat(channel))) //Allow channelcon in other servers but avoid double handling when it's enabled + && (!event.getMessage().getContent().contains("channelcon") || MCChatCustom.hasCustomChat(channel))) //Allow channelcon in other servers but avoid double handling when it's enabled return; if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID())) return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel @@ -98,7 +101,7 @@ public class CommonListeners { && !(event.getMessage().getContent().startsWith("/") && event.getChannel().getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // return; - if (MCChatListener.isMinecraftChatEnabled(event.getAuthor().toString())) + if (MCChatPrivate.isMinecraftChatEnabled(event.getAuthor().toString())) if (!event.getMessage().getContent().equalsIgnoreCase("mcchat")) return; if (event.getMessage().getAuthor().isBot()) @@ -201,7 +204,7 @@ public class CommonListeners { public static void debug(String debug) { if (CommonListeners.debug) //Debug - System.out.println(debug); + DPUtils.getLogger().info(debug); } public static boolean debug() { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 6f9b3c9..cd8a826 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -2,6 +2,8 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.discordplugin.mcchat.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.player.*; @@ -36,7 +38,7 @@ public class MCListener implements Listener { public void onPlayerLogin(PlayerLoginEvent e) { if (e.getResult() != Result.ALLOWED) return; - MCChatListener.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) //Only private mcchat should be in ConnectedSenders + 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 -> callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); } @@ -50,9 +52,9 @@ public class MCListener implements Listener { DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); if (dp != null) { val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); - MCChatListener.addSender(MCChatListener.OnlineSenders, dp.getDiscordID(), + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); - MCChatListener.addSender(MCChatListener.OnlineSenders, dp.getDiscordID(), + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel } if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { @@ -63,8 +65,7 @@ public class MCListener implements Listener { p.sendMessage("§bIf it wasn't you, do /discord decline"); } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; - MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); - //System.out.println("Does this appear more than once?"); //No + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); }); @@ -74,16 +75,16 @@ public class MCListener implements Listener { public void onPlayerLeave(TBMCPlayerQuitEvent e) { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Only care about real users - MCChatListener.OnlineSenders.entrySet() + MCChatUtils.OnlineSenders.entrySet() .removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()))); Bukkit.getScheduler().runTask(DiscordPlugin.plugin, - () -> MCChatListener.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) + () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; - MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } @EventHandler(priority = EventPriority.HIGHEST) @@ -109,7 +110,7 @@ public class MCListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerDeath(PlayerDeathEvent e) { - MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); } @EventHandler @@ -119,7 +120,7 @@ public class MCListener implements Listener { return; final String msg = base.getDisplayName() + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; - MCChatListener.forAllowedCustomAndAllMCChat(MCChatListener.send(msg), base, ChannelconBroadcast.AFK, false); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); } @EventHandler @@ -151,12 +152,12 @@ public class MCListener implements Listener { @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { - MCChatListener.forAllowedMCChat(MCChatListener.send(event.getMessage()), event); + MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event); } @EventHandler public void onBroadcastMessage(BroadcastMessageEvent event) { - MCChatListener.forCustomAndAllMCChat(MCChatListener.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); + MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); } @EventHandler @@ -164,7 +165,7 @@ public 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 - MCChatListener.forAllMCChat(MCChatListener.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); + MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java new file mode 100644 index 0000000..74979f8 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -0,0 +1,59 @@ +package buttondevteam.discordplugin.mcchat; + +import buttondevteam.discordplugin.DiscordConnectedPlayer; +import buttondevteam.lib.chat.Channel; +import lombok.NonNull; +import lombok.val; +import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IUser; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MCChatCustom { + /** + * Used for town or nation chats or anything else + */ + static ArrayList lastmsgCustom = new ArrayList<>(); + + public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles) { + val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles); + lastmsgCustom.add(lmd); + } + + public static boolean hasCustomChat(IChannel channel) { + return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID()); + } + + @Nullable + public static CustomLMD getCustomChat(IChannel channel) { + return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); + } + + public static boolean removeCustomChat(IChannel channel) { + MCChatUtils.lastmsgfromd.remove(channel.getLongID()); + return lastmsgCustom.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); + } + + public static List getCustomChats() { + return Collections.unmodifiableList(lastmsgCustom); + } + + public static class CustomLMD extends MCChatUtils.LastMsgData { + public final String groupID; + public final Channel mcchannel; + public final DiscordConnectedPlayer dcp; + public int toggles; + + private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, + @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles) { + super(channel, user); + groupID = groupid; + this.mcchannel = mcchannel; + this.dcp = dcp; + this.toggles = toggles; + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java similarity index 60% rename from src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java rename to src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 0860efd..f81c01d 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -1,57 +1,47 @@ -package buttondevteam.discordplugin.listeners; +package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; -import buttondevteam.discordplugin.*; -import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; -import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.DiscordSender; +import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; -import io.netty.util.collection.LongObjectHashMap; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.experimental.var; import lombok.val; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.api.events.IListener; 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.IPrivateChannel; import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.MissingPermissionsException; -import javax.annotation.Nullable; import java.awt.*; import java.time.Instant; -import java.util.List; -import java.util.*; +import java.util.AbstractMap; +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.function.Supplier; import java.util.stream.Collectors; -import java.util.stream.Stream; public class MCChatListener implements Listener, IListener { private BukkitTask sendtask; @@ -105,7 +95,7 @@ public class MCChatListener implements Listener, IListener // embed.withFooterText(e.getChannel().DisplayName); embed.withTimestamp(time); final long nanoTime = System.nanoTime(); - InterruptibleConsumer doit = lastmsgdata -> { + InterruptibleConsumer doit = lastmsgdata -> { final EmbedObject embedObject = embed.build(); if (lastmsgdata.message == null || lastmsgdata.message.isDeleted() || !authorPlayer.equals(lastmsgdata.message.getEmbeds().get(0).getAuthor().getName()) @@ -120,7 +110,7 @@ public class MCChatListener implements Listener, IListener try { lastmsgdata.content = embedObject.description = lastmsgdata.content + "\n" + embedObject.description;// The message object doesn't get updated - final LastMsgData _lastmsgdata = lastmsgdata; + 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); @@ -133,17 +123,17 @@ public class MCChatListener implements Listener, IListener if (e.getChannel().isGlobal() && (e.isFromcmd() || isdifferentchannel.test(DiscordPlugin.chatchannel))) - doit.accept(lastmsgdata == null - ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null) - : lastmsgdata); + doit.accept(MCChatUtils.lastmsgdata == null + ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(DiscordPlugin.chatchannel, null) + : MCChatUtils.lastmsgdata); - for (LastMsgData data : lastmsgPerUser) { + for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { if ((e.isFromcmd() || isdifferentchannel.test(data.channel)) - && e.shouldSendTo(getSender(data.channel, data.user))) + && e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user))) doit.accept(data); } - val iterator = lastmsgCustom.iterator(); + val iterator = MCChatCustom.lastmsgCustom.iterator(); while (iterator.hasNext()) { val lmd = iterator.next(); if ((e.isFromcmd() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord @@ -165,32 +155,6 @@ public class MCChatListener implements Listener, IListener } } - @RequiredArgsConstructor - public static class LastMsgData { - public IMessage message; - public long time; - public String content; - public final IChannel channel; - public Channel mcchannel; - public final IUser user; - } - - public static class CustomLMD extends LastMsgData { - public final String groupID; - public final Channel mcchannel; - public final DiscordConnectedPlayer dcp; - public int toggles; - - private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, - @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles) { - super(channel, user); - groupID = groupid; - this.mcchannel = mcchannel; - this.dcp = dcp; - this.toggles = toggles; - } - } - @EventHandler public void onChatPreprocess(TBMCChatPreprocessEvent event) { int start = -1; @@ -214,72 +178,8 @@ public class MCChatListener implements Listener, IListener private static final String[] UnconnectedCmds = new String[]{"list", "u", "shrug", "tableflip", "unflip", "mwiki", "yeehaw", "lenny", "rp", "plugins"}; - private static LastMsgData lastmsgdata; private static short lastlist = 0; private static short lastlistp = 0; - /** - * Used for messages in PMs (mcchat). - */ - private static ArrayList lastmsgPerUser = new ArrayList(); - /** - * Used for town or nation chats or anything else - */ - private static ArrayList lastmsgCustom = new ArrayList<>(); - private static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks - - public static boolean privateMCChat(IChannel 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()); - val op = Bukkit.getOfflinePlayer(mcp.getUUID()); - if (start) { - val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); - addSender(ConnectedSenders, user, sender); - if (p == null)// Player is offline - If the player is online, that takes precedence - MCListener.callEventExcludingSome(new PlayerJoinEvent(sender, "")); - } else { - val sender = removeSender(ConnectedSenders, channel, user); - if (p == null)// Player is offline - If the player is online, that takes precedence - MCListener.callEventExcludingSome(new PlayerQuitEvent(sender, "")); - } - } - if (!start) - lastmsgfromd.remove(channel.getLongID()); - return start // - ? lastmsgPerUser.add(new LastMsgData(channel, user)) // Doesn't support group DMs - : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); - } - - public static T addSender(HashMap> senders, - IUser user, T sender) { - return addSender(senders, user.getStringID(), sender); - } - - 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); - senders.put(did, map); - return sender; - } - - public static T getSender(HashMap> senders, - IChannel channel, IUser user) { - var map = senders.get(user.getStringID()); - 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()); - if (map != null) - return map.remove(channel); - return null; - } // ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender // Offline public chat......x............................................ @@ -292,143 +192,8 @@ public class MCChatListener implements Listener, IListener // If online and disabling private chat, don't logout // The maps may not contain the senders for UnconnectedSenders - public static boolean isMinecraftChatEnabled(DiscordPlayer dp) { - return isMinecraftChatEnabled(dp.getDiscordID()); - } - - 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)); - } - - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles) { - val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles); - lastmsgCustom.add(lmd); - } - - public static boolean hasCustomChat(IChannel channel) { - return lastmsgCustom.stream().anyMatch(lmd -> lmd.channel.getLongID() == channel.getLongID()); - } - - @Nullable - public static CustomLMD getCustomChat(IChannel channel) { - return lastmsgCustom.stream().filter(lmd -> lmd.channel.getLongID() == channel.getLongID()).findAny().orElse(null); - } - - public static boolean removeCustomChat(IChannel channel) { - lastmsgfromd.remove(channel.getLongID()); - return lastmsgCustom.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); - } - - public static List getCustomChats() { - return Collections.unmodifiableList(lastmsgCustom); - } - - /** - * May contain P<DiscordID> as key for public chat - */ - 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 short ListC = 0; - /** - * Resets the last message, so it will start a new one instead of appending to it. - * This is used when someone (even the bot) sends a message to the channel. - * - * @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) { - if (channel.getLongID() == DiscordPlugin.chatchannel.getLongID()) { - (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, 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() ? lastmsgPerUser : lastmsgCustom) { - if (data.channel.getLongID() == channel.getLongID()) { - data.message = null; - return; - } - } - //If it gets here, it's sending a message to a non-chat channel - } - - public static void forAllMCChat(Consumer action) { - action.accept(DiscordPlugin.chatchannel); - for (LastMsgData data : lastmsgPerUser) - action.accept(data.channel); - // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat - } - - /** - * For custom and all MC chat - * - * @param action The action to act - * @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) { - if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) - forAllMCChat(action); - final Consumer customLMDConsumer = cc -> action.accept(cc.channel); - if (toggle == null) - lastmsgCustom.forEach(customLMDConsumer); - else - lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).forEach(customLMDConsumer); - } - - /** - * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. - * - * @param action The action to do - * @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) { - lastmsgCustom.stream().filter(clmd -> { - //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple - if (toggle != null && (clmd.toggles & toggle.flag) == 0) - return false; //If null then allow - 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 - } - - /** - * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. - * - * @param action The action to do - * @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 - * @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) { - 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 void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { - if (event.getChannel().isGlobal()) - action.accept(DiscordPlugin.chatchannel); - for (LastMsgData data : lastmsgPerUser) - if (event.shouldSendTo(getSender(data.channel, data.user))) - action.accept(data.channel); - lastmsgCustom.stream().filter(clmd -> { - if ((clmd.toggles & ChannelconBroadcast.BROADCAST.flag) == 0) - return false; - return event.shouldSendTo(clmd.dcp); - }).map(clmd -> clmd.channel).forEach(action); - } - /** * Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode. * @@ -448,13 +213,13 @@ public class MCChatListener implements Listener, IListener if (wait) recthread.join(5000); } - lastmsgdata = null; - lastmsgPerUser.clear(); - lastmsgCustom.clear(); - lastmsgfromd.clear(); - ConnectedSenders.clear(); + MCChatUtils.lastmsgdata = null; + MCChatPrivate.lastmsgPerUser.clear(); + MCChatCustom.lastmsgCustom.clear(); + MCChatUtils.lastmsgfromd.clear(); + MCChatUtils.ConnectedSenders.clear(); lastlist = lastlistp = ListC = 0; - UnconnectedSenders.clear(); + MCChatUtils.UnconnectedSenders.clear(); recthread = sendthread = null; } catch (InterruptedException e) { e.printStackTrace(); //This thread shouldn't be interrupted @@ -473,16 +238,16 @@ public class MCChatListener implements Listener, IListener val author = ev.getMessage().getAuthor(); if (author.isBot()) return; - final boolean hasCustomChat = hasCustomChat(ev.getChannel()); + final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getChannel()); if (!ev.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID()) - && !(ev.getMessage().getChannel().isPrivate() && isMinecraftChatEnabled(author.getStringID())) + && !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID())) && !hasCustomChat) return; if (ev.getMessage().getContent().equalsIgnoreCase("mcchat")) return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommonListeners) if (CommonListeners.runCommand(ev.getMessage(), true)) return; - resetLastMessage(ev.getChannel()); + MCChatUtils.resetLastMessage(ev.getChannel()); lastlist++; recevents.add(ev); if (rectask != null) @@ -508,7 +273,7 @@ public class MCChatListener implements Listener, IListener val sender = event.getMessage().getAuthor(); String dmessage = event.getMessage().getContent(); try { - final DiscordSenderBase dsender = getSender(event.getMessage().getChannel(), sender); + final DiscordSenderBase dsender = MCChatUtils.getSender(event.getMessage().getChannel(), sender); val user = dsender.getChromaUser(); for (IUser u : event.getMessage().getMentions()) { @@ -528,7 +293,7 @@ public class MCChatListener implements Listener, IListener .getAttachments().stream().map(IMessage.Attachment::getUrl).collect(Collectors.joining("\n")) : ""); - CustomLMD clmd = getCustomChat(event.getChannel()); + MCChatCustom.CustomLMD clmd = MCChatCustom.getCustomChat(event.getChannel()); boolean react = false; @@ -573,18 +338,13 @@ public class MCChatListener implements Listener, IListener () -> { //TODO: Better handling... val channel = user.channel(); val chtmp = channel.get(); - //System.out.println("1: "+chtmp.ID); - //System.out.println("clmd: "+clmd); if (clmd != null) { channel.set(clmd.mcchannel); //Hack to send command in the channel - //System.out.println("clmd chan: "+clmd.mcchannel.ID); } //TODO: Permcheck isn't implemented for commands - //System.out.println("2: "+channel.get().ID); VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); if (clmd != null) channel.set(chtmp); - //System.out.println("3: "+channel.get().ID); - TODO: Remove }); else { Channel chc = ch.get(); @@ -638,7 +398,7 @@ public class MCChatListener implements Listener, IListener } if (react) { try { - val lmfd = lastmsgfromd.get(event.getChannel().getLongID()); + 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 @@ -646,7 +406,7 @@ public class MCChatListener implements Listener, IListener } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e); } - lastmsgfromd.put(event.getChannel().getLongID(), event.getMessage()); + MCChatUtils.lastmsgfromd.put(event.getChannel().getLongID(), event.getMessage()); DPUtils.perform(() -> event.getMessage().addReaction(DiscordPlugin.DELIVERED_REACTION)); } } catch (Exception e) { @@ -654,19 +414,6 @@ public class MCChatListener implements Listener, IListener } } - /** - * This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. - */ - private static DiscordSenderBase getSender(IChannel channel, final IUser 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(OnlineSenders, channel, author)), // - () -> Optional.of(addSender(UnconnectedSenders, author, - new DiscordSender(author, channel)))).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst().get(); - } - @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 new file mode 100644 index 0000000..3afdd18 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -0,0 +1,55 @@ +package buttondevteam.discordplugin.mcchat; + +import buttondevteam.discordplugin.DiscordConnectedPlayer; +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.listeners.MCListener; +import buttondevteam.lib.player.TBMCPlayer; +import lombok.val; +import org.bukkit.Bukkit; +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 java.util.ArrayList; + +public class MCChatPrivate { + + /** + * Used for messages in PMs (mcchat). + */ + static ArrayList lastmsgPerUser = new ArrayList<>(); + + public static boolean privateMCChat(IChannel 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()); + val op = Bukkit.getOfflinePlayer(mcp.getUUID()); + if (start) { + val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); + MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); + if (p == null)// Player is offline - If the player is online, that takes precedence + MCListener.callEventExcludingSome(new PlayerJoinEvent(sender, "")); + } else { + val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel, user); + if (p == null)// Player is offline - If the player is online, that takes precedence + MCListener.callEventExcludingSome(new PlayerQuitEvent(sender, "")); + } + } + if (!start) + MCChatUtils.lastmsgfromd.remove(channel.getLongID()); + return start // + ? lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs + : lastmsgPerUser.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); + } + + public static boolean isMinecraftChatEnabled(DiscordPlayer dp) { + return isMinecraftChatEnabled(dp.getDiscordID()); + } + + 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)); + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java new file mode 100644 index 0000000..e700b9a --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -0,0 +1,182 @@ +package buttondevteam.discordplugin.mcchat; + +import buttondevteam.discordplugin.*; +import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; +import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.chat.Channel; +import io.netty.util.collection.LongObjectHashMap; +import lombok.RequiredArgsConstructor; +import lombok.experimental.var; +import org.bukkit.command.CommandSender; +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.HashMap; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; + +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<>(); + /** + * May contain P<DiscordID> as key for public chat + */ + public static final HashMap> OnlineSenders = new HashMap<>(); + static LastMsgData lastmsgdata; + static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks + + public static T addSender(HashMap> senders, + IUser user, T sender) { + return addSender(senders, user.getStringID(), sender); + } + + 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); + senders.put(did, map); + return sender; + } + + public static T getSender(HashMap> senders, + IChannel channel, IUser user) { + var map = senders.get(user.getStringID()); + 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()); + if (map != null) + return map.remove(channel); + return null; + } + + public static void forAllMCChat(Consumer action) { + action.accept(DiscordPlugin.chatchannel); + for (LastMsgData data : MCChatPrivate.lastmsgPerUser) + action.accept(data.channel); + // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat + } + + /** + * For custom and all MC chat + * + * @param action The action to act + * @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) { + if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) + forAllMCChat(action); + final Consumer customLMDConsumer = cc -> action.accept(cc.channel); + if (toggle == null) + MCChatCustom.lastmsgCustom.forEach(customLMDConsumer); + else + MCChatCustom.lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).forEach(customLMDConsumer); + } + + /** + * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. + * + * @param action The action to do + * @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) { + 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 + if (toggle != null && (clmd.toggles & toggle.flag) == 0) + return false; //If null then allow + 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 + } + + /** + * Do the {@code action} for each custom chat the {@code sender} have access to and has that broadcast type enabled. + * + * @param action The action to do + * @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 + * @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) { + 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 void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { + if (event.getChannel().isGlobal()) + action.accept(DiscordPlugin.chatchannel); + for (LastMsgData data : MCChatPrivate.lastmsgPerUser) + if (event.shouldSendTo(getSender(data.channel, data.user))) + action.accept(data.channel); + MCChatCustom.lastmsgCustom.stream().filter(clmd -> { + if ((clmd.toggles & ChannelconBroadcast.BROADCAST.flag) == 0) + return false; + return event.shouldSendTo(clmd.dcp); + }).map(clmd -> clmd.channel).forEach(action); + } + + /** + * 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) { + //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(); + } + + /** + * Resets the last message, so it will start a new one instead of appending to it. + * This is used when someone (even the bot) sends a message to the channel. + * + * @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) { + if (channel.getLongID() == DiscordPlugin.chatchannel.getLongID()) { + (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, 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()) { + data.message = null; + return; + } + } + //If it gets here, it's sending a message to a non-chat channel + } + + @RequiredArgsConstructor + public static class LastMsgData { + public IMessage message; + public long time; + public String content; + public final IChannel channel; + public Channel mcchannel; + public final IUser user; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 709b055..4c84bdf 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -1,7 +1,6 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.listeners.MCChatListener; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java index f695dba..2f2ad21 100755 --- a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java @@ -2,7 +2,7 @@ package buttondevteam.discordplugin.mccommands; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.commands.ConnectCommand; -import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; @@ -35,7 +35,7 @@ public class AcceptMCCommand extends DiscordMCCommandBase { dp.save(); mcp.save(); ConnectCommand.WaitingToConnect.remove(player.getName()); - MCChatListener.UnconnectedSenders.remove(did); //Remove all unconnected, will be recreated where needed + MCChatUtils.UnconnectedSenders.remove(did); //Remove all unconnected, will be recreated where needed player.sendMessage("§bAccounts connected."); return true; } -- 2.30.2 From 21221dfeeb147cf5e78b7e6caff507c4430d04cb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 18 Dec 2018 00:52:02 +0100 Subject: [PATCH 026/108] NPE fix, prefix --- .../discordplugin/DiscordPlugin.java | 18 ++++++++++++++---- .../discordplugin/commands/ConnectCommand.java | 6 +++--- .../discordplugin/commands/HelpCommand.java | 7 +++---- .../discordplugin/commands/MCChatCommand.java | 7 ++++--- .../discordplugin/commands/RoleCommand.java | 2 +- .../commands/UserinfoCommand.java | 3 ++- .../discordplugin/mcchat/MCChatListener.java | 5 +++-- 7 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 02709d1..8c4856a 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -12,7 +12,9 @@ import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; @@ -27,7 +29,6 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.api.ClientBuilder; import sx.blah.discord.api.IDiscordClient; @@ -49,7 +50,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; -public class DiscordPlugin extends JavaPlugin implements IListener { +public class DiscordPlugin extends ButtonPlugin implements IListener { private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; private static boolean stop = false; public static IDiscordClient dc; @@ -57,8 +58,17 @@ public class DiscordPlugin extends JavaPlugin implements IListener { public static boolean SafeMode = true; public static List GameRoles; + public ConfigData Prefix() { + return getData("prefix", '/'); + } + + public static char getPrefix() { + if (plugin == null) return '/'; + return plugin.Prefix().get(); + } + @Override - public void onEnable() { + public void pluginEnable() { stop = false; //If not the first time try { Bukkit.getLogger().info("Initializing DiscordPlugin..."); @@ -238,7 +248,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { public static boolean Restart; @Override - public void onDisable() { + public void pluginDisable() { stop = true; for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index a339c4d..6e16c09 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -30,7 +30,7 @@ public class ConnectCommand extends DiscordCommandBase { return false; if (args.contains(" ")) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Too many arguments.\nUsage: connect "); + "Too many arguments.\nUsage: " + DiscordPlugin.getPrefix() + "connect "); return true; } if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { @@ -68,8 +68,8 @@ public class ConnectCommand extends DiscordCommandBase { public String[] getHelpText() { return new String[] { // "---- Connect command ----", // - "This commands let's you connect your acoount with a Minecraft account. This'd allow using the Minecraft chat and other things.", // - "Usage: connect " // + "This command lets you connect your account with a Minecraft account. This allows using the Minecraft chat and other things.", // + "Usage: /connect " // }; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java index 29aff28..bcef6ea 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java @@ -3,7 +3,6 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; import sx.blah.discord.handle.obj.IMessage; -import java.util.Arrays; import java.util.stream.Collectors; public class HelpCommand extends DiscordCommandBase { @@ -19,11 +18,11 @@ public class HelpCommand extends DiscordCommandBase { if (args.length() == 0) DiscordPlugin.sendMessageToChannel(message.getChannel(), "Available commands:\n" + DiscordCommandBase.commands.values().stream() - .map(dc -> dc.getCommandName()).collect(Collectors.joining("\n"))); + .map(dc -> DiscordPlugin.getPrefix() + dc.getCommandName()).collect(Collectors.joining("\n"))); else DiscordPlugin.sendMessageToChannel(message.getChannel(), (argdc = DiscordCommandBase.commands.get(args)) == null ? "Command not found: " + args - : Arrays.stream(argdc.getHelpText()).collect(Collectors.joining("\n"))); + : String.join("\n", argdc.getHelpText())); return true; } @@ -32,7 +31,7 @@ public class HelpCommand extends DiscordCommandBase { return new String[] { // "---- Help command ----", // "Shows some info about a command or lists the available commands.", // - "Usage: help [command]"// + "Usage: " + DiscordPlugin.getPrefix() + "help [command]"// }; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java index 7a5b7c8..24c6390 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java @@ -25,7 +25,7 @@ public class MCChatCommand extends DiscordCommandBase { MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); DiscordPlugin.sendMessageToChannel(message.getChannel(), "Minecraft chat " + (mcchat // - ? "enabled. Use '/mcchat' again to turn it off." // + ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // : "disabled.")); } catch (Exception e) { TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e); @@ -36,8 +36,9 @@ public class MCChatCommand extends DiscordCommandBase { @Override public String[] getHelpText() { return new String[] { // - "mcchat enables or disables the Minecraft chat in private messages.", // - "It can be useful if you don't want your messages to be visible, for example when talking a private channel." // + DiscordPlugin.getPrefix() + "mcchat enables or disables the Minecraft chat in private messages.", // + "It can be useful if you don't want your messages to be visible, for example when talking in a private channel.", // + "You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." // }; // TODO: Pin channel switching to indicate the current channel } diff --git a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java index 3978c6a..a7f2bf5 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java @@ -86,7 +86,7 @@ public class RoleCommand extends DiscordCommandBase { public String[] getHelpText() { return new String[]{ // "Add or remove game roles from yourself.", // - "Usage: role add|remove or role list", // + "Usage: " + DiscordPlugin.getPrefix() + "role add|remove or role list", // }; } diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index b0608ed..b1dbf8b 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -91,7 +91,8 @@ public class UserinfoCommand extends DiscordCommandBase { "---- User information ----", // "Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", // "If used without args, shows your info.", // - "Usage: userinfo [username/nickname[#tag]/ping]\nExamples:\nuserinfo ChromaBot\nuserinfo ChromaBot#6338\nuserinfo @ChromaBot#6338" // + "Usage: " + DiscordPlugin.getPrefix() + "userinfo [username/nickname[#tag]/ping]", // + "Examples:\n" + DiscordPlugin.getPrefix() + "userinfo ChromaBot\n" + DiscordPlugin.getPrefix() + "userinfo ChromaBot#6338\n" + DiscordPlugin.getPrefix() + "userinfo @ChromaBot#6338" // }; } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index f81c01d..15489e5 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -382,8 +382,9 @@ public class MCChatListener implements Listener, IListener } 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.filteranderrormsg.apply(clmd.dcp) : dsender.getChromaUser().channel().get().filteranderrormsg.apply(dsender); - TBMCChatAPI.SendSystemMessage(clmd != null ? clmd.mcchannel : dsender.getChromaUser().channel().get(), rtr.score, rtr.groupID, + 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."); } -- 2.30.2 From 5ff433f3bbaa2809233910eb8bf2fb2bdd506f26 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 22 Dec 2018 16:20:20 +0100 Subject: [PATCH 027/108] Code organization Moved part of MCListener Added support for custom chat player list --- .../discordplugin/ChromaBot.java | 14 +- .../discordplugin/DiscordPlugin.java | 11 +- .../discordplugin/listeners/MCListener.java | 174 ++--------------- .../discordplugin/mcchat/MCChatPrivate.java | 8 +- .../discordplugin/mcchat/MCChatUtils.java | 38 +++- .../discordplugin/mcchat/MCListener.java | 184 ++++++++++++++++++ .../mcchat/MinecraftChatModule.java | 1 + 7 files changed, 247 insertions(+), 183 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index 90e5afb..56a6fb9 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -2,7 +2,6 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MCChatUtils; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; import sx.blah.discord.api.internal.json.objects.EmbedObject; @@ -11,8 +10,6 @@ import sx.blah.discord.util.EmbedBuilder; import javax.annotation.Nullable; import java.awt.*; -import java.util.Arrays; -import java.util.stream.Collectors; public class ChromaBot { /** @@ -144,15 +141,6 @@ public class ChromaBot { } public void updatePlayerList() { - DPUtils.performNoWait(() -> { - String[] s = DiscordPlugin.chatchannel.getTopic().split("\\n----\\n"); - if (s.length < 3) - return; - s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "") - + " online"; - s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream() - .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); - DiscordPlugin.chatchannel.changeTopic(Arrays.stream(s).collect(Collectors.joining("\n----\n"))); - }); + MCChatUtils.updatePlayerList(); } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 8c4856a..da87790 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -5,10 +5,7 @@ import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.ExceptionListener; import buttondevteam.discordplugin.listeners.MCListener; -import buttondevteam.discordplugin.mcchat.MCChatCustom; -import buttondevteam.discordplugin.mcchat.MCChatListener; -import buttondevteam.discordplugin.mcchat.MCChatUtils; -import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.mcchat.*; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; import buttondevteam.lib.TBMCCoreAPI; @@ -27,7 +24,6 @@ import lombok.val; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.scheduler.BukkitTask; import sx.blah.discord.api.ClientBuilder; @@ -250,10 +246,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener @Override public void pluginDisable() { stop = true; - for (val entry : MCChatUtils.ConnectedSenders.entrySet()) - for (val valueEntry : entry.getValue().entrySet()) - MCListener.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); - MCChatUtils.ConnectedSenders.clear(); + MCChatPrivate.logoutAll(); getConfig().set("lastannouncementtime", lastannouncementtime); getConfig().set("lastseentime", lastseentime); getConfig().set("serverup", false); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index cd8a826..89b4e17 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -1,99 +1,29 @@ package buttondevteam.discordplugin.listeners; -import buttondevteam.discordplugin.*; -import buttondevteam.discordplugin.commands.ConnectCommand; -import buttondevteam.discordplugin.mcchat.MCChatListener; +import buttondevteam.discordplugin.ChannelconBroadcast; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.player.*; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerBase; +import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; +import buttondevteam.lib.player.TBMCYEEHAWEvent; import com.earth2me.essentials.CommandSource; -import lombok.val; -import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.api.events.MuteStatusChangeEvent; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.*; -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.PlayerLoginEvent.Result; -import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.event.server.BroadcastMessageEvent; import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.plugin.AuthorNagException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredListener; import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.MissingPermissionsException; -import java.util.Arrays; -import java.util.logging.Level; - public class MCListener implements Listener { - @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerLogin(PlayerLoginEvent e) { - if (e.getResult() != Result.ALLOWED) - 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 -> callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(TBMCPlayerJoinEvent e) { - if (e.getPlayer() instanceof DiscordConnectedPlayer) - return; // Don't show the joined message for the fake player - Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { - final Player p = e.getPlayer(); - DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); - if (dp != null) { - val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); - MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); - MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel - } - if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { - IUser user = DiscordPlugin.dc - .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); - p.sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() - + " do /discord accept"); - p.sendMessage("§bIf it wasn't you, do /discord decline"); - } - final String message = e.GetPlayer().PlayerName().get() + " joined the game"; - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); - MCChatListener.ListC = 0; - ChromaBot.getInstance().updatePlayerList(); - }); - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerLeave(TBMCPlayerQuitEvent e) { - if (e.getPlayer() instanceof DiscordConnectedPlayer) - 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, - () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) - .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); - 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); - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerKick(PlayerKickEvent e) { - /*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") - && !e.getReason().equals("Server closed")) // The leave messages errored with the previous setup, I could make it wait since I moved it here, but instead I have a special - MCChatListener.forAllowedCustomAndAllMCChat(e.getPlayer().getName() + " left the game"); // message for this - Oh wait this doesn't even send normally because of the hook*/ - } - @EventHandler public void onGetInfo(TBMCPlayerGetInfoEvent e) { if (DiscordPlugin.SafeMode) @@ -108,21 +38,6 @@ public class MCListener implements Listener { e.addInfo(user.getPresence().getActivity().get() + ": " + user.getPresence().getText().get()); } - @EventHandler(priority = EventPriority.LOW) - public void onPlayerDeath(PlayerDeathEvent e) { - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); - } - - @EventHandler - public void onPlayerAFK(AfkStatusChangeEvent e) { - final Player base = e.getAffected().getBase(); - if (e.isCancelled() || !base.isOnline()) - return; - final String msg = base.getDisplayName() - + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); - } - @EventHandler public void onServerCommand(ServerCommandEvent e) { DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped @@ -136,13 +51,16 @@ public class MCListener implements Listener { 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 IUser user = DiscordPlugin.dc.getUserByID( - Long.parseLong(TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) - .getAs(DiscordPlayer.class).getDiscordID())); + Long.parseLong(p.getDiscordID())); if (e.getValue()) user.addRole(role); else user.removeRole(role); + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); }); } catch (DiscordException | MissingPermissionsException ex) { TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", @@ -167,66 +85,4 @@ public class MCListener implements Listener { //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } - - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; - - public static void callEventExcludingSome(Event event) { - callEventExcluding(event, EXCLUDED_PLUGINS); - } - - /** - * Calls an event with the given details. - *

- * This method only synchronizes when the event is not asynchronous. - * - * @param event Event details - * @param plugins The plugins to exclude. Not case sensitive. - */ - private static void callEventExcluding(Event event, String... plugins) { // Copied from Spigot-API and modified a bit - if (event.isAsynchronous()) { - if (Thread.holdsLock(Bukkit.getPluginManager())) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); - } - if (Bukkit.getServer().isPrimaryThread()) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from primary server thread."); - } - fireEventExcluding(event, plugins); - } else { - synchronized (Bukkit.getPluginManager()) { - fireEventExcluding(event, plugins); - } - } - } - - private static void fireEventExcluding(Event event, String... plugins) { - HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - val server = Bukkit.getServer(); - - for (RegisteredListener registration : listeners) { - if (!registration.getPlugin().isEnabled() - || Arrays.stream(plugins).anyMatch(p -> p.equalsIgnoreCase(registration.getPlugin().getName()))) - continue; // Modified to exclude plugins - - try { - registration.callEvent(event); - } catch (AuthorNagException ex) { - Plugin plugin = registration.getPlugin(); - - if (plugin.isNaggable()) { - plugin.setNaggable(false); - - server.getLogger().log(Level.SEVERE, - String.format("Nag author(s): '%s' of '%s' about the following: %s", - plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), - ex.getMessage())); - } - } catch (Throwable ex) { - server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " - + registration.getPlugin().getDescription().getFullName(), ex); - } - } - } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 3afdd18..5edcfa0 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -2,7 +2,6 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.listeners.MCListener; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; import org.bukkit.Bukkit; @@ -52,4 +51,11 @@ public class MCChatPrivate { return lastmsgPerUser.stream() .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did)); } + + public static void logoutAll() { + for (val entry : MCChatUtils.ConnectedSenders.entrySet()) + for (val valueEntry : entry.getValue().entrySet()) + MCListener.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); + MCChatUtils.ConnectedSenders.clear(); + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index e700b9a..cb476a2 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCSystemChatEvent; @@ -7,6 +8,7 @@ import buttondevteam.lib.chat.Channel; import io.netty.util.collection.LongObjectHashMap; import lombok.RequiredArgsConstructor; import lombok.experimental.var; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IMessage; @@ -17,6 +19,7 @@ import java.util.HashMap; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.Stream; public class MCChatUtils { @@ -29,9 +32,36 @@ public class MCChatUtils { * May contain P<DiscordID> as key for public chat */ public static final HashMap> OnlineSenders = new HashMap<>(); - static LastMsgData lastmsgdata; + static @Nullable LastMsgData lastmsgdata; static LongObjectHashMap lastmsgfromd = new LongObjectHashMap<>(); // Last message sent by a Discord user, used for clearing checkmarks + public static void updatePlayerList() { + if (notEnabled()) return; + DPUtils.performNoWait(() -> { + if (lastmsgdata != null) + updatePL(lastmsgdata); + MCChatCustom.lastmsgCustom.forEach(MCChatUtils::updatePL); + }); + } + + private static boolean notEnabled() { + return !ComponentManager.isEnabled(MinecraftChatModule.class); + } + + private static void updatePL(LastMsgData lmd) { + String topic = lmd.channel.getTopic(); + if (topic.length() == 0) + topic = ".\n----\nMinecraft chat\n----\n."; + String[] s = topic.split("\\n----\\n"); + if (s.length < 3) + return; + s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "") + + " 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)); + } + public static T addSender(HashMap> senders, IUser user, T sender) { return addSender(senders, user.getStringID(), sender); @@ -64,6 +94,7 @@ public class MCChatUtils { } public static void forAllMCChat(Consumer action) { + if (notEnabled()) return; action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) action.accept(data.channel); @@ -78,6 +109,7 @@ public class MCChatUtils { * @param hookmsg Whether the message is also sent from the hook */ 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); @@ -95,6 +127,7 @@ public class MCChatUtils { * @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) { + 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 if (toggle != null && (clmd.toggles & toggle.flag) == 0) @@ -114,6 +147,7 @@ public class MCChatUtils { * @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) { + if (notEnabled()) return; if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) forAllMCChat(action); forAllowedCustomMCChat(action, sender, toggle); @@ -124,6 +158,7 @@ public class MCChatUtils { } public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { + if (notEnabled()) return; if (event.getChannel().isGlobal()) action.accept(DiscordPlugin.chatchannel); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) @@ -156,6 +191,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) { + if (notEnabled()) return; if (channel.getLongID() == DiscordPlugin.chatchannel.getLongID()) { (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null) : lastmsgdata).message = null; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java new file mode 100644 index 0000000..1824ef8 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -0,0 +1,184 @@ +package buttondevteam.discordplugin.mcchat; + +import buttondevteam.discordplugin.*; +import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.player.TBMCPlayerJoinEvent; +import buttondevteam.lib.player.TBMCPlayerQuitEvent; +import buttondevteam.lib.player.TBMCYEEHAWEvent; +import lombok.val; +import net.ess3.api.events.AfkStatusChangeEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.*; +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.PlayerLoginEvent.Result; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.BroadcastMessageEvent; +import org.bukkit.plugin.AuthorNagException; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredListener; +import sx.blah.discord.handle.obj.IUser; + +import java.util.Arrays; +import java.util.logging.Level; + +class MCListener implements Listener { + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerLogin(PlayerLoginEvent e) { + if (e.getResult() != Result.ALLOWED) + 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 -> callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerJoin(TBMCPlayerJoinEvent e) { + if (e.getPlayer() instanceof DiscordConnectedPlayer) + return; // Don't show the joined message for the fake player + Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { + final Player p = e.getPlayer(); + DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); + if (dp != null) { + val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), + new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), + new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel + } + if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { + IUser user = DiscordPlugin.dc + .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); + p.sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() + + " do /discord accept"); + p.sendMessage("§bIf it wasn't you, do /discord decline"); + } + final String message = e.GetPlayer().PlayerName().get() + " joined the game"; + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); + MCChatListener.ListC = 0; + ChromaBot.getInstance().updatePlayerList(); + }); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerLeave(TBMCPlayerQuitEvent e) { + if (e.getPlayer() instanceof DiscordConnectedPlayer) + 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, + () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) + .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() + .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); + 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); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerKick(PlayerKickEvent e) { + /*if (!DiscordPlugin.hooked && !e.getReason().equals("The server is restarting") + && !e.getReason().equals("Server closed")) // The leave messages errored with the previous setup, I could make it wait since I moved it here, but instead I have a special + MCChatListener.forAllowedCustomAndAllMCChat(e.getPlayer().getName() + " left the game"); // message for this - Oh wait this doesn't even send normally because of the hook*/ + } + + @EventHandler(priority = EventPriority.LOW) + public void onPlayerDeath(PlayerDeathEvent e) { + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); + } + + @EventHandler + public void onPlayerAFK(AfkStatusChangeEvent e) { + final Player base = e.getAffected().getBase(); + if (e.isCancelled() || !base.isOnline()) + return; + final String msg = base.getDisplayName() + + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); + } + + @EventHandler + public void onChatSystemMessage(TBMCSystemChatEvent event) { + MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event); + } + + @EventHandler + public void onBroadcastMessage(BroadcastMessageEvent event) { + MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); + } + + @EventHandler + public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support + String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() + : event.getSender().getName(); + //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO + MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); + } + + private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; + + static void callEventExcludingSome(Event event) { + callEventExcluding(event, EXCLUDED_PLUGINS); + } + + /** + * Calls an event with the given details. + *

+ * This method only synchronizes when the event is not asynchronous. + * + * @param event Event details + * @param plugins The plugins to exclude. Not case sensitive. + */ + private static void callEventExcluding(Event event, String... plugins) { // Copied from Spigot-API and modified a bit + if (event.isAsynchronous()) { + if (Thread.holdsLock(Bukkit.getPluginManager())) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); + } + if (Bukkit.getServer().isPrimaryThread()) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from primary server thread."); + } + fireEventExcluding(event, plugins); + } else { + synchronized (Bukkit.getPluginManager()) { + fireEventExcluding(event, plugins); + } + } + } + + private static void fireEventExcluding(Event event, String... plugins) { + HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + val server = Bukkit.getServer(); + + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled() + || Arrays.stream(plugins).anyMatch(p -> p.equalsIgnoreCase(registration.getPlugin().getName()))) + continue; // Modified to exclude plugins + + try { + registration.callEvent(event); + } catch (AuthorNagException ex) { + Plugin plugin = registration.getPlugin(); + + if (plugin.isNaggable()) { + plugin.setNaggable(false); + + server.getLogger().log(Level.SEVERE, + String.format("Nag author(s): '%s' of '%s' about the following: %s", + plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), + ex.getMessage())); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + + registration.getPlugin().getDescription().getFullName(), ex); + } + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 4c84bdf..12ddb78 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -10,6 +10,7 @@ public class MinecraftChatModule extends Component { MCChatListener mcchat = new MCChatListener(); DiscordPlugin.dc.getDispatcher().registerListener(mcchat); TBMCCoreAPI.RegisterEventsForExceptions(mcchat, getPlugin()); + TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin()); } @Override -- 2.30.2 From e29e6f1682dd9a092070d96baf2ffe7da26bb9b8 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 23 Dec 2018 00:39:27 +0100 Subject: [PATCH 028/108] First version of new events stuff Actually registered the debug message listener --- .../discordplugin/AsyncDiscordEvent.java | 27 +++++++ .../discordplugin/DiscordPlugin.java | 4 +- .../DebugMessageListener.java | 2 +- .../ExceptionListenerModule.java} | 20 ++++- .../listeners/CommandListener.java | 27 +++++++ .../listeners/CommonListeners.java | 7 ++ .../discordplugin/listeners/MCListener.java | 73 ++++++++++++++++++ .../discordplugin/mcchat/MCListener.java | 76 ++----------------- 8 files changed, 159 insertions(+), 77 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java rename src/main/java/buttondevteam/discordplugin/{listeners => exceptions}/DebugMessageListener.java (91%) rename src/main/java/buttondevteam/discordplugin/{listeners/ExceptionListener.java => exceptions/ExceptionListenerModule.java} (79%) create mode 100644 src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java diff --git a/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java b/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java new file mode 100644 index 0000000..c4479f3 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/AsyncDiscordEvent.java @@ -0,0 +1,27 @@ +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/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index da87790..9870d99 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -2,8 +2,8 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.listeners.CommonListeners; -import buttondevteam.discordplugin.listeners.ExceptionListener; import buttondevteam.discordplugin.listeners.MCListener; import buttondevteam.discordplugin.mcchat.*; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; @@ -217,7 +217,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener dc.getDispatcher().registerListener(listener); Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new MinecraftChatModule()); - Bukkit.getPluginManager().registerEvents(new ExceptionListener(), this); + Component.registerComponent(this, new ExceptionListenerModule()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/DebugMessageListener.java b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java similarity index 91% rename from src/main/java/buttondevteam/discordplugin/listeners/DebugMessageListener.java rename to src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java index 1e163c4..cca3e98 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/DebugMessageListener.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java @@ -1,4 +1,4 @@ -package buttondevteam.discordplugin.listeners; +package buttondevteam.discordplugin.exceptions; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCDebugMessageEvent; diff --git a/src/main/java/buttondevteam/discordplugin/listeners/ExceptionListener.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java similarity index 79% rename from src/main/java/buttondevteam/discordplugin/listeners/ExceptionListener.java rename to src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 549bb97..f491a24 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/ExceptionListener.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -1,9 +1,12 @@ -package buttondevteam.discordplugin.listeners; +package buttondevteam.discordplugin.exceptions; +import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCExceptionEvent; +import buttondevteam.lib.architecture.Component; 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.IRole; @@ -13,13 +16,13 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -public class ExceptionListener implements Listener { +public class ExceptionListenerModule extends Component implements Listener { private List lastthrown = new ArrayList<>(); private List lastsourcemsg = new ArrayList<>(); @EventHandler public void onException(TBMCExceptionEvent e) { - if (DiscordPlugin.SafeMode) + if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(getClass())) return; if (lastthrown.stream() .anyMatch(ex -> Arrays.equals(e.getException().getStackTrace(), ex.getStackTrace()) @@ -59,4 +62,15 @@ public class ExceptionListener implements Listener { ex.printStackTrace(); } } + + @Override + protected void enable() { + Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin()); + TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin()); + } + + @Override + protected void disable() { + + } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java new file mode 100644 index 0000000..891edf5 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -0,0 +1,27 @@ +package buttondevteam.discordplugin.listeners; + +import buttondevteam.discordplugin.AsyncDiscordEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import sx.blah.discord.api.events.Event; +import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; +import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; + +public class CommandListener implements Listener { + @SuppressWarnings("unchecked") + @EventHandler + public void onEvent(AsyncDiscordEvent event_) { + if (event_.getEvent() instanceof MentionEvent) + onMention((AsyncDiscordEvent) event_); + else if (event_.getEvent() instanceof MessageReceivedEvent) + onMessageReceived((AsyncDiscordEvent) event_); + } + + private void onMention(AsyncDiscordEvent event) { + //TODO: Can't use priorities with this + } + + private void onMessageReceived(AsyncDiscordEvent event) { + + } +} diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 737e5cf..800c40d 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.listeners; +import buttondevteam.discordplugin.AsyncDiscordEvent; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; @@ -8,6 +9,7 @@ import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.lib.TBMCCoreAPI; import lombok.val; import org.bukkit.Bukkit; +import sx.blah.discord.api.events.Event; import sx.blah.discord.api.events.IListener; import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; @@ -63,6 +65,10 @@ public class CommonListeners { list.add(i); } + private static void callDiscordEvent(Event event) { + MCListener.callEventExcluding(new AsyncDiscordEvent(event), true, "DiscordPlugin"); + } + private static long lasttime = 0; public static IListener[] getListeners() { @@ -71,6 +77,7 @@ public class CommonListeners { public void handle(MentionEvent event) { if (DiscordPlugin.SafeMode) return; + callDiscordEvent(event); if (event.getMessage().getAuthor().isBot()) return; final IChannel channel = event.getMessage().getChannel(); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 89b4e17..a01e727 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -12,17 +12,27 @@ import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; import buttondevteam.lib.player.TBMCYEEHAWEvent; import com.earth2me.essentials.CommandSource; +import lombok.val; import net.ess3.api.events.MuteStatusChangeEvent; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.event.Event; import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.server.BroadcastMessageEvent; import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.plugin.AuthorNagException; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredListener; import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.MissingPermissionsException; +import java.util.Arrays; +import java.util.logging.Level; + public class MCListener implements Listener { @EventHandler public void onGetInfo(TBMCPlayerGetInfoEvent e) { @@ -85,4 +95,67 @@ public class MCListener implements Listener { //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } + + private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; + + public static void callEventExcludingSome(Event event) { + callEventExcluding(event, false, EXCLUDED_PLUGINS); + } + + /** + * Calls an event with the given details. + *

+ * This method only synchronizes when the event is not asynchronous. + * + * @param event Event details + * @param only Flips the operation and includes the listed plugins + * @param plugins The plugins to exclude. Not case sensitive. + */ + public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit + if (event.isAsynchronous()) { + if (Thread.holdsLock(Bukkit.getPluginManager())) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); + } + if (Bukkit.getServer().isPrimaryThread()) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from primary server thread."); + } + fireEventExcluding(event, only, plugins); + } else { + synchronized (Bukkit.getPluginManager()) { + fireEventExcluding(event, only, plugins); + } + } + } + + private static void fireEventExcluding(Event event, boolean only, String... plugins) { + HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + val server = Bukkit.getServer(); + + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled() + || Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName()))) + continue; // Modified to exclude plugins + + try { + registration.callEvent(event); + } catch (AuthorNagException ex) { + Plugin plugin = registration.getPlugin(); + + if (plugin.isNaggable()) { + plugin.setNaggable(false); + + server.getLogger().log(Level.SEVERE, + String.format("Nag author(s): '%s' of '%s' about the following: %s", + plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), + ex.getMessage())); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + + registration.getPlugin().getDescription().getFullName(), ex); + } + } + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 1824ef8..9b419e9 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -10,7 +10,9 @@ import lombok.val; import net.ess3.api.events.AfkStatusChangeEvent; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.*; +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; @@ -18,14 +20,8 @@ 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 org.bukkit.plugin.AuthorNagException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredListener; import sx.blah.discord.handle.obj.IUser; -import java.util.Arrays; -import java.util.logging.Level; - class MCListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerLogin(PlayerLoginEvent e) { @@ -33,7 +29,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 -> callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); + .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); } @EventHandler(priority = EventPriority.LOWEST) @@ -73,7 +69,7 @@ class MCListener implements Listener { Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); + .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; @@ -119,66 +115,4 @@ class MCListener implements Listener { //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } - - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; - - static void callEventExcludingSome(Event event) { - callEventExcluding(event, EXCLUDED_PLUGINS); - } - - /** - * Calls an event with the given details. - *

- * This method only synchronizes when the event is not asynchronous. - * - * @param event Event details - * @param plugins The plugins to exclude. Not case sensitive. - */ - private static void callEventExcluding(Event event, String... plugins) { // Copied from Spigot-API and modified a bit - if (event.isAsynchronous()) { - if (Thread.holdsLock(Bukkit.getPluginManager())) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); - } - if (Bukkit.getServer().isPrimaryThread()) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from primary server thread."); - } - fireEventExcluding(event, plugins); - } else { - synchronized (Bukkit.getPluginManager()) { - fireEventExcluding(event, plugins); - } - } - } - - private static void fireEventExcluding(Event event, String... plugins) { - HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - val server = Bukkit.getServer(); - - for (RegisteredListener registration : listeners) { - if (!registration.getPlugin().isEnabled() - || Arrays.stream(plugins).anyMatch(p -> p.equalsIgnoreCase(registration.getPlugin().getName()))) - continue; // Modified to exclude plugins - - try { - registration.callEvent(event); - } catch (AuthorNagException ex) { - Plugin plugin = registration.getPlugin(); - - if (plugin.isNaggable()) { - plugin.setNaggable(false); - - server.getLogger().log(Level.SEVERE, - String.format("Nag author(s): '%s' of '%s' about the following: %s", - plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), - ex.getMessage())); - } - } catch (Throwable ex) { - server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " - + registration.getPlugin().getDescription().getFullName(), ex); - } - } - } } -- 2.30.2 From 7a6b79365fb0bab7199261458718d9c8c031df9a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 23 Dec 2018 03:22:50 +0100 Subject: [PATCH 029/108] Another version of the events stuff It directly calls the methods in the modules Also made a fun module --- .../commands/DiscordCommandBase.java | 1 + .../discordplugin/fun/FunModule.java | 86 ++++++ .../listeners/CommandListener.java | 86 ++++-- .../listeners/CommonListeners.java | 288 ++++++------------ .../listeners/DiscordListener.java | 4 + .../{commands => mcchat}/MCChatCommand.java | 6 +- .../discordplugin/mcchat/MCChatListener.java | 27 +- .../mcchat/MinecraftChatModule.java | 12 +- 8 files changed, 273 insertions(+), 237 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/fun/FunModule.java create mode 100644 src/main/java/buttondevteam/discordplugin/listeners/DiscordListener.java rename src/main/java/buttondevteam/discordplugin/{commands => mcchat}/MCChatCommand.java (91%) diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index a4da021..45f175f 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.mcchat.MCChatCommand; import buttondevteam.lib.TBMCCoreAPI; import sx.blah.discord.handle.obj.IMessage; diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java new file mode 100644 index 0000000..5dea2d3 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -0,0 +1,86 @@ +package buttondevteam.discordplugin.fun; + +import buttondevteam.core.ComponentManager; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import sx.blah.discord.handle.obj.IMessage; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class FunModule extends Component { + private static FunModule mod; + + 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 + }; + + private ConfigData serverReady() { + return getData("serverReady", true); + } + + private ConfigData> serverReadyAnswers() { + return getData("serverReadyAnswers", Arrays.asList(serverReadyStrings), + data -> (List) data, data -> data); //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(serverReadyStrings.length) { + private static final long serialVersionUID = 2213771460909848770L; + + { + createUsableServerReadyStrings(this); + } + }; + + private static void createUsableServerReadyStrings(ArrayList list) { + for (short i = 0; i < serverReadyStrings.length; i++) + list.add(i); + } + + @Override + protected void enable() { + mod = this; + } + + @Override + protected void disable() { + } + + public static boolean executeMemes(IMessage message) { + if (!ComponentManager.isEnabled(FunModule.class)) return false; + if (mod.serverReady().get()) { + if (!TBMCCoreAPI.IsTestServer() + && Arrays.stream(serverReadyQuestions).anyMatch(s -> message.getContent().toLowerCase().contains(s))) { + int next; + if (usableServerReadyStrings.size() == 0) + createUsableServerReadyStrings(usableServerReadyStrings); + next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); + DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]); + return true; + } + } + return false; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 891edf5..d1d9386 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -1,27 +1,73 @@ package buttondevteam.discordplugin.listeners; -import buttondevteam.discordplugin.AsyncDiscordEvent; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import sx.blah.discord.api.events.Event; -import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; -import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.commands.DiscordCommandBase; +import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IMessage; -public class CommandListener implements Listener { - @SuppressWarnings("unchecked") - @EventHandler - public void onEvent(AsyncDiscordEvent event_) { - if (event_.getEvent() instanceof MentionEvent) - onMention((AsyncDiscordEvent) event_); - else if (event_.getEvent() instanceof MessageReceivedEvent) - onMessageReceived((AsyncDiscordEvent) event_); +public class CommandListener { + /** + * Runs a ChromaBot command. If mentionedonly is false, it will only execute the command if it was in #bot with the correct prefix or in private. + * + * @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 + */ + public static boolean runCommand(IMessage message, boolean mentionedonly) { + final IChannel channel = message.getChannel(); + if (mentionedonly) { + if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()) + && !message.getContent().contains("channelcon")) //Allow channelcon in other servers + return false; //Private chat is handled without mentions + } else { + if (!message.getChannel().isPrivate() + && !(message.getContent().startsWith("/") + && channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // + return false; + } + message.getChannel().setTypingStatus(true); // Fun + final StringBuilder cmdwithargs = new StringBuilder(message.getContent()); + final String mention = DiscordPlugin.dc.getOurUser().mention(false); + final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); + 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(r -> r.mention())::iterator) + gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions + if (mentionedonly && !gotmention) { + message.getChannel().setTypingStatus(false); + return false; + } + message.getChannel().setTypingStatus(true); + String cmdwithargsString = cmdwithargs.toString().trim(); //Remove spaces between mention and command + int index = cmdwithargsString.indexOf(" "); + String cmd; + String args; + if (index == -1) { + cmd = cmdwithargsString; + args = ""; + } else { + cmd = cmdwithargsString.substring(0, index); + args = cmdwithargsString.substring(index + 1).trim(); //In case there are multiple spaces + } + DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message); + message.getChannel().setTypingStatus(false); + return true; } - private void onMention(AsyncDiscordEvent event) { - //TODO: Can't use priorities with this - } - - private void onMessageReceived(AsyncDiscordEvent event) { - + private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { + if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text + if (cmdwithargs.length() > mention.length() + 1) + cmdwithargs.delete(0, + cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length()); + else + cmdwithargs.replace(0, cmdwithargs.length(), "help"); + else { + if (cmdwithargs.length() > 0 && cmdwithargs.charAt(0) == '/') + cmdwithargs.deleteCharAt(0); //Don't treat / as mention, mentions can be used in public mcchat + return false; + } + if (cmdwithargs.length() == 0) + cmdwithargs.replace(0, cmdwithargs.length(), "help"); + return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 800c40d..92cf74b 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -1,15 +1,11 @@ package buttondevteam.discordplugin.listeners; -import buttondevteam.discordplugin.AsyncDiscordEvent; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.commands.DiscordCommandBase; -import buttondevteam.discordplugin.mcchat.MCChatCustom; -import buttondevteam.discordplugin.mcchat.MCChatPrivate; -import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.lib.architecture.Component; import lombok.val; import org.bukkit.Bukkit; -import sx.blah.discord.api.events.Event; import sx.blah.discord.api.events.IListener; import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; @@ -17,195 +13,112 @@ 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; -import sx.blah.discord.handle.obj.IChannel; -import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.StatusType; import sx.blah.discord.util.EmbedBuilder; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; -import java.util.Random; import java.util.concurrent.TimeUnit; public class CommonListeners { - 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 - }; + /*private static ArrayList dcListeners=new ArrayList<>(); - 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(serverReadyStrings.length) { - private static final long serialVersionUID = 2213771460909848770L; - - { - createUsableServerReadyStrings(this); - } - }; - - private static void createUsableServerReadyStrings(ArrayList list) { - for (short i = 0; i < serverReadyStrings.length; i++) - list.add(i); + public static void registerDiscordListener(DiscordListener listener) { + //Step 1: Get all events that are handled by us + //Step 2: Find methods that handle these + //...or just simply call the methods in the right order } private static void callDiscordEvent(Event event) { - MCListener.callEventExcluding(new AsyncDiscordEvent(event), true, "DiscordPlugin"); - } + String name=event.getClass().getSimpleName(); + name=Character.toLowerCase(name.charAt(0))+name.substring(1); + for (Object listener : dcListeners) { + listener.getClass().getMethods(name, AsyncDiscordEvent.class); + } + }*/ private static long lasttime = 0; - public static IListener[] getListeners() { - return new IListener[]{new IListener() { - @Override - public void handle(MentionEvent event) { - if (DiscordPlugin.SafeMode) - return; - callDiscordEvent(event); - if (event.getMessage().getAuthor().isBot()) - return; - final IChannel channel = event.getMessage().getChannel(); - if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()) - && (!event.getMessage().getContent().contains("channelcon") || MCChatCustom.hasCustomChat(channel))) //Allow channelcon in other servers but avoid double handling when it's enabled - return; - if (channel.getStringID().equals(DiscordPlugin.chatchannel.getStringID())) - return; // The chat code already handles this - Right now while testing botchannel is the same as chatchannel - event.getMessage().getChannel().setTypingStatus(true); // Fun - runCommand(event.getMessage(), true); - } - }, new IListener() { - @Override - public void handle(MessageReceivedEvent event) { - if (DiscordPlugin.SafeMode) - return; - final String msglowercase = event.getMessage().getContent().toLowerCase(); - if (!TBMCCoreAPI.IsTestServer() - && Arrays.stream(serverReadyQuestions).anyMatch(s -> msglowercase.contains(s))) { - int next; - if (usableServerReadyStrings.size() == 0) - createUsableServerReadyStrings(usableServerReadyStrings); - next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); - DiscordPlugin.sendMessageToChannel(event.getMessage().getChannel(), serverReadyStrings[next]); - return; - } - if (!event.getMessage().getChannel().isPrivate() - && !(event.getMessage().getContent().startsWith("/") - && event.getChannel().getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // - return; - if (MCChatPrivate.isMinecraftChatEnabled(event.getAuthor().toString())) - if (!event.getMessage().getContent().equalsIgnoreCase("mcchat")) - return; - if (event.getMessage().getAuthor().isBot()) - return; - runCommand(event.getMessage(), false); - } - }, new IListener() { - @Override - public void handle(PresenceUpdateEvent event) { - if (DiscordPlugin.SafeMode) - return; - val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0); - if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) - && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() - .anyMatch(r -> r.getLongID() == devrole.getLongID()) - && DiscordPlugin.devServer.getUsersByRole(devrole).stream() - .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) - && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) - && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", - new EmbedBuilder() - .withImage( - "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - .build()); - lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); - } - } - }, (IListener) event -> { - Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole())) - return; //Deleted or not a game role - DiscordPlugin.GameRoles.add(event.getRole().getName()); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); - }, 100); - }, (IListener) event -> { - if (DiscordPlugin.GameRoles.remove(event.getRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role."); - }, (IListener) event -> { //Role update event - if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { - if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); - } else { - if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) - return; - boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role - DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color - if (removed) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); - else - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); - } - }}; - } + /* + MentionEvent: + - CommandListener (starts with mention, in #bot unless 'channelcon') - /** - * Runs a ChromaBot command. - * - * @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 (always true if mentionedonly is false) - */ - public static boolean runCommand(IMessage message, boolean mentionedonly) { - debug("A"); - if (DiscordPlugin.SafeMode) - return true; - debug("B"); - final StringBuilder cmdwithargs = new StringBuilder(message.getContent()); - final String mention = DiscordPlugin.dc.getOurUser().mention(false); - final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); - 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(r -> r.mention())::iterator) - gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions - debug("C"); - if (mentionedonly && !gotmention) { - message.getChannel().setTypingStatus(false); - return false; - } - debug("D"); - message.getChannel().setTypingStatus(true); - String cmdwithargsString = cmdwithargs.toString().trim(); //Remove spaces between mention and command - int index = cmdwithargsString.indexOf(" "); - String cmd; - String args; - if (index == -1) { - cmd = cmdwithargsString; - args = ""; - } else { - cmd = cmdwithargsString.substring(0, index); - args = cmdwithargsString.substring(index + 1).trim(); //In case there are multiple spaces - } - debug("E"); - DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message); - message.getChannel().setTypingStatus(false); - return true; - } + MessageReceivedEvent: + - 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(MentionEvent event) { + if (DiscordPlugin.SafeMode) + return; + if (event.getMessage().getAuthor().isBot()) + return; + CommandListener.runCommand(event.getMessage(), true); + } + }, new IListener() { + @Override + public void handle(MessageReceivedEvent event) { + if (DiscordPlugin.SafeMode) + return; + if (event.getMessage().getAuthor().isBot()) + return; + boolean handled = false; + val mcchat = Component.getComponents().get(MinecraftChatModule.class); + if (mcchat != null && mcchat.isEnabled()) + handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); + if (!handled) + handled = CommandListener.runCommand(event.getMessage(), false); + } + }, new IListener() { + @Override + public void handle(PresenceUpdateEvent event) { + if (DiscordPlugin.SafeMode) + return; + val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0); + if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) + && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) + && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() + .anyMatch(r -> r.getLongID() == devrole.getLongID()) + && DiscordPlugin.devServer.getUsersByRole(devrole).stream() + .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) + && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) + && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { + DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", + new EmbedBuilder() + .withImage( + "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") + .build()); + lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); + } + } + }, (IListener) event -> { + Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { + if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole())) + return; //Deleted or not a game role + DiscordPlugin.GameRoles.add(event.getRole().getName()); + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + }, 100); + }, (IListener) event -> { + if (DiscordPlugin.GameRoles.remove(event.getRole().getName())) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role."); + }, (IListener) event -> { //Role update event + if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { + if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + } else { + if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + return; + boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role + DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color + if (removed) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + else + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + } + }}; + } private static boolean debug = false; @@ -217,21 +130,4 @@ public class CommonListeners { public static boolean debug() { return debug = !debug; } - - private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { - if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text - if (cmdwithargs.length() > mention.length() + 1) - cmdwithargs.delete(0, - cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length()); - else - cmdwithargs.replace(0, cmdwithargs.length(), "help"); - else { - if (cmdwithargs.length() > 0 && cmdwithargs.charAt(0) == '/') - cmdwithargs.deleteCharAt(0); //Don't treat / as mention, mentions can be used in public mcchat - return false; - } - if (cmdwithargs.length() == 0) - cmdwithargs.replace(0, cmdwithargs.length(), "help"); - return true; - } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/DiscordListener.java b/src/main/java/buttondevteam/discordplugin/listeners/DiscordListener.java new file mode 100644 index 0000000..292a1a1 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/listeners/DiscordListener.java @@ -0,0 +1,4 @@ +package buttondevteam.discordplugin.listeners; + +public interface DiscordListener { +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java similarity index 91% rename from src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java rename to src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index 24c6390..3c05f02 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -1,8 +1,8 @@ -package buttondevteam.discordplugin.commands; +package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.mcchat.MCChatPrivate; +import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.lib.TBMCCoreAPI; import sx.blah.discord.handle.obj.IMessage; @@ -13,7 +13,7 @@ public class MCChatCommand extends DiscordCommandBase { return "mcchat"; } - @Override + @Override //TODO: Only register if module is enabled public boolean run(IMessage message, String args) { if (!message.getChannel().isPrivate()) { DiscordPlugin.sendMessageToChannel(message.getChannel(), diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 15489e5..67c7b0a 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -5,7 +5,6 @@ import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordSender; import buttondevteam.discordplugin.DiscordSenderBase; -import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; @@ -22,7 +21,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.events.IListener; 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; @@ -43,7 +41,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -public class MCChatListener implements Listener, IListener { +public class MCChatListener implements Listener { private BukkitTask sendtask; private LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); private Runnable sendrunnable; @@ -231,27 +229,25 @@ public class MCChatListener implements Listener, IListener private Runnable recrun; private static Thread recthread; - @Override // Discord - TODO: Call from the common listener - public void handle(MessageReceivedEvent ev) { + // Discord + public boolean handleDiscord(MessageReceivedEvent ev) { if (!ComponentManager.isEnabled(MinecraftChatModule.class)) - return; + return false; val author = ev.getMessage().getAuthor(); - if (author.isBot()) - return; final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getChannel()); - if (!ev.getMessage().getChannel().getStringID().equals(DiscordPlugin.chatchannel.getStringID()) + if (ev.getMessage().getChannel().getLongID() != DiscordPlugin.chatchannel.getLongID() && !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID())) && !hasCustomChat) - return; - if (ev.getMessage().getContent().equalsIgnoreCase("mcchat")) - return; // Race condition: If it gets here after it enabled mcchat it says it - I might as well allow disabling with this (CommonListeners) - if (CommonListeners.runCommand(ev.getMessage(), true)) - return; + return false; //Chat isn't enabled on this channel + if (hasCustomChat && ev.getMessage().getContent().length() < "/mcchat<>".length() + && ev.getMessage().getContent().replace("/", "") + .equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat + return false; //Allow disabling the chat if needed MCChatUtils.resetLastMessage(ev.getChannel()); lastlist++; recevents.add(ev); if (rectask != null) - return; + return true; recrun = () -> { //Don't return in a while loop next time recthread = Thread.currentThread(); processDiscordToMC(); @@ -259,6 +255,7 @@ public class MCChatListener implements Listener, IListener 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() { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 12ddb78..9af7a5e 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -3,13 +3,19 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import lombok.Getter; public class MinecraftChatModule extends Component { + private @Getter MCChatListener listener; + + public MCChatListener getListener() { //It doesn't want to generate + return listener; + } @Override protected void enable() { - MCChatListener mcchat = new MCChatListener(); - DiscordPlugin.dc.getDispatcher().registerListener(mcchat); - TBMCCoreAPI.RegisterEventsForExceptions(mcchat, getPlugin()); + listener = new MCChatListener(); + DiscordPlugin.dc.getDispatcher().registerListener(listener); + TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin()); } -- 2.30.2 From 040373280ee44ad6ed934e562f9749cbf23a44f9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 23 Dec 2018 22:34:26 +0100 Subject: [PATCH 030/108] Everything seems to work Removed double handling of certain events in MCListeners Removed MentionEvent handling completely Some mcchat fixes --- .../commands/ChannelconCommand.java | 9 ++- .../listeners/CommandListener.java | 10 +--- .../listeners/CommonListeners.java | 23 +++----- .../discordplugin/listeners/MCListener.java | 58 ------------------- .../discordplugin/mcchat/MCChatListener.java | 3 + .../discordplugin/mcchat/MCChatPrivate.java | 8 ++- .../discordplugin/mcchat/MCChatUtils.java | 2 +- .../discordplugin/mcchat/MCListener.java | 35 ++++++++++- 8 files changed, 59 insertions(+), 89 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index a018a1e..c89baab 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.ChannelconBroadcast; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.mcchat.MCChatCustom; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.player.TBMCPlayer; @@ -99,10 +100,12 @@ public class ChannelconCommand extends DiscordCommandBase { "---- Channel connect ---", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "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 #bot use /connect .", // - "Call this command from the channel you want to use. Usage: @ChromaBot channelcon ", // + "You also need to have your Minecraft account connected. In #bot use " + DiscordPlugin.getPrefix() + "connect .", // + "Call this command from the channel you want to use.", // + "Usage: @" + DiscordPlugin.dc.getOurUser().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 / prefix only works in #bot.", // + "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in #bot.", // "Invite link: " // }; } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index d1d9386..85f0fd4 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -15,17 +15,13 @@ public class CommandListener { */ public static boolean runCommand(IMessage message, boolean mentionedonly) { final IChannel channel = message.getChannel(); - if (mentionedonly) { - if (!channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()) - && !message.getContent().contains("channelcon")) //Allow channelcon in other servers - return false; //Private chat is handled without mentions - } else { + if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!message.getChannel().isPrivate() - && !(message.getContent().startsWith("/") + && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() && channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // return false; + message.getChannel().setTypingStatus(true); // Fun } - message.getChannel().setTypingStatus(true); // Fun final StringBuilder cmdwithargs = new StringBuilder(message.getContent()); final String mention = DiscordPlugin.dc.getOurUser().mention(false); final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 92cf74b..7cc3dcc 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -7,7 +7,6 @@ import buttondevteam.lib.architecture.Component; import lombok.val; import org.bukkit.Bukkit; import sx.blah.discord.api.events.IListener; -import sx.blah.discord.handle.impl.events.guild.channel.message.MentionEvent; 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; @@ -41,23 +40,15 @@ public class CommonListeners { /* MentionEvent: - - CommandListener (starts with mention, in #bot unless 'channelcon') + - CommandListener (starts with mention, only 'channelcon' and not in #bot) MessageReceivedEvent: + - v CommandListener (starts with mention, in #bot or a connected chat) - 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(MentionEvent event) { - if (DiscordPlugin.SafeMode) - return; - if (event.getMessage().getAuthor().isBot()) - return; - CommandListener.runCommand(event.getMessage(), true); - } - }, new IListener() { + return new IListener[]{new IListener() { @Override public void handle(MessageReceivedEvent event) { if (DiscordPlugin.SafeMode) @@ -65,9 +56,13 @@ public class CommonListeners { if (event.getMessage().getAuthor().isBot()) return; boolean handled = false; + if (event.getChannel().getLongID() == DiscordPlugin.botchannel.getLongID() //If mentioned, that's higher than chat + || event.getMessage().getContent().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()) - handled = ((MinecraftChatModule) mcchat).getListener().handleDiscord(event); + 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); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index a01e727..b36414d 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -1,34 +1,19 @@ package buttondevteam.discordplugin.listeners; -import buttondevteam.discordplugin.ChannelconBroadcast; -import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.mcchat.MCChatUtils; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; -import buttondevteam.lib.player.TBMCYEEHAWEvent; -import com.earth2me.essentials.CommandSource; import lombok.val; -import net.ess3.api.events.MuteStatusChangeEvent; import org.bukkit.Bukkit; -import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.server.BroadcastMessageEvent; import org.bukkit.event.server.ServerCommandEvent; import org.bukkit.plugin.AuthorNagException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; -import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.IUser; -import sx.blah.discord.util.DiscordException; -import sx.blah.discord.util.MissingPermissionsException; import java.util.Arrays; import java.util.logging.Level; @@ -53,49 +38,6 @@ public class MCListener implements Listener { DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped } - @EventHandler - public void onPlayerMute(MuteStatusChangeEvent e) { - try { - DPUtils.performNoWait(() -> { - final IRole role = DiscordPlugin.dc.getRoleByID(164090010461667328L); - 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 IUser user = DiscordPlugin.dc.getUserByID( - Long.parseLong(p.getDiscordID())); - if (e.getValue()) - user.addRole(role); - else - user.removeRole(role); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); - }); - } catch (DiscordException | MissingPermissionsException ex) { - TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", - ex); - } - } - - @EventHandler - public void onChatSystemMessage(TBMCSystemChatEvent event) { - MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event); - } - - @EventHandler - public void onBroadcastMessage(BroadcastMessageEvent event) { - MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); - } - - @EventHandler - public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support - String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() - : event.getSender().getName(); - //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO - MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); - } - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; public static void callEventExcludingSome(Event event) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 67c7b0a..98eb523 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordSender; import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.listeners.CommandListener; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; @@ -243,6 +244,8 @@ public class MCChatListener implements Listener { && ev.getMessage().getContent().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()); lastlist++; recevents.add(ev); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 5edcfa0..8356b44 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -13,6 +13,8 @@ import sx.blah.discord.handle.obj.IUser; import java.util.ArrayList; +import static buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome; + public class MCChatPrivate { /** @@ -29,11 +31,11 @@ public class MCChatPrivate { val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence - MCListener.callEventExcludingSome(new PlayerJoinEvent(sender, "")); + callEventExcludingSome(new PlayerJoinEvent(sender, "")); } else { val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel, user); if (p == null)// Player is offline - If the player is online, that takes precedence - MCListener.callEventExcludingSome(new PlayerQuitEvent(sender, "")); + callEventExcludingSome(new PlayerQuitEvent(sender, "")); } } if (!start) @@ -55,7 +57,7 @@ public class MCChatPrivate { public static void logoutAll() { for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) - MCListener.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); + callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); MCChatUtils.ConnectedSenders.clear(); } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index cb476a2..6826f6e 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -50,7 +50,7 @@ public class MCChatUtils { private static void updatePL(LastMsgData lmd) { String topic = lmd.channel.getTopic(); - if (topic.length() == 0) + if (topic == null || topic.length() == 0) topic = ".\n----\nMinecraft chat\n----\n."; String[] s = topic.split("\\n----\\n"); if (s.length < 3) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 9b419e9..2e2d089 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -2,12 +2,13 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.player.TBMCPlayerJoinEvent; -import buttondevteam.lib.player.TBMCPlayerQuitEvent; -import buttondevteam.lib.player.TBMCYEEHAWEvent; +import buttondevteam.lib.player.*; +import com.earth2me.essentials.CommandSource; import lombok.val; import net.ess3.api.events.AfkStatusChangeEvent; +import net.ess3.api.events.MuteStatusChangeEvent; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -20,7 +21,10 @@ 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.IUser; +import sx.blah.discord.util.DiscordException; +import sx.blah.discord.util.MissingPermissionsException; class MCListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) @@ -98,6 +102,31 @@ class MCListener implements Listener { MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); } + @EventHandler + public void onPlayerMute(MuteStatusChangeEvent e) { + try { + DPUtils.performNoWait(() -> { + final IRole role = DiscordPlugin.dc.getRoleByID(164090010461667328L); + 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 IUser user = DiscordPlugin.dc.getUserByID( + Long.parseLong(p.getDiscordID())); + if (e.getValue()) + user.addRole(role); + else + user.removeRole(role); + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); + }); + } catch (DiscordException | MissingPermissionsException ex) { + TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", + ex); + } + } + @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event); -- 2.30.2 From 68e69782ee022f531967955c042f14042e94cdad Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 23 Dec 2018 23:50:13 +0100 Subject: [PATCH 031/108] Well, not everything Fixed some private mcchat issues Fixed #85 --- .../discordplugin/listeners/MCListener.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 3 ++- .../discordplugin/mcchat/MCChatPrivate.java | 14 ++++++++++---- .../discordplugin/mcchat/MCListener.java | 6 ++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index b36414d..a39d5fc 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -38,7 +38,7 @@ public class MCListener implements Listener { DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped } - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises"}; + private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises", "JourneyMapServer"}; //TODO: Make configurable public static void callEventExcludingSome(Event event) { callEventExcluding(event, false, EXCLUDED_PLUGINS); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 98eb523..882921b 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -240,7 +240,8 @@ public class MCChatListener implements Listener { && !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID())) && !hasCustomChat) return false; //Chat isn't enabled on this channel - if (hasCustomChat && ev.getMessage().getContent().length() < "/mcchat<>".length() + 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 return false; //Allow disabling the chat if needed diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 8356b44..99c1740 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -2,9 +2,11 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.player.TBMCPlayer; 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.IChannel; @@ -31,13 +33,13 @@ public class MCChatPrivate { val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName()); MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender); if (p == null)// Player is offline - If the player is online, that takes precedence - callEventExcludingSome(new PlayerJoinEvent(sender, "")); + callEventSync(new PlayerJoinEvent(sender, "")); } else { val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel, user); if (p == null)// Player is offline - If the player is online, that takes precedence - callEventExcludingSome(new PlayerQuitEvent(sender, "")); + callEventSync(new PlayerQuitEvent(sender, "")); } - } + } // ---- PermissionsEx warning is normal on logout ---- if (!start) MCChatUtils.lastmsgfromd.remove(channel.getLongID()); return start // @@ -57,7 +59,11 @@ public class MCChatPrivate { public static void logoutAll() { for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) - callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); + callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync MCChatUtils.ConnectedSenders.clear(); } + + private static void callEventSync(Event event) { + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> callEventExcludingSome(event)); + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 2e2d089..2c5fdb0 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -9,6 +9,7 @@ import com.earth2me.essentials.CommandSource; import lombok.val; import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.api.events.MuteStatusChangeEvent; +import net.ess3.api.events.NickChangeEvent; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -144,4 +145,9 @@ class MCListener implements Listener { //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } + + @EventHandler + public void onNickChange(NickChangeEvent event) { + MCChatUtils.updatePlayerList(); + } } -- 2.30.2 From 1911672b103c3da7349f47a1dfc3f4f484430154 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 26 Dec 2018 01:35:36 +0100 Subject: [PATCH 032/108] Christmas hotfix --- .../discordplugin/listeners/CommandListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 85f0fd4..73e827d 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -4,6 +4,7 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.DiscordCommandBase; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IMessage; +import sx.blah.discord.handle.obj.IRole; public class CommandListener { /** @@ -14,6 +15,8 @@ public class CommandListener { * @return Whether it ran the command */ public static boolean runCommand(IMessage 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(); if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!message.getChannel().isPrivate() @@ -27,7 +30,7 @@ public class CommandListener { final String mentionNick = DiscordPlugin.dc.getOurUser().mention(true); 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(r -> r.mention())::iterator) + for (String mentionRole : (Iterable) message.getRoleMentions().stream().filter(r -> DiscordPlugin.dc.getOurUser().hasRole(r)).map(IRole::mention)::iterator) gotmention = checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention; // Delete all mentions if (mentionedonly && !gotmention) { message.getChannel().setTypingStatus(false); -- 2.30.2 From f13c8321cd5e70cc46412074756b896d49e49e88 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 27 Dec 2018 01:16:55 +0100 Subject: [PATCH 033/108] Slight API change --- .../buttondevteam/discordplugin/mcchat/MCChatListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 882921b..c2ec714 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -121,13 +121,13 @@ public class MCChatListener implements Listener { || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); if (e.getChannel().isGlobal() - && (e.isFromcmd() || isdifferentchannel.test(DiscordPlugin.chatchannel))) + && (e.isFromCommand() || isdifferentchannel.test(DiscordPlugin.chatchannel))) doit.accept(MCChatUtils.lastmsgdata == null ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(DiscordPlugin.chatchannel, null) : MCChatUtils.lastmsgdata); for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { - if ((e.isFromcmd() || isdifferentchannel.test(data.channel)) + if ((e.isFromCommand() || isdifferentchannel.test(data.channel)) && e.shouldSendTo(MCChatUtils.getSender(data.channel, data.user))) doit.accept(data); } @@ -135,7 +135,7 @@ public class MCChatListener implements Listener { val iterator = MCChatCustom.lastmsgCustom.iterator(); while (iterator.hasNext()) { val lmd = iterator.next(); - if ((e.isFromcmd() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord + 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 -- 2.30.2 From 93af5f66d220c7c55e92035357ee2b773f7de1fb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 10 Jan 2019 01:45:45 +0100 Subject: [PATCH 034/108] Fixes and improvements (config) Fixed occasional ConcurrentModificationException with the custom chat loading Waiting much less on MC command responses (0.2s instead of 0.5s) Made the #bot channel configurable Linking the #bot channel everywhere it's mentioned #51 --- .editorconfig | 19 + .../buttondevteam/discordplugin/DPUtils.java | 18 + .../discordplugin/DiscordPlugin.java | 910 +++++++++--------- .../discordplugin/DiscordSenderBase.java | 2 +- .../commands/ChannelconCommand.java | 11 +- .../discordplugin/fun/FunModule.java | 4 +- .../listeners/CommandListener.java | 2 +- .../listeners/CommonListeners.java | 256 ++--- .../discordplugin/mcchat/MCChatListener.java | 2 +- .../mccommands/AcceptMCCommand.java | 87 +- .../mccommands/DeclineMCCommand.java | 63 +- 11 files changed, 710 insertions(+), 664 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4b9e6ec --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = false +indent_style = space +indent_size = 4 + +[*.json] +indent_style = space +indent_size = 2 + +[*.java] +indent_style = tab +tab_width = 4 + +[{*.yml, *.yaml}] +indent_style = space +indent_size = 2 + diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index f68053a..6c079f6 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -1,6 +1,10 @@ package buttondevteam.discordplugin; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.architecture.IHaveConfig; import org.bukkit.Bukkit; +import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IIDLinkedObject; import sx.blah.discord.util.EmbedBuilder; import sx.blah.discord.util.RequestBuffer; import sx.blah.discord.util.RequestBuffer.IRequest; @@ -103,4 +107,18 @@ 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) + } + + /** + * Mentions the bot channel. Useful for help texts. + * + * @return The string for mentioning the channel + */ + public static String botmention() { + if (DiscordPlugin.plugin == null) return "#bot"; + return DiscordPlugin.plugin.CommandChannel().get().mention(); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 9870d99..0bf2b3b 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,450 +1,460 @@ -package buttondevteam.discordplugin; - -import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; -import buttondevteam.discordplugin.commands.DiscordCommandBase; -import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; -import buttondevteam.discordplugin.listeners.CommonListeners; -import buttondevteam.discordplugin.listeners.MCListener; -import buttondevteam.discordplugin.mcchat.*; -import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; -import buttondevteam.discordplugin.mccommands.ResetMCCommand; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.architecture.ButtonPlugin; -import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.chat.Channel; -import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.ChromaGamerBase; -import com.google.common.io.Files; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import lombok.val; -import net.milkbowl.vault.permission.Permission; -import org.bukkit.Bukkit; -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.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; - -public class DiscordPlugin extends ButtonPlugin implements IListener { - private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; - private static boolean stop = false; - public static IDiscordClient dc; - public static DiscordPlugin plugin; - public static boolean SafeMode = true; - public static List GameRoles; - - public ConfigData Prefix() { - return getData("prefix", '/'); - } - - public static char getPrefix() { - if (plugin == null) return '/'; - return plugin.Prefix().get(); - } - - @Override - public void pluginEnable() { - stop = false; //If not the first time - try { - Bukkit.getLogger().info("Initializing DiscordPlugin..."); - plugin = this; - lastannouncementtime = getConfig().getLong("lastannouncementtime"); - lastseentime = getConfig().getLong("lastseentime"); - ClientBuilder cb = new ClientBuilder(); - cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); - dc = cb.login(); - dc.getDispatcher().registerListener(this); - } catch (Exception e) { - e.printStackTrace(); - Bukkit.getPluginManager().disablePlugin(this); - } - } - - public static IChannel botchannel; - public static IChannel annchannel; - public static IChannel genchannel; - public static IChannel chatchannel; - public static IChannel botroomchannel; - public static IChannel modlogchannel; - /** - * Don't send messages, just receive, the same channel is used when testing - */ - public static IChannel officechannel; - public static IChannel updatechannel; - public static IChannel devofficechannel; - public static IGuild mainServer; - public static IGuild devServer; - - 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"); - task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { - if (mainServer == null || devServer == null) { - mainServer = event.getClient().getGuildByID(125813020357165056L); - devServer = event.getClient().getGuildByID(219529124321034241L); - } - if (mainServer == null || devServer == null) - return; // Retry - if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - botchannel = mainServer.getChannelByID(209720707188260864L); // bot - annchannel = mainServer.getChannelByID(126795071927353344L); // announcements - genchannel = mainServer.getChannelByID(125813020357165056L); // general - chatchannel = mainServer.getChannelByID(249663564057411596L); // minecraft_chat - botroomchannel = devServer.getChannelByID(239519012529111040L); // bot-room - officechannel = devServer.getChannelByID(219626707458457603L); // developers-office - updatechannel = devServer.getChannelByID(233724163519414272L); // server-updates - devofficechannel = officechannel; // developers-office - modlogchannel = mainServer.getChannelByID(283840717275791360L); // modlog - dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft"); - } else { - botchannel = devServer.getChannelByID(239519012529111040L); // bot-room - annchannel = botchannel; // bot-room - genchannel = botchannel; // bot-room - botroomchannel = botchannel;// bot-room - chatchannel = botchannel;// bot-room - officechannel = devServer.getChannelByID(219626707458457603L); // developers-office - updatechannel = botchannel; - devofficechannel = botchannel;// bot-room - modlogchannel = botchannel; // bot-room - dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); - } - if (botchannel == null || annchannel == null || genchannel == null || botroomchannel == null - || chatchannel == null || officechannel == null || updatechannel == null) - return; // Retry - SafeMode = false; - if (task != null) - task.cancel(); - if (!sent) { - new ChromaBot(this).updatePlayerList(); - GameRoles = mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); - - val chcons = getConfig().getConfigurationSection("chcons"); - if (chcons != null) { - val chconkeys = chcons.getKeys(false); - for (val chconkey : chconkeys) { - val chcon = chcons.getConfigurationSection(chconkey); - val mcch = Channel.getChannels().stream().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); - val ch = dc.getChannelByID(chcon.getLong("chid")); - val did = chcon.getLong("did"); - val user = dc.fetchUser(did); - val dcp = new DiscordConnectedPlayer(user, ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname")); - val groupid = chcon.getString("groupid"); - val toggles = chcon.getInt("toggles"); - if (!mcch.isPresent() || ch == null || user == null || groupid == null) - continue; - MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles); - } - } - - DiscordCommandBase.registerCommands(); - if (ResetMCCommand.resetting) - 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); - - ResetMCCommand.resetting = false; //This is the last event handling this flag - - getConfig().set("serverup", true); - saveConfig(); - DPUtils.performNoWait(() -> { - try { - List msgs = genchannel.getPinnedMessages(); - for (int i = msgs.size() - 1; i >= 10; i--) { // Unpin all pinned messages except the newest 10 - genchannel.unpin(msgs.get(i)); - Thread.sleep(10); - } - } catch (InterruptedException ignore) { - } - }); - 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.")); - Bukkit.getPluginManager().disablePlugin(this); - } - TBMCCoreAPI.SendUnsentExceptions(); - TBMCCoreAPI.SendUnsentDebugMessages(); - /*if (!TBMCCoreAPI.IsTestServer()) { - final Calendar currentCal = Calendar.getInstance(); - final Calendar newCal = Calendar.getInstance(); - currentCal.set(currentCal.get(Calendar.YEAR), currentCal.get(Calendar.MONTH), - currentCal.get(Calendar.DAY_OF_MONTH), 4, 10); - if (currentCal.get(Calendar.DAY_OF_MONTH) % 9 == 0 && currentCal.before(newCal)) { - Random rand = new Random(); - sendMessageToChannel(dc.getChannels().get(rand.nextInt(dc.getChannels().size())), - "You could make a religion out of this"); - } - }*/ - } - }, 0, 10); - for (IListener listener : CommonListeners.getListeners()) - dc.getDispatcher().registerListener(listener); - Component.registerComponent(this, new GeneralEventBroadcasterModule()); - Component.registerComponent(this, new MinecraftChatModule()); - Component.registerComponent(this, new ExceptionListenerModule()); - TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); - TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); - TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); - ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase - ? ((DiscordSenderBase) sender).getChromaUser() : null)); - new Thread(this::AnnouncementGetterThreadMethod).start(); - setupProviders(); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); - } - } - - public boolean isGameRole(IRole r) { - if (r.getGuild().getLongID() != mainServer.getLongID()) - return false; //Only allow on the main server - val rc = new Color(149, 165, 166, 0); - return r.getColor().equals(rc) - && r.getPosition() < mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role - } - - /** - * Always true, except when running "stop" from console - */ - public static boolean Restart; - - @Override - public void pluginDisable() { - stop = true; - MCChatPrivate.logoutAll(); - getConfig().set("lastannouncementtime", lastannouncementtime); - getConfig().set("lastseentime", lastseentime); - getConfig().set("serverup", false); - - val chcons = MCChatCustom.getCustomChats(); - val chconsc = getConfig().createSection("chcons"); - for (val chcon : chcons) { - val chconc = chconsc.createSection(chcon.channel.getStringID()); - chconc.set("mcchid", chcon.mcchannel.ID); - chconc.set("chid", chcon.channel.getLongID()); - chconc.set("did", chcon.user.getLongID()); - chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); - chconc.set("mcname", chcon.dcp.getName()); - chconc.set("groupid", chcon.groupID); - chconc.set("toggles", chcon.toggles); - } - - saveConfig(); - EmbedObject embed; - if (ResetMCCommand.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); - ChromaBot.getInstance().updatePlayerList(); - try { - SafeMode = true; // Stop interacting with Discord - MCChatListener.stop(true); - ChromaBot.delete(); - dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing - dc.logout(); - mainServer = devServer = null; //Fetch servers and channels again - sent = false; - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); - } - } - - private long lastannouncementtime = 0; - private long lastseentime = 0; - public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.of("✅"); - - private void AnnouncementGetterThreadMethod() { - while (!stop) { - try { - if (SafeMode) { - Thread.sleep(10000); - continue; - } - String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); - JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() - .get("children").getAsJsonArray(); - StringBuilder msgsb = new StringBuilder(); - StringBuilder modmsgsb = new StringBuilder(); - long lastanntime = lastannouncementtime; - for (int i = json.size() - 1; i >= 0; i--) { - JsonObject item = json.get(i).getAsJsonObject(); - final JsonObject data = item.get("data").getAsJsonObject(); - String author = data.get("author").getAsString(); - JsonElement distinguishedjson = data.get("distinguished"); - String distinguished; - if (distinguishedjson.isJsonNull()) - distinguished = null; - else - distinguished = distinguishedjson.getAsString(); - String permalink = "https://www.reddit.com" + data.get("permalink").getAsString(); - long date = data.get("created_utc").getAsLong(); - if (date > lastseentime) - lastseentime = date; - else if (date > lastannouncementtime) { - do { - val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit"); - if (reddituserclass == null) - break; - val user = ChromaGamerBase.getUser(author, reddituserclass); - String id = user.getConnectedID(DiscordPlayer.class); - if (id != null) - author = "<@" + id + ">"; - } while (false); - if (!author.startsWith("<")) - author = "/u/" + author; - (distinguished != null && distinguished.equals("moderator") ? modmsgsb : msgsb) - .append("A new post was submitted to the subreddit by ").append(author).append("\n") - .append(permalink).append("\n"); - lastanntime = date; - } - } - if (msgsb.length() > 0) - genchannel.pin(sendMessageToChannelWait(genchannel, msgsb.toString())); - if (modmsgsb.length() > 0) - sendMessageToChannel(annchannel, modmsgsb.toString()); - if (lastannouncementtime != lastanntime) { - lastannouncementtime = lastanntime; // If sending succeeded - getConfig().set("lastannouncementtime", lastannouncementtime); - getConfig().set("lastseentime", lastseentime); - saveConfig(); - } - } catch (Exception e) { - e.printStackTrace(); - } - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - - public static void sendMessageToChannel(IChannel channel, String message) { - sendMessageToChannel(channel, message, null); - } - - 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 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); - Bukkit.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) { - Bukkit.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; - } -} +package buttondevteam.discordplugin; + +import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; +import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; +import buttondevteam.discordplugin.listeners.CommonListeners; +import buttondevteam.discordplugin.listeners.MCListener; +import buttondevteam.discordplugin.mcchat.*; +import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; +import buttondevteam.discordplugin.mccommands.ResetMCCommand; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.ButtonPlugin; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.chat.Channel; +import buttondevteam.lib.chat.TBMCChatAPI; +import buttondevteam.lib.player.ChromaGamerBase; +import com.google.common.io.Files; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.val; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +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.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +public class DiscordPlugin extends ButtonPlugin implements IListener { + private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; + private static boolean stop = false; + public static IDiscordClient dc; + public static DiscordPlugin plugin; + public static boolean SafeMode = true; + public static List GameRoles; + + 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); + } + + public ConfigData CommandChannel() { + return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); + } + + @Override + public void pluginEnable() { + stop = false; //If not the first time + try { + Bukkit.getLogger().info("Initializing DiscordPlugin..."); + plugin = this; + lastannouncementtime = getConfig().getLong("lastannouncementtime"); + lastseentime = getConfig().getLong("lastseentime"); + ClientBuilder cb = new ClientBuilder(); + cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); + dc = cb.login(); + dc.getDispatcher().registerListener(this); + } catch (Exception e) { + e.printStackTrace(); + Bukkit.getPluginManager().disablePlugin(this); + } + } + + public static IChannel botchannel; //Can be removed + public static IChannel annchannel; + public static IChannel genchannel; + public static IChannel chatchannel; + public static IChannel botroomchannel; + public static IChannel modlogchannel; + /** + * Don't send messages, just receive, the same channel is used when testing + */ + public static IChannel officechannel; + public static IChannel updatechannel; + public static IChannel devofficechannel; + public static IGuild mainServer; + public static IGuild devServer; + + 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"); + task = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { + if (mainServer == null || devServer == null) { + mainServer = event.getClient().getGuildByID(125813020357165056L); + devServer = event.getClient().getGuildByID(219529124321034241L); + } + if (mainServer == null || devServer == null) + return; // Retry + if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() + botchannel = mainServer.getChannelByID(209720707188260864L); // bot + annchannel = mainServer.getChannelByID(126795071927353344L); // announcements + genchannel = mainServer.getChannelByID(125813020357165056L); // general + chatchannel = mainServer.getChannelByID(249663564057411596L); // minecraft_chat + botroomchannel = devServer.getChannelByID(239519012529111040L); // bot-room + officechannel = devServer.getChannelByID(219626707458457603L); // developers-office + updatechannel = devServer.getChannelByID(233724163519414272L); // server-updates + devofficechannel = officechannel; // developers-office + modlogchannel = mainServer.getChannelByID(283840717275791360L); // modlog + dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft"); + } else { + botchannel = devServer.getChannelByID(239519012529111040L); // bot-room + annchannel = botchannel; // bot-room + genchannel = botchannel; // bot-room + botroomchannel = botchannel;// bot-room + chatchannel = botchannel;// bot-room + officechannel = devServer.getChannelByID(219626707458457603L); // developers-office + updatechannel = botchannel; + devofficechannel = botchannel;// bot-room + modlogchannel = botchannel; // bot-room + dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); + } + if (botchannel == null || annchannel == null || genchannel == null || botroomchannel == null + || chatchannel == null || officechannel == null || updatechannel == null) + return; // Retry + SafeMode = false; + if (task != null) + task.cancel(); + if (!sent) { + new ChromaBot(this).updatePlayerList(); + GameRoles = mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); + + val chcons = getConfig().getConfigurationSection("chcons"); + if (chcons != null) { + val chconkeys = chcons.getKeys(false); + for (val chconkey : chconkeys) { + val chcon = chcons.getConfigurationSection(chconkey); + val mcch = Channel.getChannels().stream().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); + val ch = dc.getChannelByID(chcon.getLong("chid")); + val did = chcon.getLong("did"); + val user = dc.fetchUser(did); + val groupid = chcon.getString("groupid"); + val toggles = chcon.getInt("toggles"); + if (!mcch.isPresent() || ch == null || user == null || groupid == null) + continue; + Bukkit.getScheduler().runTask(this, () -> { //<-- 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); + }); + } + } + + DiscordCommandBase.registerCommands(); + if (ResetMCCommand.resetting) + 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); + + ResetMCCommand.resetting = false; //This is the last event handling this flag + + getConfig().set("serverup", true); + saveConfig(); + DPUtils.performNoWait(() -> { + try { + List msgs = genchannel.getPinnedMessages(); + for (int i = msgs.size() - 1; i >= 10; i--) { // Unpin all pinned messages except the newest 10 + genchannel.unpin(msgs.get(i)); + Thread.sleep(10); + } + } catch (InterruptedException ignore) { + } + }); + 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(); + /*if (!TBMCCoreAPI.IsTestServer()) { + final Calendar currentCal = Calendar.getInstance(); + final Calendar newCal = Calendar.getInstance(); + currentCal.set(currentCal.get(Calendar.YEAR), currentCal.get(Calendar.MONTH), + currentCal.get(Calendar.DAY_OF_MONTH), 4, 10); + if (currentCal.get(Calendar.DAY_OF_MONTH) % 9 == 0 && currentCal.before(newCal)) { + Random rand = new Random(); + sendMessageToChannel(dc.getChannels().get(rand.nextInt(dc.getChannels().size())), + "You could make a religion out of this"); + } + }*/ + } + }, 0, 10); + for (IListener listener : CommonListeners.getListeners()) + dc.getDispatcher().registerListener(listener); + Component.registerComponent(this, new GeneralEventBroadcasterModule()); + Component.registerComponent(this, new MinecraftChatModule()); + Component.registerComponent(this, new ExceptionListenerModule()); + TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); + TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); + TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); + ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase + ? ((DiscordSenderBase) sender).getChromaUser() : null)); + new Thread(this::AnnouncementGetterThreadMethod).start(); + setupProviders(); + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); + } + } + + public boolean isGameRole(IRole r) { + if (r.getGuild().getLongID() != mainServer.getLongID()) + return false; //Only allow on the main server + val rc = new Color(149, 165, 166, 0); + return r.getColor().equals(rc) + && r.getPosition() < mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role + } + + /** + * Always true, except when running "stop" from console + */ + public static boolean Restart; + + @Override + public void pluginDisable() { + stop = true; + MCChatPrivate.logoutAll(); + getConfig().set("lastannouncementtime", lastannouncementtime); + getConfig().set("lastseentime", lastseentime); + getConfig().set("serverup", false); + + val chcons = MCChatCustom.getCustomChats(); + val chconsc = getConfig().createSection("chcons"); + for (val chcon : chcons) { + val chconc = chconsc.createSection(chcon.channel.getStringID()); + chconc.set("mcchid", chcon.mcchannel.ID); + chconc.set("chid", chcon.channel.getLongID()); + chconc.set("did", chcon.user.getLongID()); + chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); + chconc.set("mcname", chcon.dcp.getName()); + chconc.set("groupid", chcon.groupID); + chconc.set("toggles", chcon.toggles); + } + + saveConfig(); + EmbedObject embed; + if (ResetMCCommand.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); + ChromaBot.getInstance().updatePlayerList(); + try { + SafeMode = true; // Stop interacting with Discord + MCChatListener.stop(true); + ChromaBot.delete(); + dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing + dc.logout(); + mainServer = devServer = null; //Fetch servers and channels again + sent = false; + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); + } + } + + private long lastannouncementtime = 0; + private long lastseentime = 0; + public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.of("✅"); + + private void AnnouncementGetterThreadMethod() { + while (!stop) { + try { + if (SafeMode) { + Thread.sleep(10000); + continue; + } + String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); + JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() + .get("children").getAsJsonArray(); + StringBuilder msgsb = new StringBuilder(); + StringBuilder modmsgsb = new StringBuilder(); + long lastanntime = lastannouncementtime; + for (int i = json.size() - 1; i >= 0; i--) { + JsonObject item = json.get(i).getAsJsonObject(); + final JsonObject data = item.get("data").getAsJsonObject(); + String author = data.get("author").getAsString(); + JsonElement distinguishedjson = data.get("distinguished"); + String distinguished; + if (distinguishedjson.isJsonNull()) + distinguished = null; + else + distinguished = distinguishedjson.getAsString(); + String permalink = "https://www.reddit.com" + data.get("permalink").getAsString(); + long date = data.get("created_utc").getAsLong(); + if (date > lastseentime) + lastseentime = date; + else if (date > lastannouncementtime) { + do { + val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit"); + if (reddituserclass == null) + break; + val user = ChromaGamerBase.getUser(author, reddituserclass); + String id = user.getConnectedID(DiscordPlayer.class); + if (id != null) + author = "<@" + id + ">"; + } while (false); + if (!author.startsWith("<")) + author = "/u/" + author; + (distinguished != null && distinguished.equals("moderator") ? modmsgsb : msgsb) + .append("A new post was submitted to the subreddit by ").append(author).append("\n") + .append(permalink).append("\n"); + lastanntime = date; + } + } + if (msgsb.length() > 0) + genchannel.pin(sendMessageToChannelWait(genchannel, msgsb.toString())); + if (modmsgsb.length() > 0) + sendMessageToChannel(annchannel, modmsgsb.toString()); + if (lastannouncementtime != lastanntime) { + lastannouncementtime = lastanntime; // If sending succeeded + getConfig().set("lastannouncementtime", lastannouncementtime); + getConfig().set("lastseentime", lastseentime); + saveConfig(); + } + } catch (Exception e) { + e.printStackTrace(); + } + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + public static void sendMessageToChannel(IChannel channel, String message) { + sendMessageToChannel(channel, message, null); + } + + 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 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); + Bukkit.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) { + Bukkit.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; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java index b031bcb..6d4098b 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSenderBase.java @@ -62,7 +62,7 @@ public abstract class DiscordSenderBase implements CommandSender { (!broadcast && user != null ? user.mention() + "\n" : "") + msgtosend.trim()); sendtask = null; msgtosend = ""; - }, 10); // Waits a half second to gather all/most of the different messages + }, 4); // Waits a 0.2 second to gather all/most of the different messages } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while sending message to DiscordSender", e); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index c89baab..50ddb9a 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -1,9 +1,6 @@ package buttondevteam.discordplugin.commands; -import buttondevteam.discordplugin.ChannelconBroadcast; -import buttondevteam.discordplugin.DiscordConnectedPlayer; -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.mcchat.MCChatCustom; import buttondevteam.lib.chat.Channel; import buttondevteam.lib.player.TBMCPlayer; @@ -75,7 +72,7 @@ public class ChannelconCommand extends DiscordCommandBase { val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class); val chp = dp.getAs(TBMCPlayer.class); if (chp == null) { - message.reply("you need to connect your Minecraft account. On our server in #bot do /connect "); + message.reply("you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect "); return true; } DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()); @@ -100,12 +97,12 @@ public class ChannelconCommand extends DiscordCommandBase { "---- Channel connect ---", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "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 #bot use " + DiscordPlugin.getPrefix() + "connect .", // + "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 ", // "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 #bot.", // + "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", // "Invite link: " // }; } diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 5dea2d3..34d95e7 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -32,11 +32,11 @@ public class FunModule extends Component { }; private ConfigData serverReady() { - return getData("serverReady", true); + return getConfig().getData("serverReady", true); } private ConfigData> serverReadyAnswers() { - return getData("serverReadyAnswers", Arrays.asList(serverReadyStrings), + return getConfig().getData("serverReadyAnswers", Arrays.asList(serverReadyStrings), data -> (List) data, data -> data); //TODO: Test } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 73e827d..b6fe5c6 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -21,7 +21,7 @@ public class CommandListener { if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!message.getChannel().isPrivate() && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() - && channel.getStringID().equals(DiscordPlugin.botchannel.getStringID()))) // + && channel.getStringID().equals(DiscordPlugin.plugin.CommandChannel().get().getStringID()))) // return false; message.getChannel().setTypingStatus(true); // Fun } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 7cc3dcc..b372750 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -1,128 +1,128 @@ -package buttondevteam.discordplugin.listeners; - -import buttondevteam.discordplugin.DPUtils; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.mcchat.MinecraftChatModule; -import buttondevteam.lib.architecture.Component; -import lombok.val; -import org.bukkit.Bukkit; -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; -import sx.blah.discord.handle.obj.StatusType; -import sx.blah.discord.util.EmbedBuilder; - -import java.util.Calendar; -import java.util.concurrent.TimeUnit; - -public class CommonListeners { - - /*private static ArrayList dcListeners=new ArrayList<>(); - - public static void registerDiscordListener(DiscordListener listener) { - //Step 1: Get all events that are handled by us - //Step 2: Find methods that handle these - //...or just simply call the methods in the right order - } - - private static void callDiscordEvent(Event event) { - String name=event.getClass().getSimpleName(); - name=Character.toLowerCase(name.charAt(0))+name.substring(1); - for (Object listener : dcListeners) { - listener.getClass().getMethods(name, AsyncDiscordEvent.class); - } - }*/ - - private static long lasttime = 0; - - /* - MentionEvent: - - CommandListener (starts with mention, only 'channelcon' and not in #bot) - - MessageReceivedEvent: - - v CommandListener (starts with mention, in #bot or a connected chat) - - 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) { - if (DiscordPlugin.SafeMode) - return; - if (event.getMessage().getAuthor().isBot()) - return; - boolean handled = false; - if (event.getChannel().getLongID() == DiscordPlugin.botchannel.getLongID() //If mentioned, that's higher than chat - || event.getMessage().getContent().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); - } - }, new IListener() { - @Override - public void handle(PresenceUpdateEvent event) { - if (DiscordPlugin.SafeMode) - return; - val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0); - if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) - && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() - .anyMatch(r -> r.getLongID() == devrole.getLongID()) - && DiscordPlugin.devServer.getUsersByRole(devrole).stream() - .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) - && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) - && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", - new EmbedBuilder() - .withImage( - "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - .build()); - lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); - } - } - }, (IListener) event -> { - Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole())) - return; //Deleted or not a game role - DiscordPlugin.GameRoles.add(event.getRole().getName()); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); - }, 100); - }, (IListener) event -> { - if (DiscordPlugin.GameRoles.remove(event.getRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role."); - }, (IListener) event -> { //Role update event - if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { - if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); - } else { - if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) - return; - boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role - DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color - if (removed) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); - else - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); - } - }}; - } - - private static boolean debug = false; - - public static void debug(String debug) { - if (CommonListeners.debug) //Debug - DPUtils.getLogger().info(debug); - } - - public static boolean debug() { - return debug = !debug; - } -} +package buttondevteam.discordplugin.listeners; + +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.lib.architecture.Component; +import lombok.val; +import org.bukkit.Bukkit; +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; +import sx.blah.discord.handle.obj.StatusType; +import sx.blah.discord.util.EmbedBuilder; + +import java.util.Calendar; +import java.util.concurrent.TimeUnit; + +public class CommonListeners { + + /*private static ArrayList dcListeners=new ArrayList<>(); + + public static void registerDiscordListener(DiscordListener listener) { + //Step 1: Get all events that are handled by us + //Step 2: Find methods that handle these + //...or just simply call the methods in the right order + } + + private static void callDiscordEvent(Event event) { + String name=event.getClass().getSimpleName(); + name=Character.toLowerCase(name.charAt(0))+name.substring(1); + for (Object listener : dcListeners) { + listener.getClass().getMethods(name, AsyncDiscordEvent.class); + } + }*/ + + private static long lasttime = 0; + + /* + MentionEvent: + - CommandListener (starts with mention, only 'channelcon' and not in #bot) + + MessageReceivedEvent: + - v CommandListener (starts with mention, in #bot or a connected chat) + - 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) { + if (DiscordPlugin.SafeMode) + return; + if (event.getMessage().getAuthor().isBot()) + return; + boolean handled = false; + if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat + || event.getMessage().getContent().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); + } + }, new IListener() { + @Override + public void handle(PresenceUpdateEvent event) { + if (DiscordPlugin.SafeMode) + return; + val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0); + if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) + && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) + && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() + .anyMatch(r -> r.getLongID() == devrole.getLongID()) + && DiscordPlugin.devServer.getUsersByRole(devrole).stream() + .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) + && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) + && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { + DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", + new EmbedBuilder() + .withImage( + "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") + .build()); + lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); + } + } + }, (IListener) event -> { + Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { + if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole())) + return; //Deleted or not a game role + DiscordPlugin.GameRoles.add(event.getRole().getName()); + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + }, 100); + }, (IListener) event -> { + if (DiscordPlugin.GameRoles.remove(event.getRole().getName())) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role."); + }, (IListener) event -> { //Role update event + if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { + if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + } else { + if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + return; + boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role + DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color + if (removed) + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + else + DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + } + }}; + } + + private static boolean debug = false; + + public static void debug(String debug) { + if (CommonListeners.debug) //Debug + DPUtils.getLogger().info(debug); + } + + public static boolean debug() { + return debug = !debug; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index c2ec714..71b9609 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -313,7 +313,7 @@ public class MCChatListener implements Listener { .collect(Collectors.joining(", ")) + (user.getConnectedID(TBMCPlayer.class) == null ? "\nTo access your commands, first please connect your accounts, using /connect in " - + DiscordPlugin.botchannel.mention() + + DPUtils.botmention() + "\nThen y" : "\nY") + "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!"); diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java index 2f2ad21..29ed176 100755 --- a/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/AcceptMCCommand.java @@ -1,43 +1,44 @@ -package buttondevteam.discordplugin.mccommands; - -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 #bot 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; - } - -} +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 index 831ad89..813d6b9 100755 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DeclineMCCommand.java @@ -1,31 +1,32 @@ -package buttondevteam.discordplugin.mccommands; - -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 #bot 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; - } - -} +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; + } + +} -- 2.30.2 From baa9cb65c8bcf1f96267e2775063d332dbb4a912 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 12 Jan 2019 01:29:34 +0100 Subject: [PATCH 035/108] API changes --- .../discordplugin/DiscordPlugin.java | 2 +- .../commands/ChannelconCommand.java | 4 ++-- .../discordplugin/mcchat/MCChatCustom.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 17 +++++++++-------- .../discordplugin/mcchat/MCChatUtils.java | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 0bf2b3b..7a76bcf 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin; +import buttondevteam.component.channel.Channel; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; @@ -12,7 +13,6 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index 50ddb9a..c2a84d3 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -1,8 +1,8 @@ package buttondevteam.discordplugin.commands; +import buttondevteam.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.mcchat.MCChatCustom; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; import org.bukkit.Bukkit; @@ -64,7 +64,7 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); return true; } - val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args) || (ch.IDs != null && Arrays.stream(ch.IDs).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); + val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /."); return true; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 74979f8..44fe077 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -1,7 +1,7 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.component.channel.Channel; import buttondevteam.discordplugin.DiscordConnectedPlayer; -import buttondevteam.lib.chat.Channel; import lombok.NonNull; import lombok.val; import sx.blah.discord.handle.obj.IChannel; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 71b9609..c7df658 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -1,5 +1,7 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.component.channel.Channel; +import buttondevteam.component.channel.ChatRoom; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; @@ -10,9 +12,7 @@ import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.chat.Channel; import buttondevteam.lib.chat.ChatMessage; -import buttondevteam.lib.chat.ChatRoom; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; import com.vdurmont.emoji.EmojiParser; @@ -72,14 +72,15 @@ public class MCChatListener implements Listener { e = se.getKey(); time = se.getValue(); - final String authorPlayer = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel().DisplayName) + "] " // + 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(e.getChannel().color.getRed(), - e.getChannel().color.getGreen(), e.getChannel().color.getBlue())); + .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) @@ -332,8 +333,8 @@ public class MCChatListener implements Listener { final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi); Optional ch = Channel.getChannels().stream() .filter(c -> c.ID.equalsIgnoreCase(topcmd) - || (c.IDs != null && c.IDs.length > 0 - && Arrays.stream(c.IDs).anyMatch(id -> id.equalsIgnoreCase(topcmd)))).findAny(); + || (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... @@ -366,7 +367,7 @@ public class MCChatListener implements Listener { } else channel.set(Channel.GlobalChat); dsender.sendMessage("You're now talking in: " - + DPUtils.sanitizeString(channel.get().DisplayName)); + + 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); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 6826f6e..c246ddb 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -1,10 +1,10 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.component.channel.Channel; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.chat.Channel; import io.netty.util.collection.LongObjectHashMap; import lombok.RequiredArgsConstructor; import lombok.experimental.var; -- 2.30.2 From 5c7100bb691f187352e10d38b7b69e8b92fea48e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 20 Jan 2019 00:43:47 +0100 Subject: [PATCH 036/108] Added check for mcchat on shutdown It'll only log fake players out that aren't actually on the server --- src/main/java/buttondevteam/discordplugin/DiscordPlugin.java | 2 +- .../discordplugin/commands/ChannelconCommand.java | 2 +- .../buttondevteam/discordplugin/mcchat/MCChatListener.java | 2 +- .../java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 7a76bcf..557ecd4 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -156,7 +156,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener val chconkeys = chcons.getKeys(false); for (val chconkey : chconkeys) { val chcon = chcons.getConfigurationSection(chconkey); - val mcch = Channel.getChannels().stream().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); + val mcch = Channel.getChannels().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); val ch = dc.getChannelByID(chcon.getLong("chid")); val did = chcon.getLong("did"); val user = dc.fetchUser(did); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index c2a84d3..8d20eb9 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -64,7 +64,7 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); return true; } - val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); + val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(args) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /."); return true; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index c7df658..8542eee 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -331,7 +331,7 @@ public class MCChatListener implements Listener { } else { int spi = cmdlowercased.indexOf(' '); final String topcmd = spi == -1 ? cmdlowercased : cmdlowercased.substring(0, spi); - Optional ch = Channel.getChannels().stream() + 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(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 99c1740..877d415 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -59,7 +59,8 @@ public class MCChatPrivate { public static void logoutAll() { for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) - callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync + if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out + callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync MCChatUtils.ConnectedSenders.clear(); } -- 2.30.2 From 7c15495fab18f81b66129c593a2dd78878075c7d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 28 Jan 2019 23:21:17 +0100 Subject: [PATCH 037/108] Using modules more & calling preprocess event Calling the command preprocess event Added to FunModule (/list, full house) Made whitelisted commands and other stuff configurable Game role module Name change #51 --- .../buttondevteam/discordplugin/DPUtils.java | 5 + .../commands/DiscordCommandBase.java | 121 +++++++------ .../discordplugin/fun/FunModule.java | 101 +++++++++-- .../listeners/CommonListeners.java | 73 +------- .../discordplugin/mcchat/MCChatListener.java | 169 ++++++++---------- .../discordplugin/mcchat/MCListener.java | 1 - .../mcchat/MinecraftChatModule.java | 12 +- .../discordplugin/role/GameRoleModule.java | 62 +++++++ .../{commands => role}/RoleCommand.java | 19 +- src/main/resources/plugin.yml | 16 +- 10 files changed, 327 insertions(+), 252 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java rename src/main/java/buttondevteam/discordplugin/{commands => role}/RoleCommand.java (78%) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 6c079f6..6b649ab 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -5,6 +5,7 @@ import buttondevteam.lib.architecture.IHaveConfig; import org.bukkit.Bukkit; import sx.blah.discord.handle.obj.IChannel; 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; @@ -111,6 +112,10 @@ public final class DPUtils { 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 roleData(IHaveConfig config, String key, long defID) { + return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getRoleByID((long) id), IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer) + } + /** * Mentions the bot channel. Useful for help texts. * diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index 45f175f..947db5b 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -1,59 +1,62 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.mcchat.MCChatCommand; -import buttondevteam.lib.TBMCCoreAPI; -import sx.blah.discord.handle.obj.IMessage; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.stream.Collectors; - -import static buttondevteam.discordplugin.listeners.CommonListeners.debug; - -public abstract class DiscordCommandBase { - public abstract String getCommandName(); - - public abstract boolean run(IMessage message, String args); - - public abstract String[] getHelpText(); - - static final HashMap commands = new HashMap(); - - public static void registerCommands() { - commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? - commands.put("userinfo", new UserinfoCommand()); - commands.put("help", new HelpCommand()); - commands.put("role", new RoleCommand()); - commands.put("mcchat", new MCChatCommand()); - commands.put("channelcon", new ChannelconCommand()); - commands.put("debug", new DebugCommand()); - commands.put("version", new VersionCommand()); - } - - public static void runCommand(String cmd, String args, IMessage message) { - debug("F"); //Not sure if needed - DiscordCommandBase command = commands.get(cmd); - if (command == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Unknown command: " + cmd + " with args: " + args + "\nDo '" - + (message.getChannel().isPrivate() ? "" : message.getClient().getOurUser().mention() + " ") - + "help' for help"); - return; - } - debug("G"); - try { - if (!command.run(message, args)) - DiscordPlugin.sendMessageToChannel(message.getChannel(), Arrays.stream(command.getHelpText()).collect(Collectors.joining("\n"))); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while executing command " + cmd + "!", e); - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "An internal error occured while executing this command. For more technical details see the server-issues channel on the dev Discord."); - } - debug("H"); - } - - protected String[] splitargs(String args) { - return args.split("\\s+"); - } -} +package buttondevteam.discordplugin.commands; + +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.mcchat.MCChatCommand; +import buttondevteam.lib.TBMCCoreAPI; +import sx.blah.discord.handle.obj.IMessage; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.stream.Collectors; + +import static buttondevteam.discordplugin.listeners.CommonListeners.debug; + +public abstract class DiscordCommandBase { + public abstract String getCommandName(); + + public abstract boolean run(IMessage message, String args); + + public abstract String[] getHelpText(); + + static final HashMap commands = new HashMap(); + + public static void registerCommands() { + commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? + commands.put("userinfo", new UserinfoCommand()); + commands.put("help", new HelpCommand()); + commands.put("mcchat", new MCChatCommand()); + commands.put("channelcon", new ChannelconCommand()); + commands.put("debug", new DebugCommand()); + commands.put("version", new VersionCommand()); + } + + public static void runCommand(String cmd, String args, IMessage message) { + debug("F"); //Not sure if needed + DiscordCommandBase command = commands.get(cmd); + if (command == null) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "Unknown command: " + cmd + " with args: " + args + "\nDo '" + + (message.getChannel().isPrivate() ? "" : message.getClient().getOurUser().mention() + " ") + + "help' for help"); + return; + } + debug("G"); + try { + if (!command.run(message, args)) + DiscordPlugin.sendMessageToChannel(message.getChannel(), Arrays.stream(command.getHelpText()).collect(Collectors.joining("\n"))); + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occured while executing command " + cmd + "!", e); + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "An internal error occured while executing this command. For more technical details see the server-issues channel on the dev Discord."); + } + debug("H"); + } + + protected String[] splitargs(String args) { + return args.split("\\s+"); + } + + public static void registerCommand(String name, DiscordCommandBase dcb) { + commands.put(name, dcb); + } +} diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 34d95e7..9565a53 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -5,14 +5,26 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; +import com.google.common.collect.Lists; +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.IMessage; +import sx.blah.discord.handle.obj.IRole; +import sx.blah.discord.handle.obj.StatusType; +import sx.blah.discord.util.EmbedBuilder; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.Calendar; import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; -public class FunModule extends Component { +public class FunModule extends Component implements Listener { private static FunModule mod; private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali @@ -35,9 +47,8 @@ public class FunModule extends Component { return getConfig().getData("serverReady", true); } - private ConfigData> serverReadyAnswers() { - return getConfig().getData("serverReadyAnswers", Arrays.asList(serverReadyStrings), - data -> (List) data, data -> data); //TODO: Test + 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", @@ -46,41 +57,93 @@ public class FunModule extends Component { "Vhen vill ze server be open?"}; private static final Random serverReadyRandom = new Random(); - private static final ArrayList usableServerReadyStrings = new ArrayList(serverReadyStrings.length) { - private static final long serialVersionUID = 2213771460909848770L; + private static final ArrayList usableServerReadyStrings = new ArrayList<>(0); - { - createUsableServerReadyStrings(this); - } - }; - - private static void createUsableServerReadyStrings(ArrayList list) { - for (short i = 0; i < serverReadyStrings.length; i++) - list.add(i); + private void createUsableServerReadyStrings() { + IntStream.range(0, serverReadyAnswers().get().size()) + .forEach(i -> FunModule.usableServerReadyStrings.add((short) i)); } @Override protected void enable() { mod = this; + registerListener(this); } @Override protected void disable() { + lastlist = lastlistp = ListC = 0; } + private static short lastlist = 0; + private static short lastlistp = 0; + + private static short ListC = 0; + public static boolean executeMemes(IMessage message) { - if (!ComponentManager.isEnabled(FunModule.class)) return false; + val fm = ComponentManager.getIfEnabled(FunModule.class); + if (fm == null) return false; + String msglowercased = message.getContent().toLowerCase(); + lastlist++; + if (lastlist > 5) { + ListC = 0; + lastlist = 0; + } + if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already + { + message.reply("Stop it. You know the answer."); + lastlist = 0; + lastlistp = (short) Bukkit.getOnlinePlayers().size(); + return true; //Handled + } + lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle if (mod.serverReady().get()) { if (!TBMCCoreAPI.IsTestServer() - && Arrays.stream(serverReadyQuestions).anyMatch(s -> message.getContent().toLowerCase().contains(s))) { + && Arrays.stream(serverReadyQuestions).anyMatch(msglowercased::contains)) { int next; if (usableServerReadyStrings.size() == 0) - createUsableServerReadyStrings(usableServerReadyStrings); + fm.createUsableServerReadyStrings(); next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); DiscordPlugin.sendMessageToChannel(message.getChannel(), serverReadyStrings[next]); - return true; + return false; //Still process it as a command/mcchat if needed } } return false; } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + ListC = 0; + } + + private ConfigData fullHouseDevRole() { + return getConfig().getDataPrimDef("fullHouseDevRole", "Developer", name -> { + val list = DiscordPlugin.devServer.getRolesByName((String) name); + return list.size() > 0 ? list.get(0) : null; + }, IRole::getName); + } + + private static long lasttime = 0; + + public static void handleFullHouse(PresenceUpdateEvent event) { + val fm = ComponentManager.getIfEnabled(FunModule.class); + if (fm == null) return; + val devrole = fm.fullHouseDevRole().get(); + if (devrole == null) return; + if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) + && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) + && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() + .anyMatch(r -> r.getLongID() == devrole.getLongID()) + && DiscordPlugin.devServer.getUsersByRole(devrole).stream() + .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) + && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) + && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { + DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", + new EmbedBuilder() + .withImage( + "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") + .build()); + lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); + } + } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index b372750..9b60fc3 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -2,42 +2,20 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.role.GameRoleModule; import buttondevteam.lib.architecture.Component; import lombok.val; -import org.bukkit.Bukkit; 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; -import sx.blah.discord.handle.obj.StatusType; -import sx.blah.discord.util.EmbedBuilder; - -import java.util.Calendar; -import java.util.concurrent.TimeUnit; public class CommonListeners { - /*private static ArrayList dcListeners=new ArrayList<>(); - - public static void registerDiscordListener(DiscordListener listener) { - //Step 1: Get all events that are handled by us - //Step 2: Find methods that handle these - //...or just simply call the methods in the right order - } - - private static void callDiscordEvent(Event event) { - String name=event.getClass().getSimpleName(); - name=Character.toLowerCase(name.charAt(0))+name.substring(1); - for (Object listener : dcListeners) { - listener.getClass().getMethods(name, AsyncDiscordEvent.class); - } - }*/ - - private static long lasttime = 0; - /* MentionEvent: - CommandListener (starts with mention, only 'channelcon' and not in #bot) @@ -55,6 +33,8 @@ public class CommonListeners { return; if (event.getMessage().getAuthor().isBot()) return; + if (FunModule.executeMemes(event.getMessage())) + return; boolean handled = false; if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat || event.getMessage().getContent().contains("channelcon")) //Only 'channelcon' is allowed in other channels @@ -71,48 +51,11 @@ public class CommonListeners { public void handle(PresenceUpdateEvent event) { if (DiscordPlugin.SafeMode) return; - val devrole = DiscordPlugin.devServer.getRolesByName("Developer").get(0); - if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) - && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() - .anyMatch(r -> r.getLongID() == devrole.getLongID()) - && DiscordPlugin.devServer.getUsersByRole(devrole).stream() - .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) - && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) - && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", - new EmbedBuilder() - .withImage( - "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") - .build()); - lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime()); - } + FunModule.handleFullHouse(event); } - }, (IListener) event -> { - Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - if (event.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(event.getRole())) - return; //Deleted or not a game role - DiscordPlugin.GameRoles.add(event.getRole().getName()); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); - }, 100); - }, (IListener) event -> { - if (DiscordPlugin.GameRoles.remove(event.getRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getRole().getName() + " as a game role."); - }, (IListener) event -> { //Role update event - if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { - if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); - } else { - if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) - return; - boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role - DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color - if (removed) - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); - else - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); - } - }}; + }, (IListener) GameRoleModule::handleRoleEvent, // + (IListener) GameRoleModule::handleRoleEvent, // + (IListener) 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 8542eee..bd9a6d1 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -11,6 +11,7 @@ import buttondevteam.discordplugin.listeners.CommandListener; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; +import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.TBMCChatAPI; @@ -47,8 +48,13 @@ public class MCChatListener implements Listener { private LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); private Runnable sendrunnable; private static Thread sendthread; + private final MinecraftChatModule module; - @EventHandler // Minecraft + public MCChatListener(MinecraftChatModule minecraftChatModule) { + module = minecraftChatModule; + } + + @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; @@ -175,12 +181,6 @@ public class MCChatListener implements Listener { } } - private static final String[] UnconnectedCmds = new String[]{"list", "u", "shrug", "tableflip", "unflip", "mwiki", - "yeehaw", "lenny", "rp", "plugins"}; - - private static short lastlist = 0; - private static short lastlistp = 0; - // ......................DiscordSender....DiscordConnectedPlayer.DiscordPlayerSender // Offline public chat......x............................................ // Online public chat.......x...........................................x @@ -192,8 +192,6 @@ public class MCChatListener implements Listener { // If online and disabling private chat, don't logout // The maps may not contain the senders for UnconnectedSenders - public static short ListC = 0; - /** * Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode. * @@ -218,7 +216,6 @@ public class MCChatListener implements Listener { MCChatCustom.lastmsgCustom.clear(); MCChatUtils.lastmsgfromd.clear(); MCChatUtils.ConnectedSenders.clear(); - lastlist = lastlistp = ListC = 0; MCChatUtils.UnconnectedSenders.clear(); recthread = sendthread = null; } catch (InterruptedException e) { @@ -249,7 +246,6 @@ public class MCChatListener implements Listener { if (CommandListener.runCommand(ev.getMessage(), true)) return true; //Allow running commands in chat channels MCChatUtils.resetLastMessage(ev.getChannel()); - lastlist++; recevents.add(ev); if (rectask != null) return true; @@ -300,87 +296,80 @@ public class MCChatListener implements Listener { boolean react = false; if (dmessage.startsWith("/")) { // Ingame command - DPUtils.perform(() -> { - if (!event.getMessage().isDeleted() && !event.getChannel().isPrivate()) - event.getMessage().delete(); - }); + 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 && Arrays.stream(UnconnectedCmds) - .noneMatch(s -> cmdlowercased.equals(s) || cmdlowercased.startsWith(s + " "))) { - // Command not whitelisted - dsender.sendMessage("Sorry, you can only access these commands:\n" - + Arrays.stream(UnconnectedCmds).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; - } - if (lastlist > 5) { - ListC = 0; - lastlist = 0; - } - if (cmdlowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already - { - dsender.sendMessage("Stop it. You know the answer."); - lastlist = 0; - } else { - 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; - } - } - } - } - lastlistp = (short) Bukkit.getOnlinePlayers().size(); + 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()) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 2c5fdb0..35abeac 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -60,7 +60,6 @@ class MCListener implements Listener { } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); - MCChatListener.ListC = 0; ChromaBot.getInstance().updatePlayerList(); }); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 9af7a5e..46b1c61 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -3,17 +3,27 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import com.google.common.collect.Lists; import lombok.Getter; +import java.util.ArrayList; + public class MinecraftChatModule extends Component { private @Getter MCChatListener listener; public MCChatListener getListener() { //It doesn't want to generate return listener; } + + public ConfigData> whitelistedCommands() { + return getConfig().getData("whitelistedCommands", () -> Lists.newArrayList("list", "u", "shrug", "tableflip", "unflip", "mwiki", + "yeehaw", "lenny", "rp", "plugins")); + } + @Override protected void enable() { - listener = new MCChatListener(); + listener = new MCChatListener(this); DiscordPlugin.dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin()); diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java new file mode 100644 index 0000000..0587cfc --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -0,0 +1,62 @@ +package buttondevteam.discordplugin.role; + +import buttondevteam.core.ComponentManager; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +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; + +public class GameRoleModule extends Component { + @Override + protected void enable() { + DiscordCommandBase.registerCommand("role", new RoleCommand()); + } + + @Override + protected void disable() { + + } + + private ConfigData logChannel() { + return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L); + } + + public static void handleRoleEvent(RoleEvent roleEvent) { + val grm = ComponentManager.getIfEnabled(GameRoleModule.class); + if (grm == null) return; + if (roleEvent instanceof RoleCreateEvent) { + Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { + if (roleEvent.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(roleEvent.getRole())) + return; //Deleted or not a game role + DiscordPlugin.GameRoles.add(roleEvent.getRole().getName()); + DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + }, 100); + } else if (roleEvent instanceof RoleDeleteEvent) { + if (DiscordPlugin.GameRoles.remove(roleEvent.getRole().getName())) + DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + roleEvent.getRole().getName() + " as a game role."); + } else if (roleEvent instanceof RoleUpdateEvent) { + val event = (RoleUpdateEvent) roleEvent; + if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { + if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) + DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + } else { + if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + return; + boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role + DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color + if (removed) + DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + else + DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + } + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java similarity index 78% rename from src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java rename to src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index a7f2bf5..1d80e51 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -1,7 +1,8 @@ -package buttondevteam.discordplugin.commands; +package buttondevteam.discordplugin.role; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.lib.TBMCCoreAPI; import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IRole; @@ -9,7 +10,7 @@ import sx.blah.discord.handle.obj.IRole; import java.util.List; import java.util.stream.Collectors; -public class RoleCommand extends DiscordCommandBase { +public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's parser @Override public String getCommandName() { @@ -22,23 +23,23 @@ public class RoleCommand extends DiscordCommandBase { return false; String[] argsa = splitargs(args); if (argsa[0].equalsIgnoreCase("add")) { - final IRole role = checkAndGetRole(message, argsa, "This command adds a game role to your account."); + final IRole role = checkAndGetRole(message, argsa, "This command adds a role to your account."); if (role == null) return true; try { DPUtils.perform(() -> message.getAuthor().addRole(role)); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added game role."); + DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added role."); } catch (Exception e) { TBMCCoreAPI.SendException("Error while adding role!", e); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while adding the role."); } } else if (argsa[0].equalsIgnoreCase("remove")) { - final IRole role = checkAndGetRole(message, argsa, "This command removes a game role from your account."); + final IRole role = checkAndGetRole(message, argsa, "This command removes a role from your account."); if (role == null) return true; try { DPUtils.perform(() -> message.getAuthor().removeRole(role)); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed game role."); + DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed role."); } catch (Exception e) { TBMCCoreAPI.SendException("Error while removing role!", e); DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while removing the role."); @@ -51,7 +52,7 @@ public class RoleCommand extends DiscordCommandBase { private void listRoles(IMessage message) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "List of game roles:\n" + DiscordPlugin.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); + "List of roles:\n" + DiscordPlugin.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); } private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) { @@ -63,7 +64,7 @@ public class RoleCommand extends DiscordCommandBase { for (int i = 2; i < argsa.length; i++) rolename.append(" ").append(argsa[i]); if (!DiscordPlugin.GameRoles.contains(rolename.toString())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "That game role cannot be found."); + DiscordPlugin.sendMessageToChannel(message.getChannel(), "That role cannot be found."); listRoles(message); return null; } @@ -85,7 +86,7 @@ public class RoleCommand extends DiscordCommandBase { @Override public String[] getHelpText() { return new String[]{ // - "Add or remove game roles from yourself.", // + "Add or remove roles from yourself.", // "Usage: " + DiscordPlugin.getPrefix() + "role add|remove or role list", // }; } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 1c74854..6507c5b 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,8 @@ -name: DiscordPlugin -main: buttondevteam.discordplugin.DiscordPlugin -version: 1.0 -author: NorbiPeti -depend: [ButtonCore] -commands: - discord: -website: 'https://github.com/TBMCPlugins/DiscordPlugin' +name: Thorpe-Discord +main: buttondevteam.discordplugin.DiscordPlugin +version: 1.0 +author: NorbiPeti +depend: [ThorpeCore] +commands: + discord: +website: 'https://github.com/TBMCPlugins/DiscordPlugin' -- 2.30.2 From 2659170c4dd7757765e9ca38eb0f841c2e4adc82 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 01:09:18 +0100 Subject: [PATCH 038/108] Modules, fixes, pins Keeping 40 pinned messages instead of 10 GameRoleModule fixes AnnouncerModule Other fixes #51 --- .../discordplugin/AnnouncerModule.java | 135 +++++++++++ .../discordplugin/DiscordPlugin.java | 153 +----------- .../commands/ChannelconCommand.java | 3 +- .../discordplugin/listeners/MCListener.java | 219 ++++++++++-------- .../discordplugin/mcchat/MCChatCustom.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 10 +- .../discordplugin/mcchat/MCChatUtils.java | 19 +- .../discordplugin/mcchat/MCListener.java | 10 +- .../mcchat/MinecraftChatModule.java | 49 +++- .../discordplugin/role/GameRoleModule.java | 35 ++- .../discordplugin/role/RoleCommand.java | 12 +- 11 files changed, 365 insertions(+), 282 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/AnnouncerModule.java diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java new file mode 100644 index 0000000..8821b94 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java @@ -0,0 +1,135 @@ +package buttondevteam.discordplugin; + +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import buttondevteam.lib.player.ChromaGamerBase; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.val; +import sx.blah.discord.handle.obj.IChannel; +import sx.blah.discord.handle.obj.IMessage; + +import java.util.List; + +public class AnnouncerModule extends Component { + public ConfigData channel() { + return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); + } + + public ConfigData modChannel() { + return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L); + } + + /** + * Set to 0 or >50 to disable + */ + public ConfigData keepPinned() { + return getConfig().getData("keepPinned", (short) 40, i -> ((Integer) i).shortValue(), Short::intValue); + } + + private ConfigData lastannouncementtime() { + return getConfig().getData("lastAnnouncementTime", 0L); + } + + private ConfigData lastseentime() { + return getConfig().getData("lastSeenTime", 0L); + } + + private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; + private static boolean stop = false; + + @Override + protected void enable() { + 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) { + } + }); + if (lastannouncementtime().get() == 0) //Load old data + lastannouncementtime().set(getConfig().getConfig().getRoot().getLong("lastannouncementtime")); + if (lastseentime().get() == 0) + lastseentime().set(getConfig().getConfig().getLong("lastseentime")); + new Thread(this::AnnouncementGetterThreadMethod).start(); + } + + @Override + protected void disable() { + stop = true; + } + + private void AnnouncementGetterThreadMethod() { + while (!stop) { + try { + if (!isEnabled()) { + Thread.sleep(10000); + continue; + } + String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); + JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() + .get("children").getAsJsonArray(); + StringBuilder msgsb = new StringBuilder(); + StringBuilder modmsgsb = new StringBuilder(); + 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(); + String author = data.get("author").getAsString(); + JsonElement distinguishedjson = data.get("distinguished"); + String distinguished; + if (distinguishedjson.isJsonNull()) + distinguished = null; + else + 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()) { + do { + val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit"); + if (reddituserclass == null) + break; + val user = ChromaGamerBase.getUser(author, reddituserclass); + String id = user.getConnectedID(DiscordPlayer.class); + if (id != null) + author = "<@" + id + ">"; + } while (false); + if (!author.startsWith("<")) + author = "/u/" + author; + (distinguished != null && distinguished.equals("moderator") ? modmsgsb : msgsb) + .append("A new post was submitted to the subreddit by ").append(author).append("\n") + .append(permalink).append("\n"); + lastanntime = date; + } + } + if (msgsb.length() > 0) + channel().get().pin(DiscordPlugin.sendMessageToChannelWait(channel().get(), msgsb.toString())); + if (modmsgsb.length() > 0) + DiscordPlugin.sendMessageToChannel(modChannel().get(), modmsgsb.toString()); + 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(); + } + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 557ecd4..6431712 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,14 +1,16 @@ package buttondevteam.discordplugin; -import buttondevteam.component.channel.Channel; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; -import buttondevteam.discordplugin.mcchat.*; +import buttondevteam.discordplugin.mcchat.MCChatPrivate; +import buttondevteam.discordplugin.mcchat.MCChatUtils; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.discordplugin.mccommands.ResetMCCommand; +import buttondevteam.discordplugin.role.GameRoleModule; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; @@ -16,10 +18,6 @@ import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import lombok.val; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; @@ -39,22 +37,17 @@ import sx.blah.discord.util.RequestBuffer; import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; public class DiscordPlugin extends ButtonPlugin implements IListener { - private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; - private static boolean stop = false; public static IDiscordClient dc; public static DiscordPlugin plugin; public static boolean SafeMode = true; - public static List GameRoles; - public ConfigData Prefix() { + public ConfigData Prefix() { return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); } @@ -73,12 +66,9 @@ public class DiscordPlugin extends ButtonPlugin implements IListener @Override public void pluginEnable() { - stop = false; //If not the first time try { Bukkit.getLogger().info("Initializing DiscordPlugin..."); plugin = this; - lastannouncementtime = getConfig().getLong("lastannouncementtime"); - lastseentime = getConfig().getLong("lastseentime"); ClientBuilder cb = new ClientBuilder(); cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); dc = cb.login(); @@ -148,31 +138,10 @@ public class DiscordPlugin extends ButtonPlugin implements IListener if (task != null) task.cancel(); if (!sent) { - new ChromaBot(this).updatePlayerList(); - GameRoles = mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); - - val chcons = getConfig().getConfigurationSection("chcons"); - if (chcons != null) { - val chconkeys = chcons.getKeys(false); - for (val chconkey : chconkeys) { - val chcon = chcons.getConfigurationSection(chconkey); - val mcch = Channel.getChannels().filter(ch -> ch.ID.equals(chcon.getString("mcchid"))).findAny(); - val ch = dc.getChannelByID(chcon.getLong("chid")); - val did = chcon.getLong("did"); - val user = dc.fetchUser(did); - val groupid = chcon.getString("groupid"); - val toggles = chcon.getInt("toggles"); - if (!mcch.isPresent() || ch == null || user == null || groupid == null) - continue; - Bukkit.getScheduler().runTask(this, () -> { //<-- 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); - }); - } - } + new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled DiscordCommandBase.registerCommands(); - if (ResetMCCommand.resetting) + if (ResetMCCommand.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)) { @@ -190,16 +159,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener getConfig().set("serverup", true); saveConfig(); - DPUtils.performNoWait(() -> { - try { - List msgs = genchannel.getPinnedMessages(); - for (int i = msgs.size() - 1; i >= 10; i--) { // Unpin all pinned messages except the newest 10 - genchannel.unpin(msgs.get(i)); - Thread.sleep(10); - } - } catch (InterruptedException ignore) { - } - }); sent = true; if (TBMCCoreAPI.IsTestServer() && !dc.getOurUser().getName().toLowerCase().contains("test")) { TBMCCoreAPI.SendException( @@ -228,52 +187,29 @@ public class DiscordPlugin extends ButtonPlugin implements IListener Component.registerComponent(this, new GeneralEventBroadcasterModule()); Component.registerComponent(this, new MinecraftChatModule()); Component.registerComponent(this, new ExceptionListenerModule()); + Component.registerComponent(this, new GameRoleModule()); + Component.registerComponent(this, new AnnouncerModule()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof DiscordSenderBase ? ((DiscordSenderBase) sender).getChromaUser() : null)); - new Thread(this::AnnouncementGetterThreadMethod).start(); setupProviders(); } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while enabling DiscordPlugin!", e); } } - public boolean isGameRole(IRole r) { - if (r.getGuild().getLongID() != mainServer.getLongID()) - return false; //Only allow on the main server - val rc = new Color(149, 165, 166, 0); - return r.getColor().equals(rc) - && r.getPosition() < mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role - } - - /** + /** * Always true, except when running "stop" from console */ public static boolean Restart; @Override public void pluginDisable() { - stop = true; MCChatPrivate.logoutAll(); - getConfig().set("lastannouncementtime", lastannouncementtime); - getConfig().set("lastseentime", lastseentime); getConfig().set("serverup", false); - val chcons = MCChatCustom.getCustomChats(); - val chconsc = getConfig().createSection("chcons"); - for (val chcon : chcons) { - val chconc = chconsc.createSection(chcon.channel.getStringID()); - chconc.set("mcchid", chcon.mcchannel.ID); - chconc.set("chid", chcon.channel.getLongID()); - chconc.set("did", chcon.user.getLongID()); - chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); - chconc.set("mcname", chcon.dcp.getName()); - chconc.set("groupid", chcon.groupID); - chconc.set("toggles", chcon.toggles); - } - saveConfig(); EmbedObject embed; if (ResetMCCommand.resetting) @@ -301,7 +237,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener ChromaBot.getInstance().updatePlayerList(); try { SafeMode = true; // Stop interacting with Discord - MCChatListener.stop(true); ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); @@ -312,76 +247,8 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } } - private long lastannouncementtime = 0; - private long lastseentime = 0; public static final ReactionEmoji DELIVERED_REACTION = ReactionEmoji.of("✅"); - private void AnnouncementGetterThreadMethod() { - while (!stop) { - try { - if (SafeMode) { - Thread.sleep(10000); - continue; - } - String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); - JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() - .get("children").getAsJsonArray(); - StringBuilder msgsb = new StringBuilder(); - StringBuilder modmsgsb = new StringBuilder(); - long lastanntime = lastannouncementtime; - for (int i = json.size() - 1; i >= 0; i--) { - JsonObject item = json.get(i).getAsJsonObject(); - final JsonObject data = item.get("data").getAsJsonObject(); - String author = data.get("author").getAsString(); - JsonElement distinguishedjson = data.get("distinguished"); - String distinguished; - if (distinguishedjson.isJsonNull()) - distinguished = null; - else - distinguished = distinguishedjson.getAsString(); - String permalink = "https://www.reddit.com" + data.get("permalink").getAsString(); - long date = data.get("created_utc").getAsLong(); - if (date > lastseentime) - lastseentime = date; - else if (date > lastannouncementtime) { - do { - val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit"); - if (reddituserclass == null) - break; - val user = ChromaGamerBase.getUser(author, reddituserclass); - String id = user.getConnectedID(DiscordPlayer.class); - if (id != null) - author = "<@" + id + ">"; - } while (false); - if (!author.startsWith("<")) - author = "/u/" + author; - (distinguished != null && distinguished.equals("moderator") ? modmsgsb : msgsb) - .append("A new post was submitted to the subreddit by ").append(author).append("\n") - .append(permalink).append("\n"); - lastanntime = date; - } - } - if (msgsb.length() > 0) - genchannel.pin(sendMessageToChannelWait(genchannel, msgsb.toString())); - if (modmsgsb.length() > 0) - sendMessageToChannel(annchannel, modmsgsb.toString()); - if (lastannouncementtime != lastanntime) { - lastannouncementtime = lastanntime; // If sending succeeded - getConfig().set("lastannouncementtime", lastannouncementtime); - getConfig().set("lastseentime", lastseentime); - saveConfig(); - } - } catch (Exception e) { - e.printStackTrace(); - } - try { - Thread.sleep(10000); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - public static void sendMessageToChannel(IChannel channel, String message) { sendMessageToChannel(channel, message, null); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index 8d20eb9..df9398a 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin.commands; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.mcchat.MCChatCustom; import buttondevteam.lib.player.TBMCPlayer; @@ -38,6 +38,7 @@ public class ChannelconCommand extends DiscordCommandBase { } if (args.toLowerCase().startsWith("toggle")) { val cc = MCChatCustom.getCustomChat(message.getChannel()); + assert cc != null; //It's not null Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")); String[] argsa = args.split(" "); if (argsa.length < 2) { diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index a39d5fc..2f99b56 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -1,103 +1,116 @@ -package buttondevteam.discordplugin.listeners; - -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.event.Event; -import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.plugin.AuthorNagException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredListener; -import sx.blah.discord.handle.obj.IUser; - -import java.util.Arrays; -import java.util.logging.Level; - -public class MCListener implements Listener { - @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; - IUser 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 onServerCommand(ServerCommandEvent e) { - DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped - } - - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises", "JourneyMapServer"}; //TODO: Make configurable - - public static void callEventExcludingSome(Event event) { - callEventExcluding(event, false, EXCLUDED_PLUGINS); - } - - /** - * Calls an event with the given details. - *

- * This method only synchronizes when the event is not asynchronous. - * - * @param event Event details - * @param only Flips the operation and includes the listed plugins - * @param plugins The plugins to exclude. Not case sensitive. - */ - public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit - if (event.isAsynchronous()) { - if (Thread.holdsLock(Bukkit.getPluginManager())) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); - } - if (Bukkit.getServer().isPrimaryThread()) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from primary server thread."); - } - fireEventExcluding(event, only, plugins); - } else { - synchronized (Bukkit.getPluginManager()) { - fireEventExcluding(event, only, plugins); - } - } - } - - private static void fireEventExcluding(Event event, boolean only, String... plugins) { - HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - val server = Bukkit.getServer(); - - for (RegisteredListener registration : listeners) { - if (!registration.getPlugin().isEnabled() - || Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName()))) - continue; // Modified to exclude plugins - - try { - registration.callEvent(event); - } catch (AuthorNagException ex) { - Plugin plugin = registration.getPlugin(); - - if (plugin.isNaggable()) { - plugin.setNaggable(false); - - server.getLogger().log(Level.SEVERE, - String.format("Nag author(s): '%s' of '%s' about the following: %s", - plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), - ex.getMessage())); - } - } catch (Throwable ex) { - server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " - + registration.getPlugin().getDescription().getFullName(), ex); - } - } - } -} +package buttondevteam.discordplugin.listeners; + +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; +import buttondevteam.lib.player.TBMCPlayerJoinEvent; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.plugin.AuthorNagException; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredListener; +import sx.blah.discord.handle.obj.IUser; + +import java.util.Arrays; +import java.util.logging.Level; + +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 + .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"); + 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; + IUser 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 onServerCommand(ServerCommandEvent e) { + DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped + } + + private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises", "JourneyMapServer"}; //TODO: Make configurable + + public static void callEventExcludingSome(Event event) { + callEventExcluding(event, false, EXCLUDED_PLUGINS); + } + + /** + * Calls an event with the given details. + *

+ * This method only synchronizes when the event is not asynchronous. + * + * @param event Event details + * @param only Flips the operation and includes the listed plugins + * @param plugins The plugins to exclude. Not case sensitive. + */ + public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit + if (event.isAsynchronous()) { + if (Thread.holdsLock(Bukkit.getPluginManager())) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); + } + if (Bukkit.getServer().isPrimaryThread()) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from primary server thread."); + } + fireEventExcluding(event, only, plugins); + } else { + synchronized (Bukkit.getPluginManager()) { + fireEventExcluding(event, only, plugins); + } + } + } + + private static void fireEventExcluding(Event event, boolean only, String... plugins) { + HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + val server = Bukkit.getServer(); + + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled() + || Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName()))) + continue; // Modified to exclude plugins + + try { + registration.callEvent(event); + } catch (AuthorNagException ex) { + Plugin plugin = registration.getPlugin(); + + if (plugin.isNaggable()) { + plugin.setNaggable(false); + + server.getLogger().log(Level.SEVERE, + String.format("Nag author(s): '%s' of '%s' about the following: %s", + plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), + ex.getMessage())); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + + registration.getPlugin().getDescription().getFullName(), ex); + } + } + } +} diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 44fe077..fe0769a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -1,6 +1,6 @@ package buttondevteam.discordplugin.mcchat; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.DiscordConnectedPlayer; import lombok.NonNull; import lombok.val; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index bd9a6d1..6c90870 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -1,8 +1,8 @@ package buttondevteam.discordplugin.mcchat; -import buttondevteam.component.channel.Channel; -import buttondevteam.component.channel.ChatRoom; import buttondevteam.core.ComponentManager; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.ChatRoom; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.DiscordSender; @@ -128,9 +128,9 @@ public class MCChatListener implements Listener { || ((DiscordSenderBase) e.getSender()).getChannel().getLongID() != ch.getLongID(); if (e.getChannel().isGlobal() - && (e.isFromCommand() || isdifferentchannel.test(DiscordPlugin.chatchannel))) + && (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get()))) doit.accept(MCChatUtils.lastmsgdata == null - ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(DiscordPlugin.chatchannel, null) + ? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null) : MCChatUtils.lastmsgdata); for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) { @@ -234,7 +234,7 @@ public class MCChatListener implements Listener { return false; val author = ev.getMessage().getAuthor(); final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getChannel()); - if (ev.getMessage().getChannel().getLongID() != DiscordPlugin.chatchannel.getLongID() + if (ev.getMessage().getChannel().getLongID() != module.chatChannel().get().getLongID() && !(ev.getMessage().getChannel().isPrivate() && MCChatPrivate.isMinecraftChatEnabled(author.getStringID())) && !hasCustomChat) return false; //Chat isn't enabled on this channel diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index c246ddb..cd45dbe 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -1,7 +1,7 @@ package buttondevteam.discordplugin.mcchat; -import buttondevteam.component.channel.Channel; import buttondevteam.core.ComponentManager; +import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCSystemChatEvent; @@ -34,6 +34,7 @@ public class MCChatUtils { 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; public static void updatePlayerList() { if (notEnabled()) return; @@ -45,7 +46,13 @@ public class MCChatUtils { } private static boolean notEnabled() { - return !ComponentManager.isEnabled(MinecraftChatModule.class); + return getModule() == null; + } + + private static MinecraftChatModule getModule() { + if (module == null) module = ComponentManager.getIfEnabled(MinecraftChatModule.class); + else if (!module.isEnabled()) module = null; //Reset if disabled + return module; } private static void updatePL(LastMsgData lmd) { @@ -95,7 +102,7 @@ public class MCChatUtils { public static void forAllMCChat(Consumer action) { if (notEnabled()) return; - action.accept(DiscordPlugin.chatchannel); + action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) action.accept(data.channel); // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat @@ -160,7 +167,7 @@ public class MCChatUtils { public static void forAllowedMCChat(Consumer action, TBMCSystemChatEvent event) { if (notEnabled()) return; if (event.getChannel().isGlobal()) - action.accept(DiscordPlugin.chatchannel); + action.accept(module.chatChannel().get()); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) if (event.shouldSendTo(getSender(data.channel, data.user))) action.accept(data.channel); @@ -192,8 +199,8 @@ public class MCChatUtils { */ public static void resetLastMessage(IChannel channel) { if (notEnabled()) return; - if (channel.getLongID() == DiscordPlugin.chatchannel.getLongID()) { - (lastmsgdata == null ? lastmsgdata = new LastMsgData(DiscordPlugin.chatchannel, null) + if (channel.getLongID() == module.chatChannel().get().getLongID()) { + (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 diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 35abeac..ca34d8c 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -1,7 +1,6 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.*; -import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.player.*; @@ -51,13 +50,6 @@ class MCListener implements Listener { MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel } - if (ConnectCommand.WaitingToConnect.containsKey(e.GetPlayer().PlayerName().get())) { - IUser user = DiscordPlugin.dc - .getUserByID(Long.parseLong(ConnectCommand.WaitingToConnect.get(e.GetPlayer().PlayerName().get()))); - p.sendMessage("§bTo connect with the Discord account @" + user.getName() + "#" + user.getDiscriminator() - + " do /discord accept"); - p.sendMessage("§bIf it wasn't you, do /discord decline"); - } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); ChromaBot.getInstance().updatePlayerList(); @@ -106,7 +98,7 @@ class MCListener implements Listener { public void onPlayerMute(MuteStatusChangeEvent e) { try { DPUtils.performNoWait(() -> { - final IRole role = DiscordPlugin.dc.getRoleByID(164090010461667328L); + final IRole role = DiscordPlugin.dc.getRoleByID(164090010461667328L); //TODO: Config final CommandSource source = e.getAffected().getSource(); if (!source.isPlayer()) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 46b1c61..55d68d6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -1,13 +1,20 @@ package buttondevteam.discordplugin.mcchat; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import com.google.common.collect.Lists; import lombok.Getter; +import lombok.val; +import org.bukkit.Bukkit; +import sx.blah.discord.handle.obj.IChannel; import java.util.ArrayList; +import java.util.UUID; public class MinecraftChatModule extends Component { private @Getter MCChatListener listener; @@ -21,16 +28,54 @@ public class MinecraftChatModule extends Component { "yeehaw", "lenny", "rp", "plugins")); } + public ConfigData chatChannel() { + return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L); + } + @Override protected void enable() { listener = new MCChatListener(this); DiscordPlugin.dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); - TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin()); + TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled + + val chcons = getConfig().getConfig().getConfigurationSection("chcons"); + if (chcons == null) //Fallback to old place + getConfig().getConfig().getRoot().getConfigurationSection("chcons"); + if (chcons != null) { + val chconkeys = chcons.getKeys(false); + 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 did = chcon.getLong("did"); + val user = DiscordPlugin.dc.fetchUser(did); + val groupid = chcon.getString("groupid"); + val toggles = chcon.getInt("toggles"); + 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); + }); + } + } } @Override protected void disable() { - //These get undone if restarting/resetting - it will ignore events if disabled + val chcons = MCChatCustom.getCustomChats(); + val chconsc = getConfig().getConfig().createSection("chcons"); + for (val chcon : chcons) { + val chconc = chconsc.createSection(chcon.channel.getStringID()); + chconc.set("mcchid", chcon.mcchannel.ID); + chconc.set("chid", chcon.channel.getLongID()); + chconc.set("did", chcon.user.getLongID()); + chconc.set("mcuid", chcon.dcp.getUniqueId().toString()); + chconc.set("mcname", chcon.dcp.getName()); + chconc.set("groupid", chcon.groupID); + chconc.set("toggles", chcon.toggles); + } + MCChatListener.stop(true); } //TODO: Use ComponentManager.isEnabled() at other places too, instead of SafeMode } diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 0587cfc..7bf3d2b 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -13,11 +13,19 @@ 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; +import java.util.stream.Collectors; public class GameRoleModule extends Component { + public List GameRoles; + @Override protected void enable() { - DiscordCommandBase.registerCommand("role", new RoleCommand()); + DiscordCommandBase.registerCommand("role", new RoleCommand(this)); + GameRoles = DiscordPlugin.mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); } @Override @@ -32,26 +40,27 @@ public class GameRoleModule extends Component { public static void handleRoleEvent(RoleEvent roleEvent) { val grm = ComponentManager.getIfEnabled(GameRoleModule.class); if (grm == null) return; + val GameRoles = grm.GameRoles; if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { - if (roleEvent.getRole().isDeleted() || !DiscordPlugin.plugin.isGameRole(roleEvent.getRole())) + if (roleEvent.getRole().isDeleted() || !grm.isGameRole(roleEvent.getRole())) return; //Deleted or not a game role - DiscordPlugin.GameRoles.add(roleEvent.getRole().getName()); + GameRoles.add(roleEvent.getRole().getName()); DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { - if (DiscordPlugin.GameRoles.remove(roleEvent.getRole().getName())) + if (GameRoles.remove(roleEvent.getRole().getName())) DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + roleEvent.getRole().getName() + " as a game role."); } else if (roleEvent instanceof RoleUpdateEvent) { val event = (RoleUpdateEvent) roleEvent; - if (!DiscordPlugin.plugin.isGameRole(event.getNewRole())) { - if (DiscordPlugin.GameRoles.remove(event.getOldRole().getName())) + if (!grm.isGameRole(event.getNewRole())) { + if (GameRoles.remove(event.getOldRole().getName())) DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); } else { - if (DiscordPlugin.GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) + if (GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().getName())) return; - boolean removed = DiscordPlugin.GameRoles.remove(event.getOldRole().getName()); //Regardless of whether it was a game role - DiscordPlugin.GameRoles.add(event.getNewRole().getName()); //Add it because it has no color + 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 if (removed) DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); else @@ -59,4 +68,12 @@ public class GameRoleModule extends Component { } } } + + private boolean isGameRole(IRole r) { + if (r.getGuild().getLongID() != DiscordPlugin.mainServer.getLongID()) + return false; //Only allow on the main server + val rc = new Color(149, 165, 166, 0); + return r.getColor().equals(rc) + && r.getPosition() < DiscordPlugin.mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role + } } diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 1d80e51..1534e2b 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -12,6 +12,12 @@ import java.util.stream.Collectors; public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's parser + private GameRoleModule grm; + + RoleCommand(GameRoleModule grm) { + this.grm = grm; + } + @Override public String getCommandName() { return "role"; @@ -52,7 +58,7 @@ public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's par private void listRoles(IMessage message) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "List of roles:\n" + DiscordPlugin.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); + "List of roles:\n" + grm.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); } private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) { @@ -63,7 +69,7 @@ public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's par StringBuilder rolename = new StringBuilder(argsa[1]); for (int i = 2; i < argsa.length; i++) rolename.append(" ").append(argsa[i]); - if (!DiscordPlugin.GameRoles.contains(rolename.toString())) { + if (!grm.GameRoles.contains(rolename.toString())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "That role cannot be found."); listRoles(message); return null; @@ -72,7 +78,7 @@ public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's par if (roles.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified role cannot be found on Discord! Removing from the list."); - DiscordPlugin.GameRoles.remove(rolename.toString()); + grm.GameRoles.remove(rolename.toString()); return null; } if (roles.size() > 1) { -- 2.30.2 From abd4050786745a0994252e3ce8d34ff943826dff Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 23:41:52 +0100 Subject: [PATCH 039/108] Server start/stop msg + announcer fix Announcer data migration fix (which won't be needed because I'm gonna copy the new config over) The server start/stop messages show up again --- .../discordplugin/AnnouncerModule.java | 9 +- .../discordplugin/DiscordPlugin.java | 83 +++++++++---------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java index 8821b94..866635f 100644 --- a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java @@ -9,9 +9,11 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import lombok.val; +import org.bukkit.configuration.file.YamlConfiguration; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IMessage; +import java.io.File; import java.util.List; public class AnnouncerModule extends Component { @@ -27,7 +29,7 @@ public class AnnouncerModule extends Component { * Set to 0 or >50 to disable */ public ConfigData keepPinned() { - return getConfig().getData("keepPinned", (short) 40, i -> ((Integer) i).shortValue(), Short::intValue); + return getConfig().getData("keepPinned", (short) 40); } private ConfigData lastannouncementtime() { @@ -57,10 +59,11 @@ public class AnnouncerModule extends Component { } catch (InterruptedException ignore) { } }); + val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change if (lastannouncementtime().get() == 0) //Load old data - lastannouncementtime().set(getConfig().getConfig().getRoot().getLong("lastannouncementtime")); + lastannouncementtime().set(yc.getLong("lastannouncementtime")); if (lastseentime().get() == 0) - lastseentime().set(getConfig().getConfig().getLong("lastseentime")); + lastseentime().set(yc.getLong("lastseentime")); new Thread(this::AnnouncementGetterThreadMethod).start(); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 6431712..9187d52 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -138,6 +138,11 @@ public class DiscordPlugin extends ButtonPlugin implements IListener if (task != null) task.cancel(); if (!sent) { + 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()); new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled DiscordCommandBase.registerCommands(); @@ -169,26 +174,10 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } TBMCCoreAPI.SendUnsentExceptions(); TBMCCoreAPI.SendUnsentDebugMessages(); - /*if (!TBMCCoreAPI.IsTestServer()) { - final Calendar currentCal = Calendar.getInstance(); - final Calendar newCal = Calendar.getInstance(); - currentCal.set(currentCal.get(Calendar.YEAR), currentCal.get(Calendar.MONTH), - currentCal.get(Calendar.DAY_OF_MONTH), 4, 10); - if (currentCal.get(Calendar.DAY_OF_MONTH) % 9 == 0 && currentCal.before(newCal)) { - Random rand = new Random(); - sendMessageToChannel(dc.getChannels().get(rand.nextInt(dc.getChannels().size())), - "You could make a religion out of this"); - } - }*/ } }, 0, 10); for (IListener listener : CommonListeners.getListeners()) dc.getDispatcher().registerListener(listener); - Component.registerComponent(this, new GeneralEventBroadcasterModule()); - Component.registerComponent(this, new MinecraftChatModule()); - Component.registerComponent(this, new ExceptionListenerModule()); - Component.registerComponent(this, new GameRoleModule()); - Component.registerComponent(this, new AnnouncerModule()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCChatAPI.AddCommands(this, DiscordMCCommandBase.class); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); @@ -205,36 +194,40 @@ public class DiscordPlugin extends ButtonPlugin implements IListener */ public static boolean Restart; - @Override - public void pluginDisable() { - MCChatPrivate.logoutAll(); - getConfig().set("serverup", false); + @Override + public void pluginPreDisable() { + EmbedObject embed; + if (ResetMCCommand.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); + ChromaBot.getInstance().updatePlayerList(); + } - saveConfig(); - EmbedObject embed; - if (ResetMCCommand.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); - ChromaBot.getInstance().updatePlayerList(); + @Override + public void pluginDisable() { + MCChatPrivate.logoutAll(); + getConfig().set("serverup", false); + + saveConfig(); try { SafeMode = true; // Stop interacting with Discord ChromaBot.delete(); -- 2.30.2 From d08d32f73f0cba7e489fad369b6fa25f3c943132 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Feb 2019 00:24:42 +0100 Subject: [PATCH 040/108] Started using new command system for DC cmds Some of the new files are a couple days old --- .../buttondevteam/discordplugin/DPUtils.java | 8 +++-- .../discordplugin/DiscordPlugin.java | 11 +++++++ .../discordplugin/commands/Command2DC.java | 32 +++++++++++++++++++ .../commands/Command2DCSender.java | 21 ++++++++++++ .../commands/DiscordCommandBase.java | 3 +- .../discordplugin/commands/ICommand2DC.java | 20 ++++++++++++ .../commands/VersionCommand.java | 23 +++++-------- 7 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/commands/Command2DC.java create mode 100644 src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java create mode 100644 src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 6b649ab..2da113e 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -2,6 +2,7 @@ package buttondevteam.discordplugin; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; +import lombok.val; import org.bukkit.Bukkit; import sx.blah.discord.handle.obj.IChannel; import sx.blah.discord.handle.obj.IIDLinkedObject; @@ -112,8 +113,11 @@ public final class DPUtils { 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 roleData(IHaveConfig config, String key, long defID) { - return config.getDataPrimDef(key, defID, id -> DiscordPlugin.dc.getRoleByID((long) id), IIDLinkedObject::getLongID); //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 config.getDataPrimDef(key, defName, name -> { + val roles = DiscordPlugin.mainServer.getRolesByName((String) name); + return roles.size() > 0 ? roles.get(0) : null; //TODO: May not handle null properly + }, IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer) } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 9187d52..40f90a9 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,7 +1,9 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; +import buttondevteam.discordplugin.commands.Command2DC; import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.commands.VersionCommand; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; @@ -18,6 +20,7 @@ import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import com.google.common.io.Files; +import lombok.Getter; import lombok.val; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; @@ -46,6 +49,8 @@ public class DiscordPlugin extends ButtonPlugin implements IListener public static IDiscordClient 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); @@ -64,11 +69,16 @@ public class DiscordPlugin extends ButtonPlugin implements IListener return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L); } + public ConfigData ModRole() { + return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); + } + @Override public void pluginEnable() { try { Bukkit.getLogger().info("Initializing DiscordPlugin..."); plugin = this; + manager = new Command2DC(); ClientBuilder cb = new ClientBuilder(); cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); dc = cb.login(); @@ -146,6 +156,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled DiscordCommandBase.registerCommands(); + getManager().registerCommand(new VersionCommand()); if (ResetMCCommand.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 diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java new file mode 100644 index 0000000..22565d9 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -0,0 +1,32 @@ +package buttondevteam.discordplugin.commands; + +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.chat.Command2; + +import java.util.HashMap; +import java.util.function.Function; + +public class Command2DC extends Command2 { + private HashMap> subcommands = new HashMap<>(); + private HashMap, ParamConverter> paramConverters = new HashMap<>(); + + @Override + public void addParamConverter(Class cl, Function converter, String errormsg) { + addParamConverter(cl, converter, errormsg, paramConverters); + } + + @Override + public boolean handleCommand(Command2DCSender sender, String commandLine) throws Exception { + return handleCommand(sender, commandLine, subcommands, paramConverters); + } + + @Override + public void registerCommand(ICommand2DC command) { + registerCommand(command, subcommands, DiscordPlugin.getPrefix()); + } + + @Override + public boolean hasPermission(Command2DCSender sender, ICommand2DC command) { + return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); + } +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java new file mode 100644 index 0000000..5a04166 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -0,0 +1,21 @@ +package buttondevteam.discordplugin.commands; + +import buttondevteam.lib.chat.Command2Sender; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import sx.blah.discord.handle.obj.IMessage; + +@RequiredArgsConstructor +public class Command2DCSender implements Command2Sender { + private final @Getter IMessage message; + + @Override + public void sendMessage(String message) { + this.message.reply(message); + } + + @Override + public void sendMessage(String[] message) { + this.message.reply(String.join("\n", message)); + } +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index 947db5b..d05964f 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -27,12 +27,13 @@ public abstract class DiscordCommandBase { commands.put("mcchat", new MCChatCommand()); commands.put("channelcon", new ChannelconCommand()); commands.put("debug", new DebugCommand()); - commands.put("version", new VersionCommand()); } public static void runCommand(String cmd, String args, IMessage message) { debug("F"); //Not sure if needed DiscordCommandBase command = commands.get(cmd); + //if(command==null) + // DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmd+" "+args); //TODO! if (command == null) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "Unknown command: " + cmd + " with args: " + args + "\nDo '" diff --git a/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java b/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java new file mode 100644 index 0000000..c602c68 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java @@ -0,0 +1,20 @@ +package buttondevteam.discordplugin.commands; + +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2; +import lombok.Getter; +import lombok.val; + +public abstract class ICommand2DC extends ICommand2 { + public ICommand2DC() { + super(DiscordPlugin.plugin.getManager()); + val ann = getClass().getAnnotation(CommandClass.class); + if (ann == null) + modOnly = false; + else + modOnly = ann.modOnly(); + } + + private final @Getter boolean modOnly; +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java index 5908495..cf0ee8c 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java @@ -1,26 +1,19 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.chat.CommandClass; import lombok.val; -import sx.blah.discord.handle.obj.IMessage; -public class VersionCommand extends DiscordCommandBase { - @Override - public String getCommandName() { - return "version"; - } - - @Override - public boolean run(IMessage message, String args) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), String.join("\n", getVersion())); +@CommandClass(helpText = { + "Version", + "Returns the plugin's version" +}) +public class VersionCommand extends ICommand2DC { + public boolean def(Command2DCSender sender) { + sender.sendMessage(getVersion()); return true; } - @Override - public String[] getHelpText() { - return VersionCommand.getVersion(); //Heh - } - public static String[] getVersion() { val desc = DiscordPlugin.plugin.getDescription(); return new String[]{ // -- 2.30.2 From 9ba57fd9897d89ba7125d699241266594bec393e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 12 Feb 2019 22:38:59 +0100 Subject: [PATCH 041/108] Actually using the cmd sys, logger stuff Some of the new files are a couple days old Using the plugin's logger almost everywhere --- .../java/buttondevteam/discordplugin/DPUtils.java | 4 ++-- .../buttondevteam/discordplugin/DiscordPlugin.java | 6 +++--- .../broadcaster/GeneralEventBroadcasterModule.java | 3 +-- .../discordplugin/listeners/CommandListener.java | 12 +++++++++--- .../discordplugin/mcchat/MCChatListener.java | 7 ++----- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 2da113e..e415298 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -59,7 +59,7 @@ public final class DPUtils { 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."); - Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!"); + getLogger().warning("Waiting for a Discord request on the main thread!"); return RequestBuffer.request(action).get(timeout, unit); // Let the pros handle this } @@ -72,7 +72,7 @@ public final class DPUtils { 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."); - Bukkit.getLogger().warning("Waiting for a Discord request on the main thread!"); + getLogger().warning("Waiting for a Discord request on the main thread!"); return RequestBuffer.request(action).get(); // Let the pros handle this } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 40f90a9..fc12fed 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -76,7 +76,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener @Override public void pluginEnable() { try { - Bukkit.getLogger().info("Initializing DiscordPlugin..."); + getLogger().info("Initializing..."); plugin = this; manager = new Command2DC(); ClientBuilder cb = new ClientBuilder(); @@ -284,7 +284,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener 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); - Bukkit.getLogger() + DPUtils.getLogger() .warning("Message was too long to send to discord and got truncated. In " + channel.getName()); } try { @@ -307,7 +307,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } catch (TimeoutException | InterruptedException e) { throw e; } catch (Exception e) { - Bukkit.getLogger().warning( + DPUtils.getLogger().warning( "Failed to deliver message to Discord! Channel: " + channel.getName() + " Message: " + message); throw new RuntimeException(e); } diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 8830f37..e8a71e7 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -4,7 +4,6 @@ import buttondevteam.discordplugin.DPUtils; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import lombok.Getter; -import org.bukkit.Bukkit; public class GeneralEventBroadcasterModule extends Component { private static @Getter boolean hooked = false; @@ -13,7 +12,7 @@ public class GeneralEventBroadcasterModule extends Component { protected void enable() { try { PlayerListWatcher.hookUp(); - Bukkit.getLogger().info("Finished hooking into the player list"); + DPUtils.getLogger().info("Finished hooking into the player list"); hooked = true; } catch (Exception e) { TBMCCoreAPI.SendException("Error while hacking the player list!", e); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index b6fe5c6..a9eae80 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -1,7 +1,8 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.commands.DiscordCommandBase; +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; @@ -38,7 +39,12 @@ public class CommandListener { } message.getChannel().setTypingStatus(true); String cmdwithargsString = cmdwithargs.toString().trim(); //Remove spaces between mention and command - int index = cmdwithargsString.indexOf(" "); + try { + DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString); + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); + } + /*int index = cmdwithargsString.indexOf(" "); String cmd; String args; if (index == -1) { @@ -48,7 +54,7 @@ public class CommandListener { cmd = cmdwithargsString.substring(0, index); args = cmdwithargsString.substring(index + 1).trim(); //In case there are multiple spaces } - DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message); + DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message);*/ message.getChannel().setTypingStatus(false); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 6c90870..5113f3c 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -9,10 +9,7 @@ import buttondevteam.discordplugin.DiscordSender; import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.discordplugin.listeners.CommandListener; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; -import buttondevteam.lib.TBMCChatEvent; -import buttondevteam.lib.TBMCChatPreprocessEvent; -import buttondevteam.lib.TBMCCommandPreprocessEvent; -import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.*; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.TBMCPlayer; @@ -377,7 +374,7 @@ public class MCChatListener implements Listener { : 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."); + : dsender.getName()) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL); } else { val cmb = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false); -- 2.30.2 From 13b168d23890275fe1c6a4f0935541064ae5e141 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 13 Feb 2019 15:21:57 +0100 Subject: [PATCH 042/108] Made all channels configurable Removed Vault repo, was unused and errors now Removed all channel fields from main class --- pom.xml | 502 +++++++++--------- .../discordplugin/DiscordPlugin.java | 35 +- .../exceptions/DebugMessageListener.java | 63 +-- .../exceptions/ExceptionListenerModule.java | 168 +++--- .../discordplugin/fun/FunModule.java | 9 +- .../discordplugin/mcchat/MCListener.java | 41 +- .../mcchat/MinecraftChatModule.java | 6 +- 7 files changed, 415 insertions(+), 409 deletions(-) diff --git a/pom.xml b/pom.xml index 0ccfe46..270da7f 100755 --- a/pom.xml +++ b/pom.xml @@ -1,251 +1,251 @@ - - 4.0.0 - - com.github.TBMCPlugins - DiscordPlugin - master-SNAPSHOT - jar - - 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 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.2 - - - package - - shade - - - - - org.spigotmc:spigot-api - com.github.TBMCPlugins.ButtonCore:ButtonCore - net.ess3:Essentials - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.1 - - - copy - compile - - copy-resources - - - target - - - resources - - - - - - - - - maven-surefire-plugin - - false - - - - - - - - UTF-8 - - master - - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - jcenter - http://jcenter.bintray.com - - - jitpack.io - https://jitpack.io - - - vault-repo - http://nexus.hc.to/content/repositories/pub_releases - - - 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 - - - - - com.github.SizableShrimp - Discord4J - httprequestchange-SNAPSHOT - - - - 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 - provided - - - com.github.xaanit - D4J-OAuth - master-SNAPSHOT - - - - org.projectlombok - lombok - 1.16.16 - provided - - - - - org.objenesis - objenesis - 2.6 - test - - - com.vdurmont - emoji-java - 4.0.0 - - - - - - ci - - - env.TRAVIS_BRANCH - - - - - ${env.TRAVIS_BRANCH} - - - - + + 4.0.0 + + com.github.TBMCPlugins + DiscordPlugin + master-SNAPSHOT + jar + + 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 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.2 + + + package + + shade + + + + + org.spigotmc:spigot-api + com.github.TBMCPlugins.ButtonCore:ButtonCore + net.ess3:Essentials + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + + copy + compile + + copy-resources + + + target + + + resources + + + + + + + + + maven-surefire-plugin + + false + + + + + + + + UTF-8 + + master + + + + + + 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 + + + + + + + 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.github.SizableShrimp + Discord4J + httprequestchange-SNAPSHOT + + + + 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 + provided + + + com.github.xaanit + D4J-OAuth + master-SNAPSHOT + + + + org.projectlombok + lombok + 1.16.16 + provided + + + + + org.objenesis + objenesis + 2.6 + test + + + com.vdurmont + emoji-java + 4.0.0 + + + + + + ci + + + env.TRAVIS_BRANCH + + + + + ${env.TRAVIS_BRANCH} + + + + diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index fc12fed..eab7e6e 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.commands.Command2DC; import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.commands.VersionCommand; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; +import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; import buttondevteam.discordplugin.mcchat.MCChatPrivate; @@ -89,18 +90,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } } - public static IChannel botchannel; //Can be removed - public static IChannel annchannel; - public static IChannel genchannel; - public static IChannel chatchannel; - public static IChannel botroomchannel; - public static IChannel modlogchannel; - /** - * Don't send messages, just receive, the same channel is used when testing - */ - public static IChannel officechannel; - public static IChannel updatechannel; - public static IChannel devofficechannel; public static IGuild mainServer; public static IGuild devServer; @@ -119,31 +108,10 @@ public class DiscordPlugin extends ButtonPlugin implements IListener if (mainServer == null || devServer == null) return; // Retry if (!TBMCCoreAPI.IsTestServer()) { //Don't change conditions here, see mainServer=devServer=null in onDisable() - botchannel = mainServer.getChannelByID(209720707188260864L); // bot - annchannel = mainServer.getChannelByID(126795071927353344L); // announcements - genchannel = mainServer.getChannelByID(125813020357165056L); // general - chatchannel = mainServer.getChannelByID(249663564057411596L); // minecraft_chat - botroomchannel = devServer.getChannelByID(239519012529111040L); // bot-room - officechannel = devServer.getChannelByID(219626707458457603L); // developers-office - updatechannel = devServer.getChannelByID(233724163519414272L); // server-updates - devofficechannel = officechannel; // developers-office - modlogchannel = mainServer.getChannelByID(283840717275791360L); // modlog dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Chromacraft"); } else { - botchannel = devServer.getChannelByID(239519012529111040L); // bot-room - annchannel = botchannel; // bot-room - genchannel = botchannel; // bot-room - botroomchannel = botchannel;// bot-room - chatchannel = botchannel;// bot-room - officechannel = devServer.getChannelByID(219626707458457603L); // developers-office - updatechannel = botchannel; - devofficechannel = botchannel;// bot-room - modlogchannel = botchannel; // bot-room dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); } - if (botchannel == null || annchannel == null || genchannel == null || botroomchannel == null - || chatchannel == null || officechannel == null || updatechannel == null) - return; // Retry SafeMode = false; if (task != null) task.cancel(); @@ -153,6 +121,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener 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 DiscordCommandBase.registerCommands(); diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java index cca3e98..95c3cdb 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/DebugMessageListener.java @@ -1,31 +1,32 @@ -package buttondevteam.discordplugin.exceptions; - -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.TBMCDebugMessageEvent; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -public class DebugMessageListener implements Listener{ - @EventHandler - public void onDebugMessage(TBMCDebugMessageEvent e) { - SendMessage(e.getDebugMessage()); - e.setSent(); - } - - private static void SendMessage(String message) { - if (DiscordPlugin.SafeMode) - return; - try { - 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(DiscordPlugin.botroomchannel, sb.toString()); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - -} +package buttondevteam.discordplugin.exceptions; + +import buttondevteam.core.ComponentManager; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.TBMCDebugMessageEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class DebugMessageListener implements Listener{ + @EventHandler + public void onDebugMessage(TBMCDebugMessageEvent e) { + SendMessage(e.getDebugMessage()); + e.setSent(); + } + + private static void SendMessage(String message) { + if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(ExceptionListenerModule.class)) + return; + try { + 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()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index f491a24..6821e6f 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -1,76 +1,92 @@ -package buttondevteam.discordplugin.exceptions; - -import buttondevteam.core.ComponentManager; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.TBMCExceptionEvent; -import buttondevteam.lib.architecture.Component; -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.IRole; - -import java.util.ArrayList; -import java.util.Arrays; -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<>(); - - @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 IRole coderRole; - - private static void SendException(Throwable e, String sourcemessage) { - try { - if (coderRole == null) - coderRole = DiscordPlugin.devServer.getRolesByName("Coder").get(0); - StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() - : new StringBuilder(coderRole.mention()).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); - sb.append(stackTrace).append("\n"); - sb.append("```"); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.botroomchannel, sb.toString()); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - @Override - protected void enable() { - Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin()); - TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin()); - } - - @Override - protected void disable() { - - } -} +package buttondevteam.discordplugin.exceptions; + +import buttondevteam.core.ComponentManager; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.TBMCExceptionEvent; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +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.IRole; + +import java.util.ArrayList; +import java.util.Arrays; +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<>(); + + @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 IRole coderRole; + + private static void SendException(Throwable e, String sourcemessage) { + if (instance == null) return; + try { + if (coderRole == null) + coderRole = DiscordPlugin.devServer.getRolesByName("Coder").get(0); + StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() + : new StringBuilder(coderRole.mention()).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); + sb.append(stackTrace).append("\n"); + sb.append("```"); + DiscordPlugin.sendMessageToChannel(getChannel(), sb.toString()); //Instance isn't null here + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private static ExceptionListenerModule instance; + + public static IChannel getChannel() { + if (instance != null) return instance.channel().get(); + return null; + } + + private ConfigData channel() { + return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); + } + + @Override + protected void enable() { + instance = this; + Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin()); + TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin()); + } + + @Override + protected void disable() { + instance = null; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 9565a53..c5bfd8d 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin.fun; import buttondevteam.core.ComponentManager; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; @@ -12,6 +13,7 @@ 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.IChannel; import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IRole; import sx.blah.discord.handle.obj.StatusType; @@ -123,6 +125,11 @@ public class FunModule extends Component implements Listener { }, IRole::getName); } + + private ConfigData fullHouseChannel() { + return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L); + } + private static long lasttime = 0; public static void handleFullHouse(PresenceUpdateEvent event) { @@ -138,7 +145,7 @@ public class FunModule extends Component implements Listener { .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(DiscordPlugin.devofficechannel, "Full house!", + DiscordPlugin.sendMessageToChannel(mod.fullHouseChannel().get(), "Full house!", new EmbedBuilder() .withImage( "https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png") diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index ca34d8c..fbf9d27 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -3,8 +3,10 @@ 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 lombok.RequiredArgsConstructor; import lombok.val; import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.api.events.MuteStatusChangeEvent; @@ -26,14 +28,17 @@ import sx.blah.discord.handle.obj.IUser; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.MissingPermissionsException; +@RequiredArgsConstructor class MCListener implements Listener { + private final MinecraftChatModule module; + @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerLogin(PlayerLoginEvent e) { if (e.getResult() != Result.ALLOWED) 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 -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); + .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() + .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); } @EventHandler(priority = EventPriority.LOWEST) @@ -46,9 +51,9 @@ class MCListener implements Listener { if (dp != null) { val user = DiscordPlugin.dc.getUserByID(Long.parseLong(dp.getDiscordID())); MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); + new DiscordPlayerSender(user, user.getOrCreatePMChannel(), p)); MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, DiscordPlugin.chatchannel, p)); //Stored per-channel + new DiscordPlayerSender(user, module.chatChannel().get(), p)); //Stored per-channel } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); @@ -61,13 +66,13 @@ class MCListener implements Listener { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Only care about real users MCChatUtils.OnlineSenders.entrySet() - .removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()))); + .removeIf(entry -> entry.getValue().entrySet().stream().anyMatch(p -> p.getValue().getUniqueId().equals(e.getPlayer().getUniqueId()))); Bukkit.getScheduler().runTask(DiscordPlugin.plugin, - () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) - .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); + () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) + .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() + .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, - ChromaBot.getInstance()::updatePlayerList, 5); + ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } @@ -90,32 +95,36 @@ class MCListener implements Listener { if (e.isCancelled() || !base.isOnline()) return; final String msg = base.getDisplayName() - + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; + + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); } + private ConfigData muteRole() { + return DPUtils.roleData(module.getConfig(), "muteRole", "Muted"); + } + @EventHandler public void onPlayerMute(MuteStatusChangeEvent e) { try { DPUtils.performNoWait(() -> { - final IRole role = DiscordPlugin.dc.getRoleByID(164090010461667328L); //TODO: Config + final IRole role = muteRole().get(); final CommandSource source = e.getAffected().getSource(); if (!source.isPlayer()) return; final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) - .getAs(DiscordPlayer.class); + .getAs(DiscordPlayer.class); if (p == null) return; final IUser user = DiscordPlugin.dc.getUserByID( - Long.parseLong(p.getDiscordID())); + Long.parseLong(p.getDiscordID())); if (e.getValue()) user.addRole(role); else user.removeRole(role); - DiscordPlugin.sendMessageToChannel(DiscordPlugin.modlogchannel, (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); + DiscordPlugin.sendMessageToChannel(module.modlogChannel().get(), (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); }); } catch (DiscordException | MissingPermissionsException ex) { TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", - ex); + ex); } } @@ -132,7 +141,7 @@ class MCListener implements Listener { @EventHandler public void onYEEHAW(TBMCYEEHAWEvent event) { //TODO: Inherit from the chat event base to have channel support String name = event.getSender() instanceof Player ? ((Player) event.getSender()).getDisplayName() - : event.getSender().getName(); + : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 55d68d6..3684a5f 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -32,12 +32,16 @@ public class MinecraftChatModule extends Component { return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L); } + public ConfigData modlogChannel() { + return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L); + } + @Override protected void enable() { listener = new MCChatListener(this); DiscordPlugin.dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); - TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled + TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(this), getPlugin());//These get undone if restarting/resetting - it will ignore events if disabled val chcons = getConfig().getConfig().getConfigurationSection("chcons"); if (chcons == null) //Fallback to old place -- 2.30.2 From 5a9986de4fa6bba673ae69ab59d5fca192dfd0a0 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Feb 2019 00:39:48 +0100 Subject: [PATCH 043/108] Command stuff fixed Replies sanitized, userinfo converted Manually removing spaces Tested --- .../discordplugin/DiscordPlugin.java | 2 + .../discordplugin/commands/Command2DC.java | 2 +- .../commands/Command2DCSender.java | 5 +- .../commands/DiscordCommandBase.java | 1 - .../discordplugin/commands/ICommand2DC.java | 2 +- .../commands/UserinfoCommand.java | 190 +++++++++--------- .../commands/VersionCommand.java | 2 + .../listeners/CommandListener.java | 26 +-- 8 files changed, 114 insertions(+), 116 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index eab7e6e..d62b773 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.Command2DC; import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.commands.UserinfoCommand; import buttondevteam.discordplugin.commands.VersionCommand; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.fun.FunModule; @@ -126,6 +127,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener DiscordCommandBase.registerCommands(); getManager().registerCommand(new VersionCommand()); + getManager().registerCommand(new UserinfoCommand()); if (ResetMCCommand.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 diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index 22565d9..e61d43f 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -22,7 +22,7 @@ public class Command2DC extends Command2 { @Override public void registerCommand(ICommand2DC command) { - registerCommand(command, subcommands, DiscordPlugin.getPrefix()); + registerCommand(command, subcommands, DiscordPlugin.getPrefix()); //Needs to be configurable for the helps } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index 5a04166..a2281f9 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.commands; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.lib.chat.Command2Sender; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -11,11 +12,11 @@ public class Command2DCSender implements Command2Sender { @Override public void sendMessage(String message) { - this.message.reply(message); + this.message.reply(DPUtils.sanitizeString(message)); } @Override public void sendMessage(String[] message) { - this.message.reply(String.join("\n", message)); + this.message.reply(DPUtils.sanitizeString(String.join("\n", message))); } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index d05964f..7f38d45 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -22,7 +22,6 @@ public abstract class DiscordCommandBase { public static void registerCommands() { commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? - commands.put("userinfo", new UserinfoCommand()); commands.put("help", new HelpCommand()); commands.put("mcchat", new MCChatCommand()); commands.put("channelcon", new ChannelconCommand()); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java b/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java index c602c68..6aae802 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ICommand2DC.java @@ -6,7 +6,7 @@ import buttondevteam.lib.chat.ICommand2; import lombok.Getter; import lombok.val; -public abstract class ICommand2DC extends ICommand2 { +public abstract class ICommand2DC extends ICommand2 { public ICommand2DC() { super(DiscordPlugin.plugin.getManager()); val ann = getClass().getAnnotation(CommandClass.class); diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index b1dbf8b..7954002 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -1,99 +1,91 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.ChromaGamerBase.InfoTarget; -import sx.blah.discord.handle.obj.IMessage; -import sx.blah.discord.handle.obj.IUser; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public class UserinfoCommand extends DiscordCommandBase { - - @Override - public String getCommandName() { - return "userinfo"; - } - - @Override - public boolean run(IMessage message, String args) { - IUser target = null; - if (args.length() == 0) - target = message.getAuthor(); - else { - final Optional firstmention = message.getMentions().stream() - .filter(m -> !m.getStringID().equals(DiscordPlugin.dc.getOurUser().getStringID())).findFirst(); - if (firstmention.isPresent()) - target = firstmention.get(); - else if (args.contains("#")) { - String[] targettag = args.split("#"); - final List targets = getUsers(message, targettag[0]); - if (targets.size() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found (by name): " + args); - return true; - } - for (IUser ptarget : targets) { - if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { - target = ptarget; - break; - } - } - if (target == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found (by discriminator): " + args + "(Found " + targets.size() - + " users with the name.)"); - return true; - } - } else { - final List targets = getUsers(message, args); - if (targets.size() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found on Discord: " + args); - 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; - } - target = targets.get(0); - } - } - try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getStringID(), 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); - } - return true; - } - - private List getUsers(IMessage message, String args) { - final List targets; - if (message.getChannel().isPrivate()) - targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args)) - .collect(Collectors.toList()); - else - targets = message.getGuild().getUsersByName(args, true); - return targets; - } - - @Override - public String[] getHelpText() { - return new String[] { // - "---- User information ----", // - "Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", // - "If used without args, shows your info.", // - "Usage: " + DiscordPlugin.getPrefix() + "userinfo [username/nickname[#tag]/ping]", // - "Examples:\n" + DiscordPlugin.getPrefix() + "userinfo ChromaBot\n" + DiscordPlugin.getPrefix() + "userinfo ChromaBot#6338\n" + DiscordPlugin.getPrefix() + "userinfo @ChromaBot#6338" // - }; - } - -} +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; +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 java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@CommandClass(helpText = { + "User information", // + "Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", // + "If used without args, shows your info.", // +}) +public class UserinfoCommand extends ICommand2DC { + @Command2.Subcommand + public boolean def(Command2DCSender sender, @Command2.OptionalArg String args) { + val message = sender.getMessage(); + IUser target = null; + if (args == null || args.length() == 0) + target = message.getAuthor(); + else { + final Optional firstmention = message.getMentions().stream() + .filter(m -> !m.getStringID().equals(DiscordPlugin.dc.getOurUser().getStringID())).findFirst(); + if (firstmention.isPresent()) + target = firstmention.get(); + else if (args.contains("#")) { + String[] targettag = args.split("#"); + final List targets = getUsers(message, targettag[0]); + if (targets.size() == 0) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "The user cannot be found (by name): " + args); + return true; + } + for (IUser ptarget : targets) { + if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { + target = ptarget; + break; + } + } + if (target == null) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "The user cannot be found (by discriminator): " + args + "(Found " + targets.size() + + " users with the name.)"); + return true; + } + } else { + final List targets = getUsers(message, args); + if (targets.size() == 0) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "The user cannot be found on Discord: " + args); + 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; + } + target = targets.get(0); + } + } + try (DiscordPlayer dp = ChromaGamerBase.getUser(target.getStringID(), 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); + } + return true; + } + + private List getUsers(IMessage message, String args) { + final List targets; + if (message.getChannel().isPrivate()) + targets = DiscordPlugin.dc.getUsers().stream().filter(u -> u.getName().equalsIgnoreCase(args)) + .collect(Collectors.toList()); + else + targets = message.getGuild().getUsersByName(args, true); + return targets; + } + +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java index cf0ee8c..ac83243 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/VersionCommand.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import lombok.val; @@ -9,6 +10,7 @@ import lombok.val; "Returns the plugin's version" }) public class VersionCommand extends ICommand2DC { + @Command2.Subcommand public boolean def(Command2DCSender sender) { sender.sendMessage(getVersion()); return true; diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index a9eae80..4093b07 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -21,7 +21,7 @@ public class CommandListener { final IChannel channel = message.getChannel(); if (!mentionedonly) { //mentionedonly conditions are in CommonListeners if (!message.getChannel().isPrivate() - && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() + && !(message.getContent().charAt(0) == DiscordPlugin.getPrefix() && channel.getStringID().equals(DiscordPlugin.plugin.CommandChannel().get().getStringID()))) // return false; message.getChannel().setTypingStatus(true); // Fun @@ -38,9 +38,10 @@ public class CommandListener { return false; } message.getChannel().setTypingStatus(true); - String cmdwithargsString = cmdwithargs.toString().trim(); //Remove spaces between mention and command + String cmdwithargsString = cmdwithargs.toString(); try { - DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString); + if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) + message.reply("Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); } @@ -61,18 +62,19 @@ public class CommandListener { private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text - if (cmdwithargs.length() > mention.length() + 1) - cmdwithargs.delete(0, - cmdwithargs.charAt(mention.length()) == ' ' ? mention.length() + 1 : mention.length()); - else - cmdwithargs.replace(0, cmdwithargs.length(), "help"); + if (cmdwithargs.length() > mention.length() + 1) { + int x = mention.length(), px = x; + while ((x = cmdwithargs.indexOf(" ", px + 1)) != -1) //Removes any space before the command + px = x; + cmdwithargs.delete(0, px + 1); + cmdwithargs.insert(0, DiscordPlugin.getPrefix()); //Always use the prefix for processing + } else + cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help"); else { - if (cmdwithargs.length() > 0 && cmdwithargs.charAt(0) == '/') - cmdwithargs.deleteCharAt(0); //Don't treat / as mention, mentions can be used in public mcchat - return false; + return false; //Don't treat / as mention, mentions can be used in public mcchat } if (cmdwithargs.length() == 0) - cmdwithargs.replace(0, cmdwithargs.length(), "help"); + cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help"); return true; } } -- 2.30.2 From 0cbc22eb7251d6d891267fad8698b785c1c71acb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Feb 2019 14:08:37 +0100 Subject: [PATCH 044/108] Added support for broadcast toggles #89 --- .../commands/ChannelconCommand.java | 136 +++++++++++------- .../discordplugin/mcchat/MCChatCustom.java | 9 +- .../discordplugin/mcchat/MCChatUtils.java | 2 +- .../mcchat/MinecraftChatModule.java | 9 +- 4 files changed, 97 insertions(+), 59 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java index df9398a..445d194 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -3,6 +3,9 @@ package buttondevteam.discordplugin.commands; import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.mcchat.MCChatCustom; +import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.TBMCPlayer; import lombok.val; import org.bukkit.Bukkit; @@ -10,61 +13,80 @@ import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.Permissions; import sx.blah.discord.util.PermissionUtils; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.function.Supplier; import java.util.stream.Collectors; -public class ChannelconCommand extends DiscordCommandBase { - @Override - public String getCommandName() { - return "channelcon"; - } +@CommandClass(helpText = {"---- Channel connect ---", // + "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // + "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 #bot use /connect .", // + "Call this command from the channel you want to use.", // + "Usage: @Bot 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 / prefix only works in #bot.", // + "Invite link: " // +}) +public class ChannelconCommand extends ICommand2DC { + @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."); + else + message.reply("this channel isn't connected."); + return true; + } - @Override - public boolean run(IMessage message, String args) { - if (args.length() == 0) - return false; - if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { - message.reply("you need to have manage permissions for this channel!"); - return true; - } - if (MCChatCustom.hasCustomChat(message.getChannel())) { - if (args.toLowerCase().startsWith("remove")) { - if (MCChatCustom.removeCustomChat(message.getChannel())) - message.reply("channel connection removed."); - else - message.reply("wait what, couldn't remove channel connection."); - return true; - } - if (args.toLowerCase().startsWith("toggle")) { - val cc = MCChatCustom.getCustomChat(message.getChannel()); - assert cc != null; //It's not null - Supplier togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")); - String[] argsa = args.split(" "); - if (argsa.length < 2) { - message.reply("toggles:\n" + togglesString.get()); - return true; - } - String arg = argsa[1].toUpperCase(); - val b = Arrays.stream(ChannelconBroadcast.values()).filter(t -> t.toString().equals(arg)).findAny(); - if (!b.isPresent()) { - message.reply("cannot find toggle. Toggles:\n" + togglesString.get()); - return true; - } - //A B | F - //------- A: original - B: mask - F: new - //0 0 | 0 - //0 1 | 1 - //1 0 | 1 - //1 1 | 0 - // XOR - cc.toggles ^= b.get().flag; - message.reply("'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")); - return true; - } - message.reply("this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); - return true; - } + @Command2.Subcommand + public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) { + val message = sender.getMessage(); + if (checkPerms(message)) return true; + val cc = MCChatCustom.getCustomChat(message.getChannel()); + assert cc != null; //It's not null + 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(TBMCSystemChatEvent.BroadcastTarget::getName).collect(Collectors.joining("\n")); + if (toggle == null) { + message.reply("toggles:\n" + togglesString.get()); + return true; + } + String arg = toggle.toUpperCase(); + val b = Arrays.stream(ChannelconBroadcast.values()).filter(t -> t.toString().equals(arg)).findAny(); + if (!b.isPresent()) { + val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg); + if (bt == null) { + message.reply("cannot find toggle. Toggles:\n" + togglesString.get()); + return true; + } + final boolean add; + if (add = !cc.brtoggles.contains(bt)) + cc.brtoggles.add(bt); + else + cc.brtoggles.remove(bt); + return respond(sender, "'" + bt.getName() + "' " + (add ? "en" : "dis") + "abled"); + } + //A B | F + //------- A: original - B: mask - F: new + //0 0 | 0 + //0 1 | 1 + //1 0 | 1 + //1 1 | 0 + // XOR + cc.toggles ^= b.get().flag; + message.reply("'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")); + return true; + } + + @Command2.Subcommand + public boolean def(Command2DCSender sender, String args) { + val message = sender.getMessage(); + if (checkPerms(message)) return true; + if (MCChatCustom.hasCustomChat(message.getChannel())) + 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(args) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /."); @@ -87,13 +109,21 @@ public class ChannelconCommand extends DiscordCommandBase { message.reply("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); + MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0, new ArrayList<>()); message.reply("alright, connection made to group `" + groupid + "`!"); return true; } - @Override - public String[] getHelpText() { + private boolean checkPerms(IMessage message) { + if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { + message.reply("you need to have manage permissions for this channel!"); + return true; + } + return false; + } + + @Override + public String[] getHelpText(Method method) { return new String[]{ // "---- Channel connect ---", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index fe0769a..4c0a62a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -2,6 +2,7 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.component.channel.Channel; import buttondevteam.discordplugin.DiscordConnectedPlayer; +import buttondevteam.lib.TBMCSystemChatEvent; import lombok.NonNull; import lombok.val; import sx.blah.discord.handle.obj.IChannel; @@ -18,8 +19,8 @@ public class MCChatCustom { */ static ArrayList lastmsgCustom = new ArrayList<>(); - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles) { - val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles); + public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, List brtoggles) { + val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles, brtoggles); lastmsgCustom.add(lmd); } @@ -46,14 +47,16 @@ public class MCChatCustom { public final Channel mcchannel; public final DiscordConnectedPlayer dcp; public int toggles; + public List brtoggles; private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, - @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles) { + @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, List brtoggles) { super(channel, user); groupID = groupid; this.mcchannel = mcchannel; this.dcp = dcp; this.toggles = toggles; + this.brtoggles = brtoggles; } } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index cd45dbe..56582ba 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -172,7 +172,7 @@ public class MCChatUtils { if (event.shouldSendTo(getSender(data.channel, data.user))) action.accept(data.channel); MCChatCustom.lastmsgCustom.stream().filter(clmd -> { - if ((clmd.toggles & ChannelconBroadcast.BROADCAST.flag) == 0) + if (!clmd.brtoggles.contains(event.getTarget())) return false; return event.shouldSendTo(clmd.dcp); }).map(clmd -> clmd.channel).forEach(action); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 3684a5f..069ac47 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import com.google.common.collect.Lists; @@ -14,7 +15,9 @@ import org.bukkit.Bukkit; import sx.blah.discord.handle.obj.IChannel; import java.util.ArrayList; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; public class MinecraftChatModule extends Component { private @Getter MCChatListener listener; @@ -56,11 +59,12 @@ public class MinecraftChatModule extends Component { val user = DiscordPlugin.dc.fetchUser(did); 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); + MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toList())); }); } } @@ -79,7 +83,8 @@ public class MinecraftChatModule extends Component { chconc.set("mcname", chcon.dcp.getName()); chconc.set("groupid", chcon.groupID); chconc.set("toggles", chcon.toggles); + chconc.set("brtoggles", chcon.brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::getName).collect(Collectors.toList())); } MCChatListener.stop(true); - } //TODO: Use ComponentManager.isEnabled() at other places too, instead of SafeMode + } } -- 2.30.2 From 0c9da49adda26b81240aa128275a93f60bb2a6ea Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 17 Feb 2019 02:26:14 +0100 Subject: [PATCH 045/108] Brtoggle & cmd fix #89 Channelcon Attempted to support chat rooms in custom chat --- .../discordplugin/DiscordPlugin.java | 2 + .../commands/DiscordCommandBase.java | 1 - .../listeners/CommandListener.java | 9 +-- .../ChannelconCommand.java | 72 +++++++++++-------- .../discordplugin/mcchat/MCChatCustom.java | 20 ++++-- .../mcchat/MinecraftChatModule.java | 2 +- 6 files changed, 65 insertions(+), 41 deletions(-) rename src/main/java/buttondevteam/discordplugin/{commands => mcchat}/ChannelconCommand.java (69%) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index d62b773..feb43df 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -9,6 +9,7 @@ import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; +import buttondevteam.discordplugin.mcchat.ChannelconCommand; import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; @@ -128,6 +129,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener DiscordCommandBase.registerCommands(); getManager().registerCommand(new VersionCommand()); getManager().registerCommand(new UserinfoCommand()); + getManager().registerCommand(new ChannelconCommand()); if (ResetMCCommand.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 diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index 7f38d45..61d5fa1 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -24,7 +24,6 @@ public abstract class DiscordCommandBase { commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? commands.put("help", new HelpCommand()); commands.put("mcchat", new MCChatCommand()); - commands.put("channelcon", new ChannelconCommand()); commands.put("debug", new DebugCommand()); } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 4093b07..4bdf572 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -63,10 +63,11 @@ public class CommandListener { private static boolean checkanddeletemention(StringBuilder cmdwithargs, String mention, IMessage message) { if (message.getContent().startsWith(mention)) // TODO: Resolve mentions: Compound arguments, either a mention or text if (cmdwithargs.length() > mention.length() + 1) { - int x = mention.length(), px = x; - while ((x = cmdwithargs.indexOf(" ", px + 1)) != -1) //Removes any space before the command - px = x; - cmdwithargs.delete(0, px + 1); + int i = cmdwithargs.indexOf(" ", mention.length()); + //noinspection StatementWithEmptyBody + 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 } else cmdwithargs.replace(0, cmdwithargs.length(), DiscordPlugin.getPrefix() + "help"); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java similarity index 69% rename from src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java rename to src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index 445d194..ceb184b 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -1,8 +1,10 @@ -package buttondevteam.discordplugin.commands; +package buttondevteam.discordplugin.mcchat; import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.ChatRoom; import buttondevteam.discordplugin.*; -import buttondevteam.discordplugin.mcchat.MCChatCustom; +import buttondevteam.discordplugin.commands.Command2DCSender; +import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; @@ -14,12 +16,12 @@ import sx.blah.discord.handle.obj.Permissions; import sx.blah.discord.util.PermissionUtils; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.function.Supplier; import java.util.stream.Collectors; -@CommandClass(helpText = {"---- Channel connect ---", // +@CommandClass(helpText = {"Channel connect", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "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 #bot use /connect .", // @@ -47,9 +49,10 @@ public class ChannelconCommand extends ICommand2DC { val message = sender.getMessage(); if (checkPerms(message)) return true; val cc = MCChatCustom.getCustomChat(message.getChannel()); - assert cc != null; //It's not null + 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(TBMCSystemChatEvent.BroadcastTarget::getName).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()); return true; @@ -82,37 +85,44 @@ public class ChannelconCommand extends ICommand2DC { } @Command2.Subcommand - public boolean def(Command2DCSender sender, String args) { + public boolean def(Command2DCSender sender, String channelID) { val message = sender.getMessage(); if (checkPerms(message)) return true; if (MCChatCustom.hasCustomChat(message.getChannel())) 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(args) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); - if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) - message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /."); - return true; - } - val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), 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 "); - return true; - } - DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()); - //Using a fake player with no login/logout, should be fine for this event - String groupid = chan.get().getGroupID(dcp); - if (groupid == null) { - message.reply("sorry, that didn't work. You cannot use that Minecraft channel."); - return true; - } + 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 /."); + return true; + } + val dp = DiscordPlayer.getUser(message.getAuthor().getStringID(), 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 "); + return true; + } + DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()); + //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."); + return true; + } + if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well + message.reply("chat rooms are not supported yet."); + 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."); return true; }*/ //TODO: "Channel admins" that can connect channels? - MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0, new ArrayList<>()); - message.reply("alright, connection made to group `" + groupid + "`!"); - return true; - } + MCChatCustom.addCustomChat(message.getChannel(), groupid, chan.get(), message.getAuthor(), dcp, 0, new HashSet<>()); + if (chan.get() instanceof ChatRoom) + message.reply("alright, connection made to the room!"); + else + message.reply("alright, connection made to group `" + groupid + "`!"); + return true; + } private boolean checkPerms(IMessage message) { if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { @@ -123,9 +133,9 @@ public class ChannelconCommand extends ICommand2DC { } @Override - public String[] getHelpText(Method method) { + public String[] getHelpText(Method method, Command2.Subcommand ann) { return new String[]{ // - "---- Channel connect ---", // + "Channel connect", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "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 .", // diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java index 4c0a62a..3d1b52f 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCustom.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.ChatRoom; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.lib.TBMCSystemChatEvent; import lombok.NonNull; @@ -12,6 +13,7 @@ import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; public class MCChatCustom { /** @@ -19,7 +21,11 @@ public class MCChatCustom { */ static ArrayList lastmsgCustom = new ArrayList<>(); - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel, IUser user, DiscordConnectedPlayer dcp, int toggles, List brtoggles) { + public static void addCustomChat(IChannel 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); + } val lmd = new CustomLMD(channel, user, groupid, mcchannel, dcp, toggles, brtoggles); lastmsgCustom.add(lmd); } @@ -35,7 +41,13 @@ public class MCChatCustom { public static boolean removeCustomChat(IChannel channel) { MCChatUtils.lastmsgfromd.remove(channel.getLongID()); - return lastmsgCustom.removeIf(lmd -> lmd.channel.getLongID() == channel.getLongID()); + return lastmsgCustom.removeIf(lmd -> { + if (lmd.channel.getLongID() != channel.getLongID()) + return false; + if (lmd.mcchannel instanceof ChatRoom) + ((ChatRoom) lmd.mcchannel).leaveRoom(lmd.dcp); + return true; + }); } public static List getCustomChats() { @@ -47,10 +59,10 @@ public class MCChatCustom { public final Channel mcchannel; public final DiscordConnectedPlayer dcp; public int toggles; - public List brtoggles; + public Set brtoggles; private CustomLMD(@NonNull IChannel channel, @NonNull IUser user, - @NonNull String groupid, @NonNull Channel mcchannel, @NonNull DiscordConnectedPlayer dcp, int toggles, List brtoggles) { + @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/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 069ac47..2fc89da 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -64,7 +64,7 @@ public class MinecraftChatModule extends Component { 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.toList())); + MCChatCustom.addCustomChat(ch, groupid, mcch.get(), user, dcp, toggles, brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::get).filter(Objects::nonNull).collect(Collectors.toSet())); }); } } -- 2.30.2 From 325b094bf7903e8f35fd5853645bdaa758cc0c9d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 22 Feb 2019 00:44:13 +0100 Subject: [PATCH 046/108] Converted all commands Well, haven't finished the role command --- .../discordplugin/AnnouncerModule.java | 2 +- .../discordplugin/DiscordPlugin.java | 11 +- .../GeneralEventBroadcasterModule.java | 3 +- .../discordplugin/commands/Command2DC.java | 18 +-- .../commands/ConnectCommand.java | 137 ++++++++---------- .../discordplugin/commands/DebugCommand.java | 23 ++- .../commands/DiscordCommandBase.java | 61 -------- .../discordplugin/commands/HelpCommand.java | 56 +++---- .../exceptions/ExceptionListenerModule.java | 2 +- .../discordplugin/fun/FunModule.java | 2 +- .../listeners/CommandListener.java | 11 -- .../discordplugin/mcchat/MCChatCommand.java | 46 +++--- .../mcchat/MinecraftChatModule.java | 4 +- .../discordplugin/role/GameRoleModule.java | 5 +- .../discordplugin/role/RoleCommand.java | 16 +- 15 files changed, 130 insertions(+), 267 deletions(-) delete mode 100755 src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java index 866635f..a4b8fda 100644 --- a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java @@ -16,7 +16,7 @@ import sx.blah.discord.handle.obj.IMessage; import java.io.File; import java.util.List; -public class AnnouncerModule extends Component { +public class AnnouncerModule extends Component { public ConfigData channel() { return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index feb43df..92bfcbb 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,15 +1,11 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; -import buttondevteam.discordplugin.commands.Command2DC; -import buttondevteam.discordplugin.commands.DiscordCommandBase; -import buttondevteam.discordplugin.commands.UserinfoCommand; -import buttondevteam.discordplugin.commands.VersionCommand; +import buttondevteam.discordplugin.commands.*; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; -import buttondevteam.discordplugin.mcchat.ChannelconCommand; import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; @@ -126,10 +122,11 @@ public class DiscordPlugin extends ButtonPlugin implements IListener Component.registerComponent(this, new FunModule()); new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCCHatModule is tested to be enabled - DiscordCommandBase.registerCommands(); getManager().registerCommand(new VersionCommand()); getManager().registerCommand(new UserinfoCommand()); - getManager().registerCommand(new ChannelconCommand()); + getManager().registerCommand(new HelpCommand()); + getManager().registerCommand(new DebugCommand()); + getManager().registerCommand(new ConnectCommand()); if (ResetMCCommand.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 diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index e8a71e7..9b57812 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -1,11 +1,12 @@ package buttondevteam.discordplugin.broadcaster; import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import lombok.Getter; -public class GeneralEventBroadcasterModule extends Component { +public class GeneralEventBroadcasterModule extends Component { private static @Getter boolean hooked = false; @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index e61d43f..c2decdb 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -3,26 +3,10 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.chat.Command2; -import java.util.HashMap; -import java.util.function.Function; - public class Command2DC extends Command2 { - private HashMap> subcommands = new HashMap<>(); - private HashMap, ParamConverter> paramConverters = new HashMap<>(); - - @Override - public void addParamConverter(Class cl, Function converter, String errormsg) { - addParamConverter(cl, converter, errormsg, paramConverters); - } - - @Override - public boolean handleCommand(Command2DCSender sender, String commandLine) throws Exception { - return handleCommand(sender, commandLine, subcommands, paramConverters); - } - @Override public void registerCommand(ICommand2DC command) { - registerCommand(command, subcommands, DiscordPlugin.getPrefix()); //Needs to be configurable for the helps + super.registerCommand(command, DiscordPlugin.getPrefix()); //Needs to be configurable for the helps } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index 6e16c09..54f63e0 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -1,76 +1,61 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; -import com.google.common.collect.HashBiMap; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import sx.blah.discord.handle.obj.IMessage; - -public class ConnectCommand extends DiscordCommandBase { - - @Override - public String getCommandName() { - return "connect"; - } - - /** - * Key: Minecraft name
- * Value: Discord ID - */ - public static HashBiMap WaitingToConnect = HashBiMap.create(); - - @Override - public boolean run(IMessage message, String args) { - if (args.length() == 0) - return false; - if (args.contains(" ")) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Too many arguments.\nUsage: " + DiscordPlugin.getPrefix() + "connect "); - return true; - } - if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getStringID()) + " with " + args); - WaitingToConnect.inverse().remove(message.getAuthor().getStringID()); - } - @SuppressWarnings("deprecation") - OfflinePlayer p = Bukkit.getOfflinePlayer(args); - if (p == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found"); - return true; - } - try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { - DiscordPlayer dp = pl.getAs(DiscordPlayer.class); - if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); - 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); - } - WaitingToConnect.put(p.getName(), message.getAuthor().getStringID()); - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Alright! Now accept the connection in Minecraft from the account " + args - + " before the next server restart. You can also adjust the Minecraft name you want to connect to with the same command."); - if (p.isOnline()) - ((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#" - + message.getAuthor().getDiscriminator() + " do /discord accept"); - return true; - } - - @Override - public String[] getHelpText() { - return new String[] { // - "---- Connect command ----", // - "This command lets you connect your account with a Minecraft account. This allows using the Minecraft chat and other things.", // - "Usage: /connect " // - }; - } - -} +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; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerBase; +import com.google.common.collect.HashBiMap; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import sx.blah.discord.handle.obj.IMessage; + +@CommandClass(helpText = { + "Connect command", // + "This command lets you connect your account with a Minecraft account. This allows using the Minecraft chat and other things.", // +}) +public class ConnectCommand extends ICommand2DC { + + /** + * Key: Minecraft name
+ * Value: Discord ID + */ + public static HashBiMap WaitingToConnect = HashBiMap.create(); + + @Command2.Subcommand + public boolean def(IMessage message, String Minecraftname) { + if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), + "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getStringID()) + " with " + Minecraftname); + WaitingToConnect.inverse().remove(message.getAuthor().getStringID()); + } + @SuppressWarnings("deprecation") + OfflinePlayer p = Bukkit.getOfflinePlayer(Minecraftname); + if (p == null) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found"); + return true; + } + try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { + DiscordPlayer dp = pl.getAs(DiscordPlayer.class); + if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) { + DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); + 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); + } + WaitingToConnect.put(p.getName(), message.getAuthor().getStringID()); + 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."); + if (p.isOnline()) + ((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#" + + message.getAuthor().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 b37e2b8..c623a63 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -2,25 +2,20 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.listeners.CommonListeners; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; import sx.blah.discord.handle.obj.IMessage; -public class DebugCommand extends DiscordCommandBase { - @Override - public String getCommandName() { - return "debug"; - } - - @Override - public boolean run(IMessage message, String args) { - if (message.getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L))) +@CommandClass(helpText = { + "Switches debug mode." +}) +public class DebugCommand extends ICommand2DC { + @Command2.Subcommand + public boolean def(IMessage message, String args) { + if (message.getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L))) //TODO: Make configurable message.reply("Debug " + (CommonListeners.debug() ? "enabled" : "disabled")); else message.reply("You need to be a moderator to use this command."); return true; } - - @Override - public String[] getHelpText() { - return new String[]{"Switches debug mode."}; - } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java deleted file mode 100755 index 61d5fa1..0000000 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ /dev/null @@ -1,61 +0,0 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.mcchat.MCChatCommand; -import buttondevteam.lib.TBMCCoreAPI; -import sx.blah.discord.handle.obj.IMessage; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.stream.Collectors; - -import static buttondevteam.discordplugin.listeners.CommonListeners.debug; - -public abstract class DiscordCommandBase { - public abstract String getCommandName(); - - public abstract boolean run(IMessage message, String args); - - public abstract String[] getHelpText(); - - static final HashMap commands = new HashMap(); - - public static void registerCommands() { - commands.put("connect", new ConnectCommand()); // TODO: API for adding commands? - commands.put("help", new HelpCommand()); - commands.put("mcchat", new MCChatCommand()); - commands.put("debug", new DebugCommand()); - } - - public static void runCommand(String cmd, String args, IMessage message) { - debug("F"); //Not sure if needed - DiscordCommandBase command = commands.get(cmd); - //if(command==null) - // DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmd+" "+args); //TODO! - if (command == null) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Unknown command: " + cmd + " with args: " + args + "\nDo '" - + (message.getChannel().isPrivate() ? "" : message.getClient().getOurUser().mention() + " ") - + "help' for help"); - return; - } - debug("G"); - try { - if (!command.run(message, args)) - DiscordPlugin.sendMessageToChannel(message.getChannel(), Arrays.stream(command.getHelpText()).collect(Collectors.joining("\n"))); - } catch (Exception e) { - TBMCCoreAPI.SendException("An error occured while executing command " + cmd + "!", e); - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "An internal error occured while executing this command. For more technical details see the server-issues channel on the dev Discord."); - } - debug("H"); - } - - protected String[] splitargs(String args) { - return args.split("\\s+"); - } - - public static void registerCommand(String name, DiscordCommandBase dcb) { - commands.put(name, dcb); - } -} diff --git a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java index bcef6ea..0194dab 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java @@ -1,38 +1,18 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.DiscordPlugin; -import sx.blah.discord.handle.obj.IMessage; - -import java.util.stream.Collectors; - -public class HelpCommand extends DiscordCommandBase { - - @Override - public String getCommandName() { - return "help"; - } - - @Override - public boolean run(IMessage message, String args) { - DiscordCommandBase argdc; - if (args.length() == 0) - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Available commands:\n" + DiscordCommandBase.commands.values().stream() - .map(dc -> DiscordPlugin.getPrefix() + dc.getCommandName()).collect(Collectors.joining("\n"))); - else - DiscordPlugin.sendMessageToChannel(message.getChannel(), - (argdc = DiscordCommandBase.commands.get(args)) == null ? "Command not found: " + args - : String.join("\n", argdc.getHelpText())); - return true; - } - - @Override - public String[] getHelpText() { - return new String[] { // - "---- Help command ----", // - "Shows some info about a command or lists the available commands.", // - "Usage: " + DiscordPlugin.getPrefix() + "help [command]"// - }; - } - -} +package buttondevteam.discordplugin.commands; + +import buttondevteam.lib.chat.CommandClass; + +@CommandClass(helpText = { + "Help command", // + "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) + sender.sendMessage(getManager().getCommandsText()); + else + sender.sendMessage("Soon:tm:"); //TODO + return true; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 6821e6f..b868586 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -19,7 +19,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -public class ExceptionListenerModule extends Component implements Listener { +public class ExceptionListenerModule extends Component implements Listener { private List lastthrown = new ArrayList<>(); private List lastsourcemsg = new ArrayList<>(); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index c5bfd8d..d7fcc86 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -26,7 +26,7 @@ import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; -public class FunModule extends Component implements Listener { +public class FunModule extends Component implements Listener { private static FunModule mod; private static final String[] serverReadyStrings = new String[]{"In one week from now", // Ali diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 4bdf572..1980bdf 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -45,17 +45,6 @@ public class CommandListener { } catch (Exception e) { TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); } - /*int index = cmdwithargsString.indexOf(" "); - String cmd; - String args; - if (index == -1) { - cmd = cmdwithargsString; - args = ""; - } else { - cmd = cmdwithargsString.substring(0, index); - args = cmdwithargsString.substring(index + 1).trim(); //In case there are multiple spaces - } - DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message);*/ message.getChannel().setTypingStatus(false); return true; } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index 3c05f02..fbe4e38 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -2,44 +2,38 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.commands.Command2DCSender; +import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCCoreAPI; -import sx.blah.discord.handle.obj.IMessage; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; +import lombok.val; -public class MCChatCommand extends DiscordCommandBase { +@CommandClass(helpText = { + "MC Chat", + "This command enables or disables the Minecraft chat in private messages.", // + "It can be useful if you don't want your messages to be visible, for example when talking in a private channel.", // + "You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." // +}) +public class MCChatCommand extends ICommand2DC { - @Override - public String getCommandName() { - return "mcchat"; - } - - @Override //TODO: Only register if module is enabled - public boolean run(IMessage message, String args) { + @Command2.Subcommand + public boolean def(Command2DCSender sender, String args) { + val message = sender.getMessage(); if (!message.getChannel().isPrivate()) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "This command can only be issued in a direct message with the bot."); + 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)) { boolean mcchat = !user.isMinecraftChatEnabled(); MCChatPrivate.privateMCChat(message.getChannel(), mcchat, message.getAuthor(), user); - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Minecraft chat " + (mcchat // - ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // - : "disabled.")); + message.reply("Minecraft chat " + (mcchat // + ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // + : "disabled.")); } catch (Exception e) { TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e); } return true; - } - - @Override - public String[] getHelpText() { - return new String[] { // - DiscordPlugin.getPrefix() + "mcchat enables or disables the Minecraft chat in private messages.", // - "It can be useful if you don't want your messages to be visible, for example when talking in a private channel.", // - "You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." // - }; // TODO: Pin channel switching to indicate the current channel - } + } // TODO: Pin channel switching to indicate the current channel } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 2fc89da..2d6e50b 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -19,7 +19,7 @@ import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; -public class MinecraftChatModule extends Component { +public class MinecraftChatModule extends Component { private @Getter MCChatListener listener; public MCChatListener getListener() { //It doesn't want to generate @@ -45,6 +45,8 @@ public class MinecraftChatModule extends Component { DiscordPlugin.dc.getDispatcher().registerListener(listener); 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()); val chcons = getConfig().getConfig().getConfigurationSection("chcons"); if (chcons == null) //Fallback to old place diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 7bf3d2b..45fe9ec 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -3,7 +3,6 @@ package buttondevteam.discordplugin.role; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import lombok.val; @@ -19,12 +18,12 @@ import java.awt.*; import java.util.List; import java.util.stream.Collectors; -public class GameRoleModule extends Component { +public class GameRoleModule extends Component { public List GameRoles; @Override protected void enable() { - DiscordCommandBase.registerCommand("role", new RoleCommand(this)); + getPlugin().getManager().registerCommand(new RoleCommand(this)); GameRoles = DiscordPlugin.mainServer.getRoles().stream().filter(this::isGameRole).map(IRole::getName).collect(Collectors.toList()); } diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 1534e2b..822eb1a 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -2,15 +2,18 @@ package buttondevteam.discordplugin.role; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; -import buttondevteam.discordplugin.commands.DiscordCommandBase; +import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; import sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IRole; import java.util.List; import java.util.stream.Collectors; -public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's parser +@CommandClass +public class RoleCommand extends ICommand2DC { //TODO private GameRoleModule grm; @@ -18,13 +21,8 @@ public class RoleCommand extends DiscordCommandBase { //TODO: Use Command2's par this.grm = grm; } - @Override - public String getCommandName() { - return "role"; - } - - @Override - public boolean run(IMessage message, String args) { + @Command2.Subcommand + public boolean def(IMessage message, String args) { if (args.length() == 0) return false; String[] argsa = splitargs(args); -- 2.30.2 From ca5fb90774c88ea790d3ce2cf194083c857dd16b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 23 Feb 2019 00:33:10 +0100 Subject: [PATCH 047/108] Command system fixes In encounter order: Lowercasing message first character on the sender Command sender fixes Mention deleting fixed if there is no space Added error handler to the message receive event Converted role command --- .../commands/Command2DCSender.java | 7 +- .../commands/ConnectCommand.java | 5 +- .../discordplugin/commands/DebugCommand.java | 9 +- .../listeners/CommandListener.java | 9 +- .../listeners/CommonListeners.java | 23 ++-- .../discordplugin/role/RoleCommand.java | 110 ++++++++---------- 6 files changed, 80 insertions(+), 83 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index a2281f9..bdff52d 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -12,11 +12,14 @@ public class Command2DCSender implements Command2Sender { @Override public void sendMessage(String message) { - this.message.reply(DPUtils.sanitizeString(message)); + if (message.length() == 0) return; + message = DPUtils.sanitizeString(message); + message = Character.toLowerCase(message.charAt(0)) + message.substring(1); + this.message.reply(message); } @Override public void sendMessage(String[] message) { - this.message.reply(DPUtils.sanitizeString(String.join("\n", message))); + sendMessage(String.join("\n", message)); } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index 54f63e0..4e37e35 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -8,10 +8,10 @@ import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayerBase; import com.google.common.collect.HashBiMap; +import lombok.val; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import sx.blah.discord.handle.obj.IMessage; @CommandClass(helpText = { "Connect command", // @@ -26,7 +26,8 @@ public class ConnectCommand extends ICommand2DC { public static HashBiMap WaitingToConnect = HashBiMap.create(); @Command2.Subcommand - public boolean def(IMessage message, String Minecraftname) { + public boolean def(Command2DCSender sender, String Minecraftname) { + val message = sender.getMessage(); if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "Replacing " + WaitingToConnect.inverse().get(message.getAuthor().getStringID()) + " with " + Minecraftname); diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index c623a63..26fc30e 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -4,18 +4,17 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; -import sx.blah.discord.handle.obj.IMessage; @CommandClass(helpText = { "Switches debug mode." }) public class DebugCommand extends ICommand2DC { @Command2.Subcommand - public boolean def(IMessage message, String args) { - if (message.getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L))) //TODO: Make configurable - message.reply("Debug " + (CommonListeners.debug() ? "enabled" : "disabled")); + public boolean def(Command2DCSender sender, String args) { + if (sender.getMessage().getAuthor().hasRole(DiscordPlugin.mainServer.getRoleByID(126030201472811008L))) //TODO: Make configurable + sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); else - message.reply("You need to be a moderator to use this command."); + sender.sendMessage("you need to be a moderator to use this command."); return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 1980bdf..4f99d35 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -53,9 +53,12 @@ public class CommandListener { 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()); - //noinspection StatementWithEmptyBody - for (; i < cmdwithargs.length() && cmdwithargs.charAt(i) == ' '; i++) - ; //Removes any space before the command + if (i == -1) + i = mention.length(); + else + //noinspection StatementWithEmptyBody + 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 } else diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index 9b60fc3..fa11f78 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.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import lombok.val; import sx.blah.discord.api.events.IListener; @@ -35,16 +36,20 @@ public class CommonListeners { return; if (FunModule.executeMemes(event.getMessage())) return; - boolean handled = false; - if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat + try { + boolean handled = false; + if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat || event.getMessage().getContent().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); + 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); + } } }, new IListener() { @Override diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 822eb1a..19d78cf 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -2,18 +2,18 @@ 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 sx.blah.discord.handle.obj.IMessage; import sx.blah.discord.handle.obj.IRole; import java.util.List; import java.util.stream.Collectors; @CommandClass -public class RoleCommand extends ICommand2DC { //TODO +public class RoleCommand extends ICommand2DC { private GameRoleModule grm; @@ -21,78 +21,64 @@ public class RoleCommand extends ICommand2DC { //TODO this.grm = grm; } + @Command2.Subcommand(helpText = { + "Add role", + "This command adds a role to your account." + }) + public boolean add(Command2DCSender sender, @Command2.TextArg String rolename) { + final IRole role = checkAndGetRole(sender, rolename); + if (role == null) + return true; + try { + DPUtils.perform(() -> sender.getMessage().getAuthor().addRole(role)); + sender.sendMessage("added role."); + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while adding role!", e); + sender.sendMessage("an error occured while adding the role."); + } + return true; + } + + @Command2.Subcommand(helpText = { + "Remove role", + "This command removes a role from your account." + }) + public boolean remove(Command2DCSender sender, @Command2.TextArg String rolename) { + final IRole role = checkAndGetRole(sender, rolename); + if (role == null) + return true; + try { + DPUtils.perform(() -> sender.getMessage().getAuthor().removeRole(role)); + sender.sendMessage("removed role."); + } catch (Exception e) { + TBMCCoreAPI.SendException("Error while removing role!", e); + sender.sendMessage("an error occured while removing the role."); + } + return true; + } + @Command2.Subcommand - public boolean def(IMessage message, String args) { - if (args.length() == 0) - return false; - String[] argsa = splitargs(args); - if (argsa[0].equalsIgnoreCase("add")) { - final IRole role = checkAndGetRole(message, argsa, "This command adds a role to your account."); - if (role == null) - return true; - try { - DPUtils.perform(() -> message.getAuthor().addRole(role)); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added role."); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while adding role!", e); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while adding the role."); - } - } else if (argsa[0].equalsIgnoreCase("remove")) { - final IRole role = checkAndGetRole(message, argsa, "This command removes a role from your account."); - if (role == null) - return true; - try { - DPUtils.perform(() -> message.getAuthor().removeRole(role)); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed role."); - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while removing role!", e); - DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while removing the role."); - } - } else if (argsa[0].equalsIgnoreCase("list")) { - listRoles(message); - } else return false; - return true; + public void list(Command2DCSender sender) { + sender.sendMessage("list of roles:\n" + grm.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); } - private void listRoles(IMessage message) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "List of roles:\n" + grm.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); - } - - private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) { - if (argsa.length < 2) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), usage + "\nUsage: " + argsa[0] + " "); + private IRole checkAndGetRole(Command2DCSender sender, String rolename) { + if (!grm.GameRoles.contains(rolename)) { + sender.sendMessage("that role cannot be found."); + list(sender); return null; } - StringBuilder rolename = new StringBuilder(argsa[1]); - for (int i = 2; i < argsa.length; i++) - rolename.append(" ").append(argsa[i]); - if (!grm.GameRoles.contains(rolename.toString())) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "That role cannot be found."); - listRoles(message); - return null; - } - final List roles = DiscordPlugin.mainServer.getRolesByName(rolename.toString()); + final List roles = DiscordPlugin.mainServer.getRolesByName(rolename); if (roles.size() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The specified role cannot be found on Discord! Removing from the list."); - grm.GameRoles.remove(rolename.toString()); + sender.sendMessage("the specified role cannot be found on Discord! Removing from the list."); + grm.GameRoles.remove(rolename); return null; } if (roles.size() > 1) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "There are more roles with this name. Why are there more roles with this name?"); + sender.sendMessage("there are multiple roles with this name. Why are there multiple roles with this name?"); return null; } return roles.get(0); } - @Override - public String[] getHelpText() { - return new String[]{ // - "Add or remove roles from yourself.", // - "Usage: " + DiscordPlugin.getPrefix() + "role add|remove or role list", // - }; - } - } -- 2.30.2 From 0f1f7b4ead3d340340b6e1fabb0b86620cb1a693 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 1 Mar 2019 18:01:32 +0100 Subject: [PATCH 048/108] Better handling of missing token Also moved the token's location --- .../discordplugin/DiscordPlugin.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 92bfcbb..7063c39 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -23,6 +23,7 @@ import lombok.Getter; import lombok.val; import net.milkbowl.vault.permission.Permission; 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; @@ -79,7 +80,24 @@ public class DiscordPlugin extends ButtonPlugin implements IListener plugin = this; manager = new Command2DC(); ClientBuilder cb = new ClientBuilder(); - cb.withToken(Files.readFirstLine(new File("TBMC", "Token.txt"), StandardCharsets.UTF_8)); + 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); + + 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) { @@ -177,6 +195,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener @Override public void pluginPreDisable() { + if (ChromaBot.getInstance() == null) return; //Failed to load EmbedObject embed; if (ResetMCCommand.resetting) embed = new EmbedBuilder().withColor(Color.ORANGE).withTitle("Discord plugin restarting").build(); @@ -207,6 +226,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener public void pluginDisable() { MCChatPrivate.logoutAll(); getConfig().set("serverup", false); + if (ChromaBot.getInstance() == null) return; //Failed to load saveConfig(); try { -- 2.30.2 From 14c42614d89cd273450dacc47e29ceed400a9671 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 2 Mar 2019 19:04:38 +0100 Subject: [PATCH 049/108] #bot mention ch null handling, limiting tries Won't try to get channels forever, since they may be set incorrectly --- src/main/java/buttondevteam/discordplugin/DPUtils.java | 6 ++++-- .../java/buttondevteam/discordplugin/DiscordPlugin.java | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index e415298..fba8a7b 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -126,8 +126,10 @@ public final class DPUtils { * @return The string for mentioning the channel */ public static String botmention() { - if (DiscordPlugin.plugin == null) return "#bot"; - return DiscordPlugin.plugin.CommandChannel().get().mention(); + IChannel channel; + if (DiscordPlugin.plugin == null + || (channel = DiscordPlugin.plugin.CommandChannel().get()) == null) return "#bot"; + return channel.mention(); } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 7063c39..fd5f2fa 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -43,6 +43,7 @@ import java.nio.charset.StandardCharsets; 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 { @@ -116,7 +117,14 @@ public class DiscordPlugin extends ButtonPlugin implements IListener 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 or dev server not found! Set ID and do /discord reset"); + return; + } if (mainServer == null || devServer == null) { mainServer = event.getClient().getGuildByID(125813020357165056L); devServer = event.getClient().getGuildByID(219529124321034241L); -- 2.30.2 From cadb53d886e602196ad13e18a8481d9805ddcf7f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Mar 2019 02:07:56 +0100 Subject: [PATCH 050/108] Made the plugin work cleanly (#51) Clean install works pretty well Automatically setting first server as main server Removed devServer variable, getting the guild from the channels Disabling each component that doesn't have its channel(s)/role(s) set correctly (unless it's not required) Removed redundant variable from the FunModule Correctly handling missing channel settings in some places Checking any role position for game roles, not just "ChromaBot" The bot is playing Minecraft now Always giving permission for commands for now --- .../discordplugin/AnnouncerModule.java | 1 + .../buttondevteam/discordplugin/DPUtils.java | 41 +++++++++++++++++-- .../discordplugin/DiscordPlugin.java | 26 +++++++----- .../discordplugin/commands/Command2DC.java | 3 +- .../exceptions/ExceptionListenerModule.java | 17 +++++--- .../discordplugin/fun/FunModule.java | 27 +++++------- .../listeners/CommonListeners.java | 3 +- .../mcchat/ChannelconCommand.java | 2 +- .../discordplugin/mcchat/MCListener.java | 9 +++- .../mcchat/MinecraftChatModule.java | 1 + .../discordplugin/role/GameRoleModule.java | 25 ++++++----- 11 files changed, 104 insertions(+), 51 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java index a4b8fda..d0efe1e 100644 --- a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java @@ -45,6 +45,7 @@ public class AnnouncerModule extends Component { @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, channel(), modChannel())) return; stop = false; //If not the first time DPUtils.performNoWait(() -> { try { diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index fba8a7b..48d5963 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -1,10 +1,13 @@ package buttondevteam.discordplugin; +import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.IHaveConfig; 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; @@ -114,10 +117,14 @@ public final class DPUtils { } 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) { return config.getDataPrimDef(key, defName, name -> { - val roles = DiscordPlugin.mainServer.getRolesByName((String) name); - return roles.size() > 0 ? roles.get(0) : null; //TODO: May not handle null properly - }, IIDLinkedObject::getLongID); //We can afford to search for the channel in the cache once (instead of using mainServer) + val roles = guild.getRolesByName((String) name); + return roles.size() > 0 ? roles.get(0) : null; + }, IIDLinkedObject::getLongID); } /** @@ -132,4 +139,32 @@ public final class DPUtils { return channel.mention(); } + /** + * 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 configs The configs to check for null + * @return Whether the component got disabled and a warning logged + */ + public static boolean disableIfConfigError(@Nullable Component component, ConfigData... configs) { + for (val config : configs) { + if (config.get() == null) { + 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); + } 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 fd5f2fa..498ba31 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -108,7 +108,6 @@ public class DiscordPlugin extends ButtonPlugin implements IListener } public static IGuild mainServer; - public static IGuild devServer; private static volatile BukkitTask task; private static volatile boolean sent = false; @@ -122,17 +121,22 @@ public class DiscordPlugin extends ButtonPlugin implements IListener tries.incrementAndGet(); if (tries.get() > 10) { //5 seconds task.cancel(); - getLogger().severe("Main or dev server not found! Set ID and do /discord reset"); + 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; } - if (mainServer == null || devServer == null) { - mainServer = event.getClient().getGuildByID(125813020357165056L); - devServer = event.getClient().getGuildByID(219529124321034241L); - } - if (mainServer == null || devServer == null) - return; // Retry + 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, "Chromacraft"); + dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "Minecraft"); } else { dc.changePresence(StatusType.ONLINE, ActivityType.PLAYING, "testing"); } @@ -140,6 +144,8 @@ public class DiscordPlugin extends ButtonPlugin implements IListener 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()); @@ -242,7 +248,7 @@ public class DiscordPlugin extends ButtonPlugin implements IListener ChromaBot.delete(); dc.changePresence(StatusType.IDLE, ActivityType.PLAYING, "Chromacraft"); //No longer using the same account for testing dc.logout(); - mainServer = devServer = null; //Fetch servers and channels again + //Configs are emptied so channels and servers are fetched again sent = false; } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java index c2decdb..a0b8fda 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DC.java @@ -11,6 +11,7 @@ public class Command2DC extends Command2 { @Override public boolean hasPermission(Command2DCSender sender, ICommand2DC command) { - return !command.isModOnly() || sender.getMessage().getAuthor().hasRole(DiscordPlugin.plugin.ModRole().get()); + //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/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index b868586..5d21bb1 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -12,6 +12,7 @@ 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 java.util.ArrayList; @@ -43,15 +44,14 @@ public class ExceptionListenerModule extends Component implements e.setHandled(); } - private static IRole coderRole; - private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; try { - if (coderRole == null) - coderRole = DiscordPlugin.devServer.getRolesByName("Coder").get(0); + IChannel channel = getChannel(); + assert channel != null; + IRole coderRole = instance.pingRole(channel.getGuild()).get(); StringBuilder sb = TBMCCoreAPI.IsTestServer() ? new StringBuilder() - : new StringBuilder(coderRole.mention()).append("\n"); + : new StringBuilder(coderRole == null ? "" : coderRole.mention()).append("\n"); sb.append(sourcemessage).append("\n"); sb.append("```").append("\n"); String stackTrace = Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")) @@ -61,7 +61,7 @@ public class ExceptionListenerModule extends Component implements stackTrace = stackTrace.substring(0, 1800); sb.append(stackTrace).append("\n"); sb.append("```"); - DiscordPlugin.sendMessageToChannel(getChannel(), sb.toString()); //Instance isn't null here + DiscordPlugin.sendMessageToChannel(channel, sb.toString()); //Instance isn't null here } catch (Exception ex) { ex.printStackTrace(); } @@ -78,8 +78,13 @@ public class ExceptionListenerModule extends Component implements return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); } + private ConfigData pingRole(IGuild guild) { + return DPUtils.roleData(getConfig(), "pingRole", "Coder", guild); + } + @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, channel())) return; instance = this; Bukkit.getPluginManager().registerEvents(new ExceptionListenerModule(), getPlugin()); TBMCCoreAPI.RegisterEventsForExceptions(new DebugMessageListener(), getPlugin()); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index d7fcc86..f5adf0d 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -13,10 +13,7 @@ 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.IChannel; -import sx.blah.discord.handle.obj.IMessage; -import sx.blah.discord.handle.obj.IRole; -import sx.blah.discord.handle.obj.StatusType; +import sx.blah.discord.handle.obj.*; import sx.blah.discord.util.EmbedBuilder; import java.util.ArrayList; @@ -27,8 +24,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; public class FunModule extends Component implements Listener { - private static FunModule mod; - 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 @@ -68,7 +63,6 @@ public class FunModule extends Component implements Listener { @Override protected void enable() { - mod = this; registerListener(this); } @@ -99,7 +93,7 @@ public class FunModule extends Component implements Listener { return true; //Handled } lastlistp = (short) Bukkit.getOnlinePlayers().size(); //Didn't handle - if (mod.serverReady().get()) { + if (fm.serverReady().get()) { if (!TBMCCoreAPI.IsTestServer() && Arrays.stream(serverReadyQuestions).anyMatch(msglowercased::contains)) { int next; @@ -118,11 +112,8 @@ public class FunModule extends Component implements Listener { ListC = 0; } - private ConfigData fullHouseDevRole() { - return getConfig().getDataPrimDef("fullHouseDevRole", "Developer", name -> { - val list = DiscordPlugin.devServer.getRolesByName((String) name); - return list.size() > 0 ? list.get(0) : null; - }, IRole::getName); + private ConfigData fullHouseDevRole(IGuild guild) { + return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); } @@ -135,17 +126,19 @@ public class FunModule extends Component implements Listener { public static void handleFullHouse(PresenceUpdateEvent event) { val fm = ComponentManager.getIfEnabled(FunModule.class); if (fm == null) return; - val devrole = fm.fullHouseDevRole().get(); + val channel = fm.fullHouseChannel().get(); + if (channel == null) return; + val devrole = fm.fullHouseDevRole(channel.getGuild()).get(); if (devrole == null) return; if (event.getOldPresence().getStatus().equals(StatusType.OFFLINE) && !event.getNewPresence().getStatus().equals(StatusType.OFFLINE) - && event.getUser().getRolesForGuild(DiscordPlugin.devServer).stream() + && event.getUser().getRolesForGuild(channel.getGuild()).stream() .anyMatch(r -> r.getLongID() == devrole.getLongID()) - && DiscordPlugin.devServer.getUsersByRole(devrole).stream() + && channel.getGuild().getUsersByRole(devrole).stream() .noneMatch(u -> u.getPresence().getStatus().equals(StatusType.OFFLINE)) && lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime()) && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) { - DiscordPlugin.sendMessageToChannel(mod.fullHouseChannel().get(), "Full house!", + 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") diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java index fa11f78..5350b32 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommonListeners.java @@ -38,7 +38,8 @@ public class CommonListeners { return; try { boolean handled = false; - if (event.getChannel().getLongID() == DiscordPlugin.plugin.CommandChannel().get().getLongID() //If mentioned, that's higher than chat + 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 handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here if (handled) return; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index ceb184b..2bd2bb6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -144,7 +144,7 @@ public class ChannelconCommand extends ICommand2DC { "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() + ".", // - "Invite link: " // + "Invite link: " // TODO: Set correct client ID }; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index fbf9d27..6cc9f5b 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -108,6 +108,7 @@ class MCListener implements Listener { try { DPUtils.performNoWait(() -> { final IRole role = muteRole().get(); + if (role == null) return; final CommandSource source = e.getAffected().getSource(); if (!source.isPlayer()) return; @@ -120,7 +121,11 @@ class MCListener implements Listener { user.addRole(role); else user.removeRole(role); - DiscordPlugin.sendMessageToChannel(module.modlogChannel().get(), (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName()); + val modlog = module.modlogChannel().get(); + String msg = (e.getValue() ? "M" : "Unm") + "uted user: " + user.getName(); + if (modlog != null) + DiscordPlugin.sendMessageToChannel(modlog, msg); + DPUtils.getLogger().info(msg); }); } catch (DiscordException | MissingPermissionsException ex) { TBMCCoreAPI.SendException("Failed to give/take Muted role to player " + e.getAffected().getName() + "!", @@ -143,7 +148,7 @@ 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 - MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); + MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); //TODO: Don't require emoji } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 2d6e50b..789fd2d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -41,6 +41,7 @@ public class MinecraftChatModule extends Component { @Override protected void enable() { + if (DPUtils.disableIfConfigError(this, chatChannel())) return; listener = new MCChatListener(this); DiscordPlugin.dc.getDispatcher().registerListener(listener); TBMCCoreAPI.RegisterEventsForExceptions(listener, getPlugin()); diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 45fe9ec..8806647 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -40,30 +40,34 @@ public class GameRoleModule extends Component { val grm = ComponentManager.getIfEnabled(GameRoleModule.class); if (grm == null) return; val GameRoles = grm.GameRoles; + val logChannel = grm.logChannel().get(); if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { if (roleEvent.getRole().isDeleted() || !grm.isGameRole(roleEvent.getRole())) return; //Deleted or not a game role GameRoles.add(roleEvent.getRole().getName()); - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + roleEvent.getRole().getName() + " as game role. If you don't want this, change the role's color from the default."); + 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."); }, 100); } else if (roleEvent instanceof RoleDeleteEvent) { - if (GameRoles.remove(roleEvent.getRole().getName())) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + roleEvent.getRole().getName() + " as a game role."); + if (GameRoles.remove(roleEvent.getRole().getName()) && logChannel != null) + DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + roleEvent.getRole().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())) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); + if (GameRoles.remove(event.getOldRole().getName()) && logChannel != null) + DiscordPlugin.sendMessageToChannel(logChannel, "Removed " + event.getOldRole().getName() + " as a game role because it's color changed."); } else { if (GameRoles.contains(event.getOldRole().getName()) && event.getOldRole().getName().equals(event.getNewRole().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 - if (removed) - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); - else - DiscordPlugin.sendMessageToChannel(grm.logChannel().get(), "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + if (logChannel != null) { + if (removed) + DiscordPlugin.sendMessageToChannel(logChannel, "Changed game role from " + event.getOldRole().getName() + " to " + event.getNewRole().getName() + "."); + else + DiscordPlugin.sendMessageToChannel(logChannel, "Added " + event.getNewRole().getName() + " as game role because it has the default color."); + } } } } @@ -73,6 +77,7 @@ public class GameRoleModule extends Component { return false; //Only allow on the main server val rc = new Color(149, 165, 166, 0); return r.getColor().equals(rc) - && r.getPosition() < DiscordPlugin.mainServer.getRoleByID(234343495735836672L).getPosition(); //Below the ChromaBot role + && DiscordPlugin.dc.getOurUser().getRolesForGuild(DiscordPlugin.mainServer) + .stream().anyMatch(or -> r.getPosition() < or.getPosition()); //Below one of our roles } } -- 2.30.2 From b39a57124600237b4309cc448f09318081b43f04 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Mar 2019 23:09:27 +0100 Subject: [PATCH 051/108] Made excluded plugins configurable Using configable mod role in debug command Also moved the AnnouncerModule --- .../discordplugin/DiscordPlugin.java | 1 + .../{ => announcer}/AnnouncerModule.java | 5 +- .../discordplugin/commands/DebugCommand.java | 2 +- .../discordplugin/listeners/MCListener.java | 73 ------------------- .../discordplugin/mcchat/MCChatPrivate.java | 6 +- .../discordplugin/mcchat/MCChatUtils.java | 71 ++++++++++++++++++ .../discordplugin/mcchat/MCListener.java | 4 +- .../mcchat/MinecraftChatModule.java | 19 +++++ 8 files changed, 100 insertions(+), 81 deletions(-) rename src/main/java/buttondevteam/discordplugin/{ => announcer}/AnnouncerModule.java (96%) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 498ba31..6d71070 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin; +import buttondevteam.discordplugin.announcer.AnnouncerModule; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.discordplugin.commands.*; import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; diff --git a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java similarity index 96% rename from src/main/java/buttondevteam/discordplugin/AnnouncerModule.java rename to src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index d0efe1e..c434dce 100644 --- a/src/main/java/buttondevteam/discordplugin/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -1,5 +1,8 @@ -package buttondevteam.discordplugin; +package buttondevteam.discordplugin.announcer; +import buttondevteam.discordplugin.DPUtils; +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index 26fc30e..2cf87fb 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -11,7 +11,7 @@ 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.mainServer.getRoleByID(126030201472811008L))) //TODO: Make configurable + 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."); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 2f99b56..c23b8fa 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -5,21 +5,11 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; import buttondevteam.lib.player.TBMCPlayerJoinEvent; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.event.Event; import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.plugin.AuthorNagException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredListener; import sx.blah.discord.handle.obj.IUser; -import java.util.Arrays; -import java.util.logging.Level; - public class MCListener implements Listener { @EventHandler public void onPlayerJoin(TBMCPlayerJoinEvent e) { @@ -50,67 +40,4 @@ public class MCListener implements Listener { public void onServerCommand(ServerCommandEvent e) { DiscordPlugin.Restart = !e.getCommand().equalsIgnoreCase("stop"); // The variable is always true except if stopped } - - private static final String[] EXCLUDED_PLUGINS = {"ProtocolLib", "LibsDisguises", "JourneyMapServer"}; //TODO: Make configurable - - public static void callEventExcludingSome(Event event) { - callEventExcluding(event, false, EXCLUDED_PLUGINS); - } - - /** - * Calls an event with the given details. - *

- * This method only synchronizes when the event is not asynchronous. - * - * @param event Event details - * @param only Flips the operation and includes the listed plugins - * @param plugins The plugins to exclude. Not case sensitive. - */ - public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit - if (event.isAsynchronous()) { - if (Thread.holdsLock(Bukkit.getPluginManager())) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); - } - if (Bukkit.getServer().isPrimaryThread()) { - throw new IllegalStateException( - event.getEventName() + " cannot be triggered asynchronously from primary server thread."); - } - fireEventExcluding(event, only, plugins); - } else { - synchronized (Bukkit.getPluginManager()) { - fireEventExcluding(event, only, plugins); - } - } - } - - private static void fireEventExcluding(Event event, boolean only, String... plugins) { - HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API - RegisteredListener[] listeners = handlers.getRegisteredListeners(); - val server = Bukkit.getServer(); - - for (RegisteredListener registration : listeners) { - if (!registration.getPlugin().isEnabled() - || Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName()))) - continue; // Modified to exclude plugins - - try { - registration.callEvent(event); - } catch (AuthorNagException ex) { - Plugin plugin = registration.getPlugin(); - - if (plugin.isNaggable()) { - plugin.setNaggable(false); - - server.getLogger().log(Level.SEVERE, - String.format("Nag author(s): '%s' of '%s' about the following: %s", - plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), - ex.getMessage())); - } - } catch (Throwable ex) { - server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " - + registration.getPlugin().getDescription().getFullName(), ex); - } - } - } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 877d415..7d87376 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -15,8 +15,6 @@ import sx.blah.discord.handle.obj.IUser; import java.util.ArrayList; -import static buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome; - public class MCChatPrivate { /** @@ -60,11 +58,11 @@ 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 - callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync + MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(valueEntry.getValue(), "")); //This is sync MCChatUtils.ConnectedSenders.clear(); } private static void callEventSync(Event event) { - Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> callEventExcludingSome(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 56582ba..3f04e56 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -8,17 +8,25 @@ import buttondevteam.lib.TBMCSystemChatEvent; import io.netty.util.collection.LongObjectHashMap; import lombok.RequiredArgsConstructor; import lombok.experimental.var; +import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +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; import java.util.HashMap; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -213,6 +221,69 @@ public class MCChatUtils { //If it gets here, it's sending a message to a non-chat channel } + public static void callEventExcludingSome(Event event) { + if (notEnabled()) return; + callEventExcluding(event, false, module.excludedPlugins().get()); + } + + /** + * Calls an event with the given details. + *

+ * This method only synchronizes when the event is not asynchronous. + * + * @param event Event details + * @param only Flips the operation and includes the listed plugins + * @param plugins The plugins to exclude. Not case sensitive. + */ + @SuppressWarnings("WeakerAccess") + public static void callEventExcluding(Event event, boolean only, String... plugins) { // Copied from Spigot-API and modified a bit + if (event.isAsynchronous()) { + if (Thread.holdsLock(Bukkit.getPluginManager())) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from inside synchronized code."); + } + if (Bukkit.getServer().isPrimaryThread()) { + throw new IllegalStateException( + event.getEventName() + " cannot be triggered asynchronously from primary server thread."); + } + fireEventExcluding(event, only, plugins); + } else { + synchronized (Bukkit.getPluginManager()) { + fireEventExcluding(event, only, plugins); + } + } + } + + private static void fireEventExcluding(Event event, boolean only, String... plugins) { + HandlerList handlers = event.getHandlers(); // Code taken from SimplePluginManager in Spigot-API + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + val server = Bukkit.getServer(); + + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled() + || Arrays.stream(plugins).anyMatch(p -> only ^ p.equalsIgnoreCase(registration.getPlugin().getName()))) + continue; // Modified to exclude plugins + + try { + registration.callEvent(event); + } catch (AuthorNagException ex) { + Plugin plugin = registration.getPlugin(); + + if (plugin.isNaggable()) { + plugin.setNaggable(false); + + server.getLogger().log(Level.SEVERE, + String.format("Nag author(s): '%s' of '%s' about the following: %s", + plugin.getDescription().getAuthors(), plugin.getDescription().getFullName(), + ex.getMessage())); + } + } catch (Throwable ex) { + server.getLogger().log(Level.SEVERE, "Could not pass event " + event.getEventName() + " to " + + registration.getPlugin().getDescription().getFullName(), ex); + } + } + } + @RequiredArgsConstructor public static class LastMsgData { public IMessage message; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 6cc9f5b..981446d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -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 -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); + .ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerQuitEvent(dcp, ""))); } @EventHandler(priority = EventPriority.LOWEST) @@ -70,7 +70,7 @@ class MCListener implements Listener { Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> MCChatUtils.ConnectedSenders.values().stream().flatMap(v -> v.values().stream()) .filter(s -> s.getUniqueId().equals(e.getPlayer().getUniqueId())).findAny() - .ifPresent(dcp -> buttondevteam.discordplugin.listeners.MCListener.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); + .ifPresent(dcp -> MCChatUtils.callEventExcludingSome(new PlayerJoinEvent(dcp, "")))); Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.GetPlayer().PlayerName().get() + " left the game"; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 789fd2d..509ea66 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -19,6 +19,9 @@ import java.util.Objects; import java.util.UUID; 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; @@ -26,19 +29,35 @@ public class MinecraftChatModule extends Component { return listener; } + /** + * 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! + */ public ConfigData> whitelistedCommands() { return getConfig().getData("whitelistedCommands", () -> Lists.newArrayList("list", "u", "shrug", "tableflip", "unflip", "mwiki", "yeehaw", "lenny", "rp", "plugins")); } + /** + * The channel to use as the public Minecraft chat - everything public gets broadcasted here + */ 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() { return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L); } + /** + * 0 * 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"}); + } + @Override protected void enable() { if (DPUtils.disableIfConfigError(this, chatChannel())) return; -- 2.30.2 From 2b4034b05f6322eef7559599c6b306839496c188 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 14 Mar 2019 16:40:58 +0100 Subject: [PATCH 052/108] NPE and 2 cmd fix --- .../buttondevteam/discordplugin/DPUtils.java | 1 + .../discordplugin/commands/UserinfoCommand.java | 16 ++++++++-------- .../discordplugin/mcchat/MCChatCommand.java | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 48d5963..c21cceb 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -122,6 +122,7 @@ public final class DPUtils { public static ConfigData roleData(IHaveConfig config, String key, String defName, IGuild 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); diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index 7954002..0433c81 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -22,22 +22,22 @@ import java.util.stream.Collectors; }) public class UserinfoCommand extends ICommand2DC { @Command2.Subcommand - public boolean def(Command2DCSender sender, @Command2.OptionalArg String args) { + public boolean def(Command2DCSender sender, @Command2.OptionalArg @Command2.TextArg String user) { val message = sender.getMessage(); IUser target = null; - if (args == null || args.length() == 0) + 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(); if (firstmention.isPresent()) target = firstmention.get(); - else if (args.contains("#")) { - String[] targettag = args.split("#"); + 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): " + args); + "The user cannot be found (by name): " + user); return true; } for (IUser ptarget : targets) { @@ -48,15 +48,15 @@ public class UserinfoCommand extends ICommand2DC { } if (target == null) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found (by discriminator): " + args + "(Found " + targets.size() + "The user cannot be found (by discriminator): " + user + "(Found " + targets.size() + " users with the name.)"); return true; } } else { - final List targets = getUsers(message, args); + final List targets = getUsers(message, user); if (targets.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), - "The user cannot be found on Discord: " + args); + "The user cannot be found on Discord: " + user); return true; } if (targets.size() > 1) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index fbe4e38..23af46f 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -18,7 +18,7 @@ import lombok.val; public class MCChatCommand extends ICommand2DC { @Command2.Subcommand - public boolean def(Command2DCSender sender, String args) { + 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."); -- 2.30.2 From 22bdc3fa620fa25b4b398a1ae4bf57a0f119cea0 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Mar 2019 14:49:27 +0100 Subject: [PATCH 053/108] YEEHAW fix, reload command --- .../discordplugin/mcchat/MCListener.java | 3 ++- .../mccommands/ReloadMCCommand.java | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 981446d..3ed7bcf 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -148,7 +148,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 - MCChatUtils.forAllMCChat(MCChatUtils.send(name + " <:YEEHAW:" + DiscordPlugin.mainServer.getEmojiByName("YEEHAW").getStringID() + ">s")); //TODO: Don't require emoji + val yeehaw = DiscordPlugin.mainServer.getEmojiByName("YEEHAW"); + MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw != null ? " <:YEEHAW:" + yeehaw.getStringID() + ">s" : " YEEHAWs"))); } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java new file mode 100644 index 0000000..01433c9 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/mccommands/ReloadMCCommand.java @@ -0,0 +1,26 @@ +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." + }; + } +} -- 2.30.2 From a9d4d5e9e1fb8f2cc79ed7c60e83f0ef3947cadb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 17 Mar 2019 22:56:17 +0100 Subject: [PATCH 054/108] Use previous version of D4J Hopefully resolves mysterious NoSuchMethodError --- pom.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 270da7f..4fb93cb 100755 --- a/pom.xml +++ b/pom.xml @@ -162,15 +162,10 @@ provided - - - com.github.SizableShrimp - Discord4J - httprequestchange-SNAPSHOT -- 2.30.2 From 8e2538e5532bb60fd1a274b377edfd408ecdd76e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 5 Apr 2019 17:26:10 +0200 Subject: [PATCH 055/108] Ignore case for role command --- .../discordplugin/role/RoleCommand.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 19d78cf..3381ae4 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -7,6 +7,7 @@ import buttondevteam.discordplugin.commands.ICommand2DC; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; +import lombok.val; import sx.blah.discord.handle.obj.IRole; import java.util.List; @@ -63,12 +64,17 @@ public class RoleCommand extends ICommand2DC { } private IRole checkAndGetRole(Command2DCSender sender, String rolename) { - if (!grm.GameRoles.contains(rolename)) { - sender.sendMessage("that role cannot be found."); - list(sender); - return null; + 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(); + if (!orn.isPresent()) { + sender.sendMessage("that role cannot be found."); + list(sender); + return null; + } + rname = orn.get(); } - final List roles = DiscordPlugin.mainServer.getRolesByName(rolename); + 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); -- 2.30.2 From d2aea8559ab5177fd285de7d14eda54c5070a30f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 10 Apr 2019 13:50:26 +0200 Subject: [PATCH 056/108] 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"}); -- 2.30.2 From 55c61cef98e6bf23a4fe53883f35145a5e247e7c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 15 Apr 2019 15:36:48 +0200 Subject: [PATCH 057/108] 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 - } -} -- 2.30.2 From d8d75c063b0cf07d8dd115d8eba8c56ca95aa94e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 13:52:01 +0200 Subject: [PATCH 058/108] 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; } } -- 2.30.2 From 12ca6fbfb578af189bae6655d3982dc2f013ba6a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 16:51:42 +0200 Subject: [PATCH 059/108] 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 } } -- 2.30.2 From 95af050517e2a26ce27a986f9fe71d862e54cd16 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 17 Apr 2019 17:54:08 +0200 Subject: [PATCH 060/108] 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()) { -- 2.30.2 From 038cb98f1a2cf91ab10e5385708b5c78a3f7944b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 13:29:52 +0200 Subject: [PATCH 061/108] 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); -- 2.30.2 From 59066ce09a1380c654f3848163d6d163c39618fd Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 16:50:00 +0200 Subject: [PATCH 062/108] 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); + } } -- 2.30.2 From 2500572e0d688bab4aee8091b199d366ca623ad7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 24 Apr 2019 17:50:13 +0200 Subject: [PATCH 063/108] 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 -- 2.30.2 From e2e8a58c4e46cb983c0dcfb762b5317ff234fc21 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Apr 2019 02:50:55 +0200 Subject: [PATCH 064/108] 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 { - -} -- 2.30.2 From eeb1955ebe6784c5f2757b949ed0f94cf7333abf Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 25 Apr 2019 19:52:43 +0200 Subject: [PATCH 065/108] 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 -- 2.30.2 From 4881f6bdd24d231c62c524e8e8e157fac9f4175b Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 1 May 2019 00:50:24 +0200 Subject: [PATCH 066/108] 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 -- 2.30.2 From b68456e6f44d669de1c740b44ed4621d45b9db2f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 4 May 2019 03:11:03 +0200 Subject: [PATCH 067/108] 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); } -- 2.30.2 From f266924a9a1495f72412082def8f2fb07aeb5915 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 6 May 2019 15:47:01 +0200 Subject: [PATCH 068/108] 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(); } } } -- 2.30.2 From beab4008737fe5bcc58e43c890d61ddd77371828 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 10 May 2019 21:39:25 +0200 Subject: [PATCH 069/108] 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) { -- 2.30.2 From b396ec47b4292eee3b8a27026eb484d6bbf338eb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 11 May 2019 00:15:50 +0200 Subject: [PATCH 070/108] 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() { -- 2.30.2 From 9e8f988ea6dd46ae4d75deeeb434ce1a50cf469c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 13:07:20 +0200 Subject: [PATCH 071/108] 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; -- 2.30.2 From ac61225730ec9c94cf1c68375de96da2fb28232d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 21:51:28 +0200 Subject: [PATCH 072/108] 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); } } -- 2.30.2 From 2bdba0af220b4927c032001a8ead833d0a49c16f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 20 May 2019 23:35:22 +0200 Subject: [PATCH 073/108] 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") -- 2.30.2 From bf538d9bd0f689ada75b053a78c07480af109867 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 25 May 2019 01:48:06 +0200 Subject: [PATCH 074/108] 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); + } + } + } +} -- 2.30.2 From 545b8130e01745668a6d8fd47200d859a8ba53a2 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 30 May 2019 18:45:44 +0200 Subject: [PATCH 075/108] 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(); + } +} -- 2.30.2 From 547292911343a15a164cb223dc4dcc6d4383763a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 31 May 2019 00:38:28 +0200 Subject: [PATCH 076/108] 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(); } } -- 2.30.2 From 939c6f4970c4dda17ce263e67a4abf06238b4f58 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 1 Jun 2019 02:27:40 +0200 Subject: [PATCH 077/108] 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; -- 2.30.2 From 9edfcf6a3d3bec85729a19337e55f7c782d73d96 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 5 Jun 2019 00:29:34 +0200 Subject: [PATCH 078/108] 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"); } } -- 2.30.2 From 34e3bb0ead4d910ac243e10a8675a3d72fe53889 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 6 Jun 2019 19:40:15 +0200 Subject: [PATCH 079/108] 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 -> { -- 2.30.2 From 27ddad537f737926d3b467319985b17ecb80b9c0 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 8 Jun 2019 22:44:03 +0200 Subject: [PATCH 080/108] Only one ready event allowed --- .../java/buttondevteam/discordplugin/DiscordPlugin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index b5a0efc..ddfc13d 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -130,6 +130,7 @@ public class DiscordPlugin extends ButtonPlugin { .take(size) // Take only the first `size` GuildCreateEvent(s) to be received .collectList()) // Take all received GuildCreateEvents and make it a List .subscribe(this::handleReady); /* All guilds have been received, client is fully connected */ + //dc.getEventDispatcher().on(DisconnectEvent.class); dc.login().subscribe(); } catch (Exception e) { e.printStackTrace(); @@ -141,6 +142,10 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { + if (mainServer != null) { //This is not the first ready event + getLogger().info("Ready event already handled"); + return; + } mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards if (mainServer == null) { if (event.size() == 0) { @@ -265,6 +270,7 @@ public class DiscordPlugin extends ButtonPlugin { dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing timings.printElapsed("Logging out..."); dc.logout().block(); + mainServer = null; //Allow ReadyEvent again //Configs are emptied so channels and servers are fetched again } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while disabling DiscordPlugin!", e); -- 2.30.2 From 0e24344efdffab26479465a501371046cbf241dc Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 9 Jun 2019 23:33:23 +0200 Subject: [PATCH 081/108] PLW error handling --- .../broadcaster/GeneralEventBroadcasterModule.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 9b57812..7aafd27 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -15,20 +15,21 @@ public class GeneralEventBroadcasterModule extends Component { PlayerListWatcher.hookUp(); DPUtils.getLogger().info("Finished hooking into the player list"); hooked = true; - } catch (Exception e) { - TBMCCoreAPI.SendException("Error while hacking the player list!", e); + } catch (Exception | NoClassDefFoundError e) { + TBMCCoreAPI.SendException("Error while hacking the player list! Disable this module if you're on an incompatible version.", e); } } @Override protected void disable() { try { + if (!hooked) return; if (PlayerListWatcher.hookDown()) DPUtils.getLogger().info("Finished unhooking the player list!"); else DPUtils.getLogger().info("Didn't have the player list hooked."); hooked = false; - } catch (Exception e) { + } catch (Exception | NoClassDefFoundError e) { TBMCCoreAPI.SendException("Error while hacking the player list!", e); } } -- 2.30.2 From 4082c2abbf2bd2489535d9603d7d9aa169f7dae6 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 30 Jun 2019 22:05:33 +0200 Subject: [PATCH 082/108] Fixes, error handling Sync events Vanilla command error handling (Older changes ^) Fixed exception Coder pinging --- .../discordplugin/DiscordConnectedPlayer.java | 6 ++- .../discordplugin/DiscordPlayerSender.java | 6 ++- .../exceptions/ExceptionListenerModule.java | 44 +++++++++---------- .../discordplugin/mcchat/MCChatListener.java | 9 +++- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index 6e30a53..843484c 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -19,7 +19,11 @@ public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlay public DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { super(user, channel, nextEntityId++, uuid, mcname, module); - vanillaCmdListener = new VanillaCommandListener<>(this); + try { + vanillaCmdListener = new VanillaCommandListener<>(this); + } catch (NoClassDefFoundError e) { + DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); + } } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 807abd4..41bb696 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -41,7 +41,11 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< public DiscordPlayerSender(User user, MessageChannel channel, Player player) { super(user, channel); this.player = player; - vanillaCmdListener = new VanillaCommandListener(this); + try { + vanillaCmdListener = new VanillaCommandListener(this); + } catch (NoClassDefFoundError e) { + DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); + } } @Override diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index d57c313..17d029a 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -50,28 +50,28 @@ public class ExceptionListenerModule extends Component implements private static void SendException(Throwable e, String sourcemessage) { if (instance == null) return; try { - Mono channel = getChannel(); - 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() >= 1980) - stackTrace = stackTrace.substring(0, 1980 - sb.length()); - sb.append(stackTrace).append("\n"); - sb.append("```"); - return channel.flatMap(ch -> ch.createMessage(sb.toString())); - }).subscribe(); + getChannel().flatMap(channel -> { + Mono coderRole; + if (channel instanceof GuildChannel) + coderRole = instance.pingRole(((GuildChannel) channel).getGuild()).get(); + else + coderRole = Mono.empty(); + return 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() >= 1980) + stackTrace = stackTrace.substring(0, 1980 - sb.length()); + sb.append(stackTrace).append("\n"); + sb.append("```"); + return channel.createMessage(sb.toString()); + }); + }).subscribe(); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index aa7e278..790edfb 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -321,7 +321,8 @@ public class MCChatListener implements Listener { return; } val ev = new TBMCCommandPreprocessEvent(dsender, dmessage); - Bukkit.getPluginManager().callEvent(ev); + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> + Bukkit.getPluginManager().callEvent(ev)); if (ev.isCancelled()) return; int spi = cmdlowercased.indexOf(' '); @@ -338,7 +339,11 @@ public class MCChatListener implements Listener { 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); + try { + VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); + } catch (NoClassDefFoundError e) { + Bukkit.dispatchCommand(dsender, cmd); + } Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); if (clmd != null) channel.set(chtmp); -- 2.30.2 From 5a5f653b865646b406f2f4f40c5d555630c7699a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 8 Jul 2019 02:00:08 +0200 Subject: [PATCH 083/108] Added DC user mention tabcomplete... But only for commands, because that's how it works now apparently #16 Also might have made it 1.14 ready, though I switched the dependency back to 1.12 Oh it's 1.12.2... --- pom.xml | 4 +-- .../discordplugin/DiscordPlayerSender.java | 22 ++++++++-------- .../discordplugin/mcchat/MCListener.java | 25 +++++++++++++++++++ .../playerfaker/DiscordFakePlayer.java | 10 ++++++++ .../playerfaker/DiscordLivingEntity.java | 10 -------- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index f0c321a..6d68328 100755 --- a/pom.xml +++ b/pom.xml @@ -148,7 +148,7 @@ --> Essentials - http://repo.ess3.net/content/repositories/essrel/ + https://ci.ender.zone/plugin/repository/everything/ projectlombok.org @@ -174,7 +174,7 @@ org.spigotmc spigot-api - 1.12-R0.1-SNAPSHOT + 1.12.2-R0.1-SNAPSHOT provided diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 41bb696..680e886 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -302,10 +302,6 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< return player.addAttachment(plugin); } - public Block getTargetBlock(HashSet transparent, int maxDistance) { - return player.getTargetBlock(transparent, maxDistance); - } - public World getWorld() { return player.getWorld(); } @@ -354,10 +350,6 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< player.setCompassTarget(loc); } - public List getLastTwoTargetBlocks(HashSet transparent, int maxDistance) { - return player.getLastTwoTargetBlocks(transparent, maxDistance); - } - public Location getCompassTarget() { return player.getCompassTarget(); } @@ -1096,11 +1088,21 @@ public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer< } public void hidePlayer(Player player) { - player.hidePlayer(player); + this.player.hidePlayer(player); + } + + @Override + public void hidePlayer(Plugin plugin, Player player) { + this.player.hidePlayer(plugin, player); } public void showPlayer(Player player) { - player.showPlayer(player); + this.player.showPlayer(player); + } + + @Override + public void showPlayer(Plugin plugin, Player player) { + this.player.showPlayer(plugin, player); } public boolean canSee(Player player) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 7c44627..231bca8 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -18,10 +18,13 @@ 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.PlayerCommandSendEvent; 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 org.bukkit.event.server.TabCompleteEvent; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.Objects; @@ -154,4 +157,26 @@ class MCListener implements Listener { public void onNickChange(NickChangeEvent event) { MCChatUtils.updatePlayerList(); } + + @EventHandler + public void onTabComplete(TabCompleteEvent event) { + int i = event.getBuffer().lastIndexOf(' '); + String t = event.getBuffer().substring(i + 1); //0 if not found + //System.out.println("Last token: " + t); + if (!t.startsWith("@")) + return; + String token = t.substring(1); + //System.out.println("Token: " + token); + val x = DiscordPlugin.mainServer.getMembers() + .flatMap(m -> Flux.just(m.getUsername(), m.getNickname().orElse(""))) + .filter(s -> s.startsWith(token)) + .map(s -> "@" + s) + .doOnNext(event.getCompletions()::add).blockLast(); + //System.out.println("Finished - last: " + x); + } + + @EventHandler + public void onCommandSend(PlayerCommandSendEvent event) { + event.getCommands().add("g"); + } } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index 6879155..1902516 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -552,10 +552,20 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player { public void hidePlayer(Player player) { } + @Override + public void hidePlayer(Plugin plugin, Player player) { + + } + @Override public void showPlayer(Player player) { } + @Override + public void showPlayer(Plugin plugin, Player player) { + + } + @Override public boolean canSee(Player player) { // Nobody can see them return false; diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java index c561fbf..9b0c60c 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java @@ -126,21 +126,11 @@ public abstract class DiscordLivingEntity extends DiscordEntity implements Livin return Arrays.asList(); } - @Override - public Block getTargetBlock(HashSet transparent, int maxDistance) { - return null; - } - @Override public Block getTargetBlock(Set transparent, int maxDistance) { return null; } - @Override - public List getLastTwoTargetBlocks(HashSet transparent, int maxDistance) { - return Arrays.asList(); - } - @Override public List getLastTwoTargetBlocks(Set transparent, int maxDistance) { return Arrays.asList(); -- 2.30.2 From 7db3b17090a19d51339c8462dcde8f8e32add289 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 22 Jul 2019 22:35:15 +0200 Subject: [PATCH 084/108] Made DCP version-independent & msg reset Some things may not be implemented yet Also added a wrapper around the vanilla cmd listener so Mockito doesn't complain about the missing class Msg reset fixed (#101) --- .../discordplugin/DiscordConnectedPlayer.java | 140 +++++++++++++++++- .../discordplugin/DiscordPlayerSender.java | 5 +- .../discordplugin/IMCPlayer.java | 4 +- .../GeneralEventBroadcasterModule.java | 8 +- .../mcchat/ChannelconCommand.java | 2 +- .../discordplugin/mcchat/MCChatPrivate.java | 2 +- .../discordplugin/mcchat/MCChatUtils.java | 5 +- .../mcchat/MinecraftChatModule.java | 2 +- .../playerfaker/VCMDWrapper.java | 12 ++ .../playerfaker/VanillaCommandListener.java | 2 +- 10 files changed, 164 insertions(+), 18 deletions(-) mode change 100755 => 100644 src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java create mode 100644 src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java old mode 100755 new mode 100644 index 843484c..da5ccd4 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -1,29 +1,155 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; -import buttondevteam.discordplugin.playerfaker.DiscordFakePlayer; +import buttondevteam.discordplugin.playerfaker.VCMDWrapper; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; 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.entity.Entity; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.ServerOperator; +import org.mockito.Answers; +import org.mockito.Mockito; +import java.util.HashSet; import java.util.UUID; -public class DiscordConnectedPlayer extends DiscordFakePlayer implements IMCPlayer { - private static int nextEntityId = 10000; - private @Getter VanillaCommandListener vanillaCmdListener; +public abstract class DiscordConnectedPlayer extends DiscordSenderBase implements IMCPlayer { + private @Getter VCMDWrapper 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); + @Delegate(excludes = ServerOperator.class) + private PermissibleBase origPerm; + + private @Getter String name; + + private @Getter OfflinePlayer basePlayer; + + @Getter + @Setter + private PermissibleBase perm; + + private Location location = Bukkit.getWorlds().get(0).getSpawnLocation(); + + private final MinecraftChatModule module; + + @Getter + private final UUID uniqueId; + + /** + * The parameters must match with {@link #create(User, MessageChannel, UUID, String, MinecraftChatModule)} + */ + protected DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, + MinecraftChatModule module) { + super(user, channel); + origPerm = perm = new PermissibleBase(basePlayer = Bukkit.getOfflinePlayer(uuid)); + name = mcname; + this.module = module; + uniqueId = uuid; + displayName = mcname; try { - vanillaCmdListener = new VanillaCommandListener<>(this); + vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener<>(this)); } catch (NoClassDefFoundError e) { DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } } + public void setOp(boolean value) { //CraftPlayer-compatible implementation + this.origPerm.setOp(value); + this.perm.recalculatePermissions(); + } + + public boolean isOp() { return this.origPerm.isOp(); } + + @Override + public boolean teleport(Location location) { + if (module.allowFakePlayerTeleports().get()) + this.location = location; + return true; + } + + @Override + public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { + if (module.allowFakePlayerTeleports().get()) + this.location = location; + return true; + } + + @Override + public boolean teleport(Entity destination) { + if (module.allowFakePlayerTeleports().get()) + this.location = destination.getLocation(); + return true; + } + + @Override + public boolean teleport(Entity destination, PlayerTeleportEvent.TeleportCause cause) { + if (module.allowFakePlayerTeleports().get()) + this.location = destination.getLocation(); + return true; + } + + @Override + public Location getLocation(Location loc) { + if (loc != null) { + loc.setWorld(getWorld()); + loc.setX(location.getX()); + loc.setY(location.getY()); + loc.setZ(location.getZ()); + loc.setYaw(location.getYaw()); + loc.setPitch(location.getPitch()); + } + + return loc; + } + + @Override + public Server getServer() { + return Bukkit.getServer(); + } + + @Override + public void sendRawMessage(String message) { + sendMessage(message); + } + + @Override + public void chat(String msg) { + Bukkit.getPluginManager() + .callEvent(new AsyncPlayerChatEvent(true, this, msg, new HashSet<>(Bukkit.getOnlinePlayers()))); + } + + @Override + public World getWorld() { + return Bukkit.getWorlds().get(0); + } + + @Override + public boolean isOnline() { + return true; + } + + @Override + public Location getLocation() { + return new Location(getWorld(), location.getX(), location.getY(), location.getZ(), + location.getYaw(), location.getPitch()); + } + + @Getter + @Setter + private String displayName; + + public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname, + MinecraftChatModule module) { + return Mockito.mock(DiscordConnectedPlayer.class, Mockito.withSettings() + .defaultAnswer(Answers.CALLS_REAL_METHODS).useConstructor(user, channel, uuid, mcname, module)); + } } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 680e886..62949c5 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin; +import buttondevteam.discordplugin.playerfaker.VCMDWrapper; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; @@ -36,13 +37,13 @@ import java.util.*; public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer { protected Player player; - private @Getter VanillaCommandListener vanillaCmdListener; + private @Getter VCMDWrapper vanillaCmdListener; public DiscordPlayerSender(User user, MessageChannel channel, Player player) { super(user, channel); this.player = player; try { - vanillaCmdListener = new VanillaCommandListener(this); + vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener(this, player)); } catch (NoClassDefFoundError e) { DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } diff --git a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java index 854db2b..7943f21 100755 --- a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java @@ -1,8 +1,8 @@ package buttondevteam.discordplugin; -import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; +import buttondevteam.discordplugin.playerfaker.VCMDWrapper; import org.bukkit.entity.Player; public interface IMCPlayer> extends Player { - VanillaCommandListener getVanillaCmdListener(); + VCMDWrapper getVanillaCmdListener(); } diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 7aafd27..804e79e 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -15,9 +15,12 @@ public class GeneralEventBroadcasterModule extends Component { PlayerListWatcher.hookUp(); DPUtils.getLogger().info("Finished hooking into the player list"); hooked = true; - } catch (Exception | NoClassDefFoundError e) { + } catch (Exception e) { TBMCCoreAPI.SendException("Error while hacking the player list! Disable this module if you're on an incompatible version.", e); + } catch (NoClassDefFoundError e) { + DPUtils.getLogger().warning("Error while hacking the player list! Disable this module if you're on an incompatible version."); } + } @Override @@ -29,8 +32,9 @@ public class GeneralEventBroadcasterModule extends Component { else DPUtils.getLogger().info("Didn't have the player list hooked."); hooked = false; - } catch (Exception | NoClassDefFoundError e) { + } catch (Exception e) { TBMCCoreAPI.SendException("Error while hacking the player list!", e); + } catch (NoClassDefFoundError ignored) { } } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index 41599b7..bc1cf20 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -107,7 +107,7 @@ public class ChannelconCommand extends ICommand2DC { return true; } val channel = message.getChannel().block(); - DiscordConnectedPlayer dcp = new DiscordConnectedPlayer(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module); + DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(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 diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 344ecf5..06c3ce1 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -26,7 +26,7 @@ public class MCChatPrivate { val op = Bukkit.getOfflinePlayer(mcp.getUUID()); val mcm = ComponentManager.getIfEnabled(MinecraftChatModule.class); if (start) { - val sender = new DiscordConnectedPlayer(user, channel, mcp.getUUID(), op.getName(), mcm); + val sender = DiscordConnectedPlayer.create(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 MCChatUtils.callLoginEvents(sender); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 92af87d..5f709d2 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -180,7 +180,10 @@ public class MCChatUtils { } public static Consumer> send(String message) { - return ch -> ch.flatMap(mc -> mc.createMessage(DPUtils.sanitizeString(message))).subscribe(); + return ch -> ch.flatMap(mc -> { + resetLastMessage(mc); + return mc.createMessage(DPUtils.sanitizeString(message)); + }).subscribe(); } public static void forAllowedMCChat(Consumer> action, TBMCSystemChatEvent event) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 28e1e72..1534ee9 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -104,7 +104,7 @@ public class MinecraftChatModule extends Component { 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, (MessageChannel) ch, UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this); + val dcp = DiscordConnectedPlayer.create(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())); }); } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java new file mode 100644 index 0000000..95a7811 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java @@ -0,0 +1,12 @@ +package buttondevteam.discordplugin.playerfaker; + +import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.IMCPlayer; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class VCMDWrapper> { + @Getter //Needed to mock the player + private final VanillaCommandListener listener; +} diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java index 29f3a13..9f2db22 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java @@ -87,7 +87,7 @@ public class VanillaCommandListener> if (!vcmd.testPermission(sender)) return true; - ICommandListener icommandlistener = sender.getVanillaCmdListener(); + ICommandListener icommandlistener = sender.getVanillaCmdListener().getListener(); String[] args = cmdstr.split(" "); args = Arrays.copyOfRange(args, 1, args.length); try { -- 2.30.2 From 480032a3d6f94550a083e1c5a92bd77cd47d335f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 8 Aug 2019 13:45:40 +0200 Subject: [PATCH 085/108] Fix of getInfo and role adding/removing Fixed getInfo if the player isn't on the DC server Fixed message after adding or removing a game role --- .../discordplugin/listeners/MCListener.java | 16 ++++++++++------ .../discordplugin/mcchat/MCListener.java | 13 +++++++------ .../discordplugin/role/RoleCommand.java | 7 +++++-- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 6062711..6c9acd6 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -12,6 +12,7 @@ import lombok.val; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.server.ServerCommandEvent; +import reactor.core.publisher.Mono; public class MCListener implements Listener { @EventHandler @@ -33,13 +34,16 @@ public class MCListener implements Listener { 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; + val userOpt = DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).onErrorResume(t -> Mono.empty()).blockOptional(); + if (!userOpt.isPresent()) return; + User user = userOpt.get(); 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; + val memberOpt = user.asMember(DiscordPlugin.mainServer.getId()).blockOptional(); + if (!memberOpt.isPresent()) return; + Member member = memberOpt.get(); + val prOpt = member.getPresence().blockOptional(); + if (!prOpt.isPresent()) return; + val pr = prOpt.get(); e.addInfo(pr.getStatus().toString()); if (pr.getActivity().isPresent()) { val activity = pr.getActivity().get(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 231bca8..0880bd9 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -27,7 +27,6 @@ import org.bukkit.event.server.TabCompleteEvent; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.Objects; import java.util.Optional; @RequiredArgsConstructor @@ -53,11 +52,13 @@ class MCListener implements Listener { final Player p = e.getPlayer(); DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); 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)); //TODO: Don't block - MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), - new DiscordPlayerSender(user, module.chatChannelMono().block(), p)); //Stored per-channel + DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).flatMap(user -> user.getPrivateChannel().flatMap(chan -> module.chatChannelMono().flatMap(cc -> { + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), + new DiscordPlayerSender(user, chan, p)); + MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), + new DiscordPlayerSender(user, cc, p)); //Stored per-channel + return Mono.empty(); + }))).subscribe(); } final String message = e.GetPlayer().PlayerName().get() + " joined the game"; MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index eb93eb6..d47007b 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -8,6 +8,7 @@ import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import discord4j.core.object.entity.Role; import lombok.val; +import reactor.core.publisher.Mono; import java.util.List; import java.util.stream.Collectors; @@ -31,7 +32,8 @@ public class RoleCommand extends ICommand2DC { return true; try { sender.getMessage().getAuthorAsMember() - .subscribe(m -> m.addRole(role.getId()).subscribe(r -> sender.sendMessage("added role."))); + .flatMap(m -> m.addRole(role.getId()).switchIfEmpty(Mono.fromRunnable(() -> sender.sendMessage("added role.")))) + .subscribe(); } catch (Exception e) { TBMCCoreAPI.SendException("Error while adding role!", e); sender.sendMessage("an error occured while adding the role."); @@ -49,7 +51,8 @@ public class RoleCommand extends ICommand2DC { return true; try { sender.getMessage().getAuthorAsMember() - .subscribe(m -> m.removeRole(role.getId()).subscribe(r -> sender.sendMessage("removed role."))); + .flatMap(m -> m.removeRole(role.getId()).switchIfEmpty(Mono.fromRunnable(() -> sender.sendMessage("removed role.")))) + .subscribe(); } catch (Exception e) { TBMCCoreAPI.SendException("Error while removing role!", e); sender.sendMessage("an error occured while removing the role."); -- 2.30.2 From 7a9e7de138276c965d9643151663544a1ef6fdc7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 8 Aug 2019 14:31:01 +0200 Subject: [PATCH 086/108] Made player list, custom and private chat toggleable The last parts of #51 --- .../mcchat/ChannelconCommand.java | 4 +++ .../discordplugin/mcchat/MCChatCommand.java | 8 +++++ .../discordplugin/mcchat/MCChatUtils.java | 3 +- .../mcchat/MinecraftChatModule.java | 29 ++++++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index bc1cf20..d51a4b0 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -90,6 +90,10 @@ public class ChannelconCommand extends ICommand2DC { @Command2.Subcommand public boolean def(Command2DCSender sender, String channelID) { val message = sender.getMessage(); + if (!module.allowCustomChat().get()) { + sender.sendMessage("channel connection is not allowed on this Minecraft server."); + return true; + } if (checkPerms(message)) return true; if (MCChatCustom.hasCustomChat(message.getChannelId())) return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index 63b2fb5..f068a12 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -9,6 +9,7 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import discord4j.core.object.entity.PrivateChannel; +import lombok.RequiredArgsConstructor; import lombok.val; @CommandClass(helpText = { @@ -17,10 +18,17 @@ import lombok.val; "It can be useful if you don't want your messages to be visible, for example when talking in a private channel.", // "You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." // }) +@RequiredArgsConstructor public class MCChatCommand extends ICommand2DC { + private final MinecraftChatModule module; + @Command2.Subcommand public boolean def(Command2DCSender sender) { + if (!module.allowPrivateChat().get()) { + sender.sendMessage("using the private chat is not allowed on this Minecraft server."); + return true; + } val message = sender.getMessage(); val channel = message.getChannel().block(); @SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 5f709d2..5e4c51c 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -53,7 +53,8 @@ public class MCChatUtils { private static HashMap, HashSet> staticExcludedPlugins = new HashMap<>(); public static void updatePlayerList() { - if (notEnabled()) return; + val mod = getModule(); + if (mod == null || !mod.showPlayerListOnDC().get()) return; if (lastmsgdata != null) updatePL(lastmsgdata); MCChatCustom.lastmsgCustom.forEach(MCChatUtils::updatePL); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 1534ee9..a44986a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -77,6 +77,33 @@ public class MinecraftChatModule extends Component { return getConfig().getData("allowFakePlayerTeleports", false); } + /** + * If this is on, each chat channel will have a player list in their description. + * It only gets added if there's no description yet or there are (at least) two lines of "----" following each other. + * Note that it will replace everything between the first and last "----" but it will only detect exactly four dashes. + * So if you want to use dashes for something else in the description, make sure it's either less or more dashes in one line. + */ + public ConfigData showPlayerListOnDC() { + return getConfig().getData("showPlayerListOnDC", true); + } + + /** + * This setting controls whether custom chat connections can be created (existing connections will always work). + * Custom chat connections can be created using the channelcon command and they allow players to display town chat in a Discord channel for example. + * See the channelcon command for more details. + */ + public ConfigData allowCustomChat() { + return getConfig().getData("allowCustomChat", true); + } + + /** + * This setting allows you to control if players can DM the bot to log on the server from Discord. + * This allows them to both chat and perform any command they can in-game. + */ + public ConfigData allowPrivateChat() { + return getConfig().getData("allowPrivateChat", true); + } + @Override protected void enable() { if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) @@ -84,7 +111,7 @@ public class MinecraftChatModule extends Component { 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 - getPlugin().getManager().registerCommand(new MCChatCommand()); + getPlugin().getManager().registerCommand(new MCChatCommand(this)); getPlugin().getManager().registerCommand(new ChannelconCommand(this)); val chcons = getConfig().getConfig().getConfigurationSection("chcons"); -- 2.30.2 From e88684a5647497b61f93caf349c9201ac82fa194 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 14 Aug 2019 00:53:51 +0200 Subject: [PATCH 087/108] Error handling, 1.14 vanilla command support Error handling (not today) Added support for vanilla commands on 1.14 --- pom.xml | 6 + .../buttondevteam/discordplugin/DPUtils.java | 4 + .../discordplugin/DiscordConnectedPlayer.java | 7 +- .../discordplugin/DiscordPlayerSender.java | 7 +- .../discordplugin/DiscordSender.java | 4 +- .../discordplugin/IMCPlayer.java | 4 +- .../discordplugin/commands/DebugCommand.java | 2 +- .../discordplugin/listeners/MCListener.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 16 ++- .../discordplugin/mcchat/MCListener.java | 4 +- .../playerfaker/DiscordFakePlayer.java | 5 +- .../playerfaker/VCMDWrapper.java | 31 ++++- .../playerfaker/VanillaCommandListener.java | 2 +- .../playerfaker/VanillaCommandListener14.java | 106 ++++++++++++++++++ 14 files changed, 178 insertions(+), 22 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java diff --git a/pom.xml b/pom.xml index 6d68328..c9d1eb8 100755 --- a/pom.xml +++ b/pom.xml @@ -183,6 +183,12 @@ 1.12.2-R0.1-SNAPSHOT provided + + org.spigotmc. + spigot + 1.14.4-R0.1-SNAPSHOT + provided + com.discord4j diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 616b750..84d2ced 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -163,4 +163,8 @@ public final class DPUtils { return getMessageChannel(config.getPath(), config.get()); } + public static Mono ignoreError(Mono mono) { + return mono.onErrorResume(t -> Mono.empty()); + } + } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index da5ccd4..b5d7da4 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -2,7 +2,6 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.playerfaker.VCMDWrapper; -import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; import lombok.Getter; @@ -21,7 +20,7 @@ import java.util.HashSet; import java.util.UUID; public abstract class DiscordConnectedPlayer extends DiscordSenderBase implements IMCPlayer { - private @Getter VCMDWrapper vanillaCmdListener; + private @Getter VCMDWrapper vanillaCmdListener; @Getter @Setter private boolean loggedIn = false; @@ -56,7 +55,9 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement uniqueId = uuid; displayName = mcname; try { - vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener<>(this)); + vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this)); + if (vanillaCmdListener.getListener() == null) + DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } catch (NoClassDefFoundError e) { DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java index 62949c5..1e94b14 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayerSender.java @@ -1,7 +1,6 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.playerfaker.VCMDWrapper; -import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; import lombok.Getter; @@ -37,13 +36,15 @@ import java.util.*; public class DiscordPlayerSender extends DiscordSenderBase implements IMCPlayer { protected Player player; - private @Getter VCMDWrapper vanillaCmdListener; + private @Getter VCMDWrapper vanillaCmdListener; public DiscordPlayerSender(User user, MessageChannel channel, Player player) { super(user, channel); this.player = player; try { - vanillaCmdListener = new VCMDWrapper<>(new VanillaCommandListener(this, player)); + vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this, player)); + if (vanillaCmdListener.getListener() == null) + DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } catch (NoClassDefFoundError e) { DPUtils.getLogger().warning("Vanilla commands won't be available from Discord due to a compatibility error."); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordSender.java b/src/main/java/buttondevteam/discordplugin/DiscordSender.java index 9eda278..0381e66 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordSender.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordSender.java @@ -12,6 +12,7 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; +import reactor.core.publisher.Mono; import java.util.Set; @@ -23,7 +24,8 @@ public class DiscordSender extends DiscordSenderBase implements CommandSender { public DiscordSender(User user, MessageChannel channel) { super(user, channel); val def = "Discord user"; - name = user == null ? def : user.asMember(DiscordPlugin.mainServer.getId()).blockOptional().map(Member::getDisplayName).orElse(def); + name = user == null ? def : user.asMember(DiscordPlugin.mainServer.getId()) + .onErrorResume(t -> Mono.empty()).blockOptional().map(Member::getDisplayName).orElse(def); } public DiscordSender(User user, MessageChannel channel, String name) { diff --git a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java index 7943f21..c2ee28e 100755 --- a/src/main/java/buttondevteam/discordplugin/IMCPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/IMCPlayer.java @@ -3,6 +3,6 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.playerfaker.VCMDWrapper; import org.bukkit.entity.Player; -public interface IMCPlayer> extends Player { - VCMDWrapper getVanillaCmdListener(); +public interface IMCPlayer extends Player { + VCMDWrapper getVanillaCmdListener(); } diff --git a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java index e1c0686..65e0663 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DebugCommand.java @@ -19,7 +19,7 @@ public class DebugCommand extends ICommand2DC { .flatMap(m -> DiscordPlugin.plugin.modRole().get() .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 -> { + .onErrorReturn(false).subscribe(success -> { if (success) sender.sendMessage("debug " + (CommonListeners.debug() ? "enabled" : "disabled")); else diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index 6c9acd6..3afc038 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -38,7 +38,7 @@ public class MCListener implements Listener { if (!userOpt.isPresent()) return; User user = userOpt.get(); e.addInfo("Discord tag: " + user.getUsername() + "#" + user.getDiscriminator()); - val memberOpt = user.asMember(DiscordPlugin.mainServer.getId()).blockOptional(); + val memberOpt = user.asMember(DiscordPlugin.mainServer.getId()).onErrorResume(t -> Mono.empty()).blockOptional(); if (!memberOpt.isPresent()) return; Member member = memberOpt.get(); val prOpt = member.getPresence().blockOptional(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 790edfb..4ff36cb 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -10,6 +10,7 @@ import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.discordplugin.listeners.CommandListener; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.playerfaker.VanillaCommandListener; +import buttondevteam.discordplugin.playerfaker.VanillaCommandListener14; import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.*; import buttondevteam.lib.chat.ChatMessage; @@ -277,10 +278,11 @@ public class MCChatListener implements Listener { 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); + val m = u.asMember(DiscordPlugin.mainServer.getId()).onErrorResume(t -> Mono.empty()).blockOptional(); + if (m.isPresent()) { + val mm = m.get(); + final String nick = mm.getDisplayName(); + dmessage = dmessage.replace(mm.getNicknameMention(), "@" + nick); } } for (GuildChannel ch : event.getGuild().flux().flatMap(Guild::getChannels).toIterable()) { @@ -340,7 +342,11 @@ public class MCChatListener implements Listener { channel.set(clmd.mcchannel); //Hack to send command in the channel } //TODO: Permcheck isn't implemented for commands try { - VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); + String mcpackage = Bukkit.getServer().getClass().getPackage().getName(); + if (mcpackage.contains("1_12")) + VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); + else if (mcpackage.contains("1_14")) + VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd); } catch (NoClassDefFoundError e) { Bukkit.dispatchCommand(dsender, cmd); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 0880bd9..c3ad14a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -118,7 +118,7 @@ class MCListener implements Listener { final DiscordPlayer p = TBMCPlayerBase.getPlayer(source.getPlayer().getUniqueId(), TBMCPlayer.class) .getAs(DiscordPlayer.class); if (p == null) return; - DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID())) + DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID())) .flatMap(user -> user.asMember(DiscordPlugin.mainServer.getId())) .flatMap(user -> role.flatMap(r -> { if (e.getValue()) @@ -131,7 +131,7 @@ class MCListener implements Listener { if (modlog != null) return modlog.flatMap(ch -> ch.createMessage(msg)); return Mono.empty(); - })).subscribe(); + }))).subscribe(); } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java index 1902516..25b505e 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java @@ -1,7 +1,9 @@ package buttondevteam.discordplugin.playerfaker; +import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import discord4j.core.object.entity.Member; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; import lombok.Getter; @@ -143,7 +145,8 @@ public class DiscordFakePlayer extends DiscordHumanEntity implements Player { @Override public String getDisplayName() { - return Objects.requireNonNull(user.asMember(DiscordPlugin.mainServer.getId()).block()).getDisplayName(); + return DPUtils.ignoreError(user.asMember(DiscordPlugin.mainServer.getId())).blockOptional() + .map(Member::getDisplayName).orElse(name); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java index 95a7811..4bcf5eb 100644 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VCMDWrapper.java @@ -4,9 +4,36 @@ import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.discordplugin.IMCPlayer; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; @RequiredArgsConstructor -public class VCMDWrapper> { +public class VCMDWrapper { @Getter //Needed to mock the player - private final VanillaCommandListener listener; + private final Object listener; + + /** + * This constructor will only send raw vanilla messages to the sender in plain text. + * + * @param player The Discord sender player (the wrapper) + */ + public static > Object createListener(T player) { + return createListener(player, null); + } + + /** + * This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player. + * + * @param player The Discord sender player (the wrapper) + * @param bukkitplayer The Bukkit player to send the raw message to + */ + public static > Object createListener(T player, Player bukkitplayer) { + String mcpackage = Bukkit.getServer().getClass().getPackage().getName(); + if (mcpackage.contains("1_12")) + return bukkitplayer == null ? new VanillaCommandListener<>(player) : new VanillaCommandListener<>(player, bukkitplayer); + else if (mcpackage.contains("1_14")) + return bukkitplayer == null ? new VanillaCommandListener14<>(player) : new VanillaCommandListener14<>(player, bukkitplayer); + else + return null; + } } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java index 9f2db22..c12a308 100755 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener.java @@ -87,7 +87,7 @@ public class VanillaCommandListener> if (!vcmd.testPermission(sender)) return true; - ICommandListener icommandlistener = sender.getVanillaCmdListener().getListener(); + ICommandListener icommandlistener = (ICommandListener) sender.getVanillaCmdListener().getListener(); String[] args = cmdstr.split(" "); args = Arrays.copyOfRange(args, 1, args.length); try { diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java new file mode 100644 index 0000000..fbaf958 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/VanillaCommandListener14.java @@ -0,0 +1,106 @@ +package buttondevteam.discordplugin.playerfaker; + +import buttondevteam.discordplugin.DiscordSenderBase; +import buttondevteam.discordplugin.IMCPlayer; +import lombok.Getter; +import lombok.val; +import net.minecraft.server.v1_14_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.v1_14_R1.CraftServer; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.command.ProxiedNativeCommandSender; +import org.bukkit.craftbukkit.v1_14_R1.command.VanillaCommandWrapper; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Arrays; + +public class VanillaCommandListener14> implements ICommandListener { + private @Getter T player; + private Player bukkitplayer; + + /** + * This constructor will only send raw vanilla messages to the sender in plain text. + * + * @param player The Discord sender player (the wrapper) + */ + public VanillaCommandListener14(T player) { + this.player = player; + this.bukkitplayer = null; + } + + /** + * This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player. + * + * @param player The Discord sender player (the wrapper) + * @param bukkitplayer The Bukkit player to send the raw message to + */ + public VanillaCommandListener14(T player, Player bukkitplayer) { + this.player = player; + this.bukkitplayer = bukkitplayer; + if (!(bukkitplayer instanceof CraftPlayer)) + throw new ClassCastException("bukkitplayer must be a Bukkit player!"); + } + + @Override + public void sendMessage(IChatBaseComponent arg0) { + player.sendMessage(arg0.getString()); + if (bukkitplayer != null) + ((CraftPlayer) bukkitplayer).getHandle().sendMessage(arg0); + } + + @Override + public boolean shouldSendSuccess() { + return true; + } + + @Override + public boolean shouldSendFailure() { + return true; + } + + @Override + public boolean shouldBroadcastCommands() { + return true; //Broadcast to in-game admins + } + + @Override + public CommandSender getBukkitSender(CommandListenerWrapper commandListenerWrapper) { + return player; + } + + public static boolean runBukkitOrVanillaCommand(DiscordSenderBase dsender, String cmdstr) { + val cmd = ((CraftServer) Bukkit.getServer()).getCommandMap().getCommand(cmdstr.split(" ")[0].toLowerCase()); + if (!(dsender instanceof Player) || !(cmd instanceof VanillaCommandWrapper)) + return Bukkit.dispatchCommand(dsender, cmdstr); // Unconnected users are treated well in vanilla cmds + + if (!(dsender instanceof IMCPlayer)) + throw new ClassCastException( + "dsender needs to implement IMCPlayer to use vanilla commands as it implements Player."); + + IMCPlayer sender = (IMCPlayer) dsender; // Don't use val on recursive interfaces :P + + val vcmd = (VanillaCommandWrapper) cmd; + if (!vcmd.testPermission(sender)) + return true; + + val world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle(); + ICommandListener icommandlistener = (ICommandListener) sender.getVanillaCmdListener().getListener(); + val wrapper = new CommandListenerWrapper(icommandlistener, new Vec3D(0, 0, 0), + new Vec2F(0, 0), world, 0, sender.getName(), + new ChatComponentText(sender.getName()), world.getMinecraftServer(), null); + val pncs = new ProxiedNativeCommandSender(wrapper, sender, sender); + String[] args = cmdstr.split(" "); + args = Arrays.copyOfRange(args, 1, args.length); + try { + return vcmd.execute(pncs, cmd.getLabel(), args); + } catch (CommandException commandexception) { + // Taken from CommandHandler + ChatMessage chatmessage = new ChatMessage(commandexception.getMessage(), commandexception.a()); + chatmessage.getChatModifier().setColor(EnumChatFormat.RED); + icommandlistener.sendMessage(chatmessage); + } + return true; + } +} -- 2.30.2 From 42e91409c7d4829627de91d14aecf5eb2bbd3558 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 14 Aug 2019 21:29:19 +0200 Subject: [PATCH 088/108] Work on 1.14 PLW support --- .../broadcaster/PlayerListWatcher.java | 335 +++--------------- 1 file changed, 41 insertions(+), 294 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index eafe7f5..c0b39c5 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -1,26 +1,20 @@ package buttondevteam.discordplugin.broadcaster; -import buttondevteam.discordplugin.mcchat.MCChatUtils; -import buttondevteam.lib.TBMCCoreAPI; -import com.mojang.authlib.GameProfile; import lombok.val; -import net.minecraft.server.v1_12_R1.*; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.CraftServer; -import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; -import org.objenesis.ObjenesisStd; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.List; -import java.util.UUID; -public class PlayerListWatcher extends DedicatedPlayerList { - private DedicatedPlayerList plist; +public class PlayerListWatcher { + private static Object plist; + private static Object mock; - public PlayerListWatcher(DedicatedServer minecraftserver) { + /*public PlayerListWatcher(DedicatedServer minecraftserver) { super(minecraftserver); // <-- Does some init stuff and calls Bukkit.setServer() so we have to use Objenesis } @@ -38,7 +32,7 @@ public class PlayerListWatcher extends DedicatedPlayerList { } @Override - public void sendMessage(IChatBaseComponent ichatbasecomponent, boolean flag) { // Needed so it calls the overriden method + public void sendMessage(IChatBaseComponent ichatbasecomponent, boolean flag) { // Needed so it calls the overridden method plist.getServer().sendMessage(ichatbasecomponent); ChatMessageType chatmessagetype = flag ? ChatMessageType.SYSTEM : ChatMessageType.CHAT; @@ -57,29 +51,50 @@ public class PlayerListWatcher extends DedicatedPlayerList { for (IChatBaseComponent component : iChatBaseComponents) { sendMessage(component, true); } - } + }*/ static void hookUp() throws Exception { - Field conf = CraftServer.class.getDeclaredField("console"); + val csc = Bukkit.getServer().getClass(); + Field conf = csc.getDeclaredField("console"); conf.setAccessible(true); - val server = (MinecraftServer) conf.get(Bukkit.getServer()); - val plw = new ObjenesisStd().newInstance(PlayerListWatcher.class); // Cannot call super constructor - plw.plist = (DedicatedPlayerList) server.getPlayerList(); - plw.maxPlayers = plw.plist.getMaxPlayers(); - Field plf = plw.getClass().getField("players"); + val server = conf.get(Bukkit.getServer()); + val nms = server.getClass().getPackage().getName(); + val dplc = Class.forName(nms + ".DedicatedPlayerList"); + mock = Mockito.mock(dplc, new Answer() { // Cannot call super constructor + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return invocation.getMethod().invoke(plist, invocation.getArguments()); + } + }); + plist = server.getClass().getMethod("getPlayerList").invoke(server); + try { + Field mpf = mock.getClass().getField("maxPlayers"); + mpf.setAccessible(true); + Field modf = mpf.getClass().getDeclaredField("modifiers"); + modf.setAccessible(true); + modf.set(mpf, mpf.getModifiers() & ~Modifier.FINAL); + mpf.set(mock, mpf.get(plist)); + } catch (NoSuchFieldException ignored) { + //The field no longer exists on 1.14 + } + Field plf = mock.getClass().getField("players"); plf.setAccessible(true); Field modf = plf.getClass().getDeclaredField("modifiers"); modf.setAccessible(true); modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); - plf.set(plw, plw.plist.players); - server.a(plw); + plf.set(mock, plf.get(plist)); + try { + server.getClass().getMethod("a", dplc).invoke(server, mock); + } catch (NoSuchMethodException e) { + server.getClass().getMethod("a", Class.forName(server.getClass().getPackage().getName() + ".PlayerList")).invoke(server, mock); + } Field pllf = CraftServer.class.getDeclaredField("playerList"); pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), plw); + pllf.set(Bukkit.getServer(), mock); } static boolean hookDown() throws Exception { - Field conf = CraftServer.class.getDeclaredField("console"); + /*Field conf = CraftServer.class.getDeclaredField("console"); conf.setAccessible(true); val server = (MinecraftServer) conf.get(Bukkit.getServer()); val plist = (DedicatedPlayerList) server.getPlayerList(); @@ -88,275 +103,7 @@ public class PlayerListWatcher extends DedicatedPlayerList { server.a(((PlayerListWatcher) plist).plist); Field pllf = CraftServer.class.getDeclaredField("playerList"); pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist); + pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist);*/ return true; } - - public void a(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) { - plist.a(entityhuman, ichatbasecomponent); - } - - public void a(EntityPlayer entityplayer, int i) { - plist.a(entityplayer, i); - } - - public void a(EntityPlayer entityplayer, WorldServer worldserver) { - plist.a(entityplayer, worldserver); - } - - public NBTTagCompound a(EntityPlayer entityplayer) { - return plist.a(entityplayer); - } - - public void a(int i) { - plist.a(i); - } - - public void a(NetworkManager networkmanager, EntityPlayer entityplayer) { - plist.a(networkmanager, entityplayer); - } - - public void a(Packet packet, int i) { - plist.a(packet, i); - } - - public EntityPlayer a(UUID uuid) { - return plist.a(uuid); - } - - public void addOp(GameProfile gameprofile) { - plist.addOp(gameprofile); - } - - public void addWhitelist(GameProfile gameprofile) { - plist.addWhitelist(gameprofile); - } - - public EntityPlayer attemptLogin(LoginListener loginlistener, GameProfile gameprofile, String hostname) { - return plist.attemptLogin(loginlistener, gameprofile, hostname); - } - - public String b(boolean flag) { - return plist.b(flag); - } - - public void b(EntityHuman entityhuman, IChatBaseComponent ichatbasecomponent) { - plist.b(entityhuman, ichatbasecomponent); - } - - public void b(EntityPlayer entityplayer, WorldServer worldserver) { - plist.b(entityplayer, worldserver); - } - - public List b(String s) { - return plist.b(s); - } - - public Location calculateTarget(Location enter, World target) { - return plist.calculateTarget(enter, target); - } - - public void changeDimension(EntityPlayer entityplayer, int i, TeleportCause cause) { - plist.changeDimension(entityplayer, i, cause); - } - - public void changeWorld(Entity entity, int i, WorldServer worldserver, WorldServer worldserver1) { - plist.changeWorld(entity, i, worldserver, worldserver1); - } - - public int d() { - return plist.d(); - } - - public void d(EntityPlayer entityplayer) { - plist.d(entityplayer); - } - - public String disconnect(EntityPlayer entityplayer) { - return plist.disconnect(entityplayer); - } - - public boolean equals(Object obj) { - return plist.equals(obj); - } - - public String[] f() { - return plist.f(); - } - - public void f(EntityPlayer entityplayer) { - plist.f(entityplayer); - } - - public boolean f(GameProfile gameprofile) { - return plist.f(gameprofile); - } - - public GameProfile[] g() { - return plist.g(); - } - - public boolean getHasWhitelist() { - return plist.getHasWhitelist(); - } - - public IpBanList getIPBans() { - return plist.getIPBans(); - } - - public int getMaxPlayers() { - return plist.getMaxPlayers(); - } - - public OpList getOPs() { - return plist.getOPs(); - } - - public EntityPlayer getPlayer(String s) { - return plist.getPlayer(s); - } - - public int getPlayerCount() { - return plist.getPlayerCount(); - } - - public GameProfileBanList getProfileBans() { - return plist.getProfileBans(); - } - - public String[] getSeenPlayers() { - return plist.getSeenPlayers(); - } - - public DedicatedServer getServer() { - return plist.getServer(); - } - - public WhiteList getWhitelist() { - return plist.getWhitelist(); - } - - public String[] getWhitelisted() { - return plist.getWhitelisted(); - } - - public AdvancementDataPlayer h(EntityPlayer entityplayer) { - return plist.h(entityplayer); - } - - public int hashCode() { - return plist.hashCode(); - } - - public boolean isOp(GameProfile gameprofile) { - return plist.isOp(gameprofile); - } - - public boolean isWhitelisted(GameProfile gameprofile) { - return plist.isWhitelisted(gameprofile); - } - - public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag, Location location, - boolean avoidSuffocation) { - return plist.moveToWorld(entityplayer, i, flag, location, avoidSuffocation); - } - - public EntityPlayer moveToWorld(EntityPlayer entityplayer, int i, boolean flag) { - return plist.moveToWorld(entityplayer, i, flag); - } - - public String[] n() { - return plist.n(); - } - - public void onPlayerJoin(EntityPlayer entityplayer, String joinMessage) { - plist.onPlayerJoin(entityplayer, joinMessage); - } - - public EntityPlayer processLogin(GameProfile gameprofile, EntityPlayer player) { - return plist.processLogin(gameprofile, player); - } - - public void reload() { - plist.reload(); - } - - public void reloadWhitelist() { - plist.reloadWhitelist(); - } - - public void removeOp(GameProfile gameprofile) { - plist.removeOp(gameprofile); - } - - public void removeWhitelist(GameProfile gameprofile) { - plist.removeWhitelist(gameprofile); - } - - public void repositionEntity(Entity entity, Location exit, boolean portal) { - plist.repositionEntity(entity, exit, portal); - } - - public int s() { - return plist.s(); - } - - public void savePlayers() { - plist.savePlayers(); - } - - @SuppressWarnings("rawtypes") - public void sendAll(Packet packet, EntityHuman entityhuman) { - plist.sendAll(packet, entityhuman); - } - - @SuppressWarnings("rawtypes") - public void sendAll(Packet packet, World world) { - plist.sendAll(packet, world); - } - - public void sendPacketNearby(EntityHuman entityhuman, double d0, double d1, double d2, double d3, int i, - Packet packet) { - plist.sendPacketNearby(entityhuman, d0, d1, d2, d3, i, packet); - } - - public void sendScoreboard(ScoreboardServer scoreboardserver, EntityPlayer entityplayer) { - plist.sendScoreboard(scoreboardserver, entityplayer); - } - - public void setHasWhitelist(boolean flag) { - plist.setHasWhitelist(flag); - } - - public void setPlayerFileData(WorldServer[] aworldserver) { - plist.setPlayerFileData(aworldserver); - } - - public NBTTagCompound t() { - return plist.t(); - } - - public void tick() { - plist.tick(); - } - - public String toString() { - return plist.toString(); - } - - public void u() { - plist.u(); - } - - public void updateClient(EntityPlayer entityplayer) { - plist.updateClient(entityplayer); - } - - public List v() { - return plist.v(); - } - - public ServerStatisticManager getStatisticManager(EntityPlayer entityhuman) { - return plist.getStatisticManager(entityhuman); - } } -- 2.30.2 From c456b2433360776f0ae9849f47618156e4f24b5f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 23 Aug 2019 01:58:47 +0200 Subject: [PATCH 089/108] Command handling improvement, PLW work More correct fallback for command handling Getting closer to finish PlayerListWatcher --- .../GeneralEventBroadcasterModule.java | 4 +- .../broadcaster/PlayerListWatcher.java | 106 ++++++++++-------- .../discordplugin/mcchat/MCChatListener.java | 6 +- 3 files changed, 68 insertions(+), 48 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 804e79e..44c2d79 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -12,7 +12,7 @@ public class GeneralEventBroadcasterModule extends Component { @Override protected void enable() { try { - PlayerListWatcher.hookUp(); + PlayerListWatcher.hookUpDown(true); DPUtils.getLogger().info("Finished hooking into the player list"); hooked = true; } catch (Exception e) { @@ -27,7 +27,7 @@ public class GeneralEventBroadcasterModule extends Component { protected void disable() { try { if (!hooked) return; - if (PlayerListWatcher.hookDown()) + if (PlayerListWatcher.hookUpDown(false)) DPUtils.getLogger().info("Finished unhooking the player list!"); else DPUtils.getLogger().info("Didn't have the player list hooked."); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index c0b39c5..e2b795f 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -1,8 +1,8 @@ package buttondevteam.discordplugin.broadcaster; +import buttondevteam.lib.TBMCCoreAPI; import lombok.val; import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -53,57 +53,75 @@ public class PlayerListWatcher { } }*/ - static void hookUp() throws Exception { + static boolean hookUpDown(boolean up) throws Exception { val csc = Bukkit.getServer().getClass(); Field conf = csc.getDeclaredField("console"); conf.setAccessible(true); val server = conf.get(Bukkit.getServer()); val nms = server.getClass().getPackage().getName(); val dplc = Class.forName(nms + ".DedicatedPlayerList"); - mock = Mockito.mock(dplc, new Answer() { // Cannot call super constructor - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return invocation.getMethod().invoke(plist, invocation.getArguments()); - } - }); - plist = server.getClass().getMethod("getPlayerList").invoke(server); - try { - Field mpf = mock.getClass().getField("maxPlayers"); - mpf.setAccessible(true); - Field modf = mpf.getClass().getDeclaredField("modifiers"); - modf.setAccessible(true); - modf.set(mpf, mpf.getModifiers() & ~Modifier.FINAL); - mpf.set(mock, mpf.get(plist)); - } catch (NoSuchFieldException ignored) { - //The field no longer exists on 1.14 - } - Field plf = mock.getClass().getField("players"); - plf.setAccessible(true); - Field modf = plf.getClass().getDeclaredField("modifiers"); - modf.setAccessible(true); - modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); - plf.set(mock, plf.get(plist)); - try { - server.getClass().getMethod("a", dplc).invoke(server, mock); - } catch (NoSuchMethodException e) { - server.getClass().getMethod("a", Class.forName(server.getClass().getPackage().getName() + ".PlayerList")).invoke(server, mock); - } - Field pllf = CraftServer.class.getDeclaredField("playerList"); - pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), mock); - } + val currentPL = server.getClass().getMethod("getPlayerList").invoke(server); + if (up) { + mock = Mockito.mock(dplc, new Answer() { // Cannot call super constructor + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + if (!invocation.getMethod().getName().equals("sendMessage")) + return invocation.getMethod().invoke(plist, invocation.getArguments()); + val args = invocation.getArguments(); + val params = invocation.getMethod().getParameterTypes(); + if (params.length == 0) { + TBMCCoreAPI.SendException("Found a strange method", + new Exception("Found a sendMessage() method without arguments.")); + return null; + } + if (params[0].getSimpleName().equals("IChatBaseComponent[]")) + for (val arg : (Object[]) args[0]) + sendMessage(arg, true); + else if (params[0].getSimpleName().equals("IChatBaseComponent")) + if (params.length > 1 && params[1].getSimpleName().equalsIgnoreCase("boolean")) + sendMessage(args[0], (Boolean) args[1]); + else + sendMessage(args[0], true); + else + TBMCCoreAPI.SendException("Found a method with interesting params", + new Exception("Found a sendMessage(" + params[0].getSimpleName() + ") method")); + return null; + } - static boolean hookDown() throws Exception { - /*Field conf = CraftServer.class.getDeclaredField("console"); - conf.setAccessible(true); - val server = (MinecraftServer) conf.get(Bukkit.getServer()); - val plist = (DedicatedPlayerList) server.getPlayerList(); - if (!(plist instanceof PlayerListWatcher)) - return false; - server.a(((PlayerListWatcher) plist).plist); - Field pllf = CraftServer.class.getDeclaredField("playerList"); + private void sendMessage(Object chatComponent, boolean system) { + //TODO + } + }); + plist = currentPL; + try { + Field mpf = mock.getClass().getField("maxPlayers"); + mpf.setAccessible(true); + Field modf = mpf.getClass().getDeclaredField("modifiers"); + modf.setAccessible(true); + modf.set(mpf, mpf.getModifiers() & ~Modifier.FINAL); + mpf.set(mock, mpf.get(plist)); + } catch (NoSuchFieldException ignored) { + //The field no longer exists on 1.14 + } + Field plf = mock.getClass().getField("players"); + plf.setAccessible(true); + Field modf = plf.getClass().getDeclaredField("modifiers"); + modf.setAccessible(true); + modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); + plf.set(mock, plf.get(plist)); + } else { + if (!(mock instanceof PlayerListWatcher)) + return false; + } + try { + server.getClass().getMethod("a", dplc).invoke(server, up ? mock : plist); + } catch (NoSuchMethodException e) { + server.getClass().getMethod("a", Class.forName(server.getClass().getPackage().getName() + ".PlayerList")) + .invoke(server, up ? mock : plist); + } + Field pllf = csc.getDeclaredField("playerList"); pllf.setAccessible(true); - pllf.set(Bukkit.getServer(), ((PlayerListWatcher) plist).plist);*/ + pllf.set(Bukkit.getServer(), up ? mock : plist); return true; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 4ff36cb..f1f81d6 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -347,10 +347,12 @@ public class MCChatListener implements Listener { VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd); else if (mcpackage.contains("1_14")) VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd); + else + Bukkit.dispatchCommand(dsender, cmd); } catch (NoClassDefFoundError e) { - Bukkit.dispatchCommand(dsender, cmd); + TBMCCoreAPI.SendException("A class is not found when trying to run command " + cmd + "!", e); } - Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmdlowercased); + Bukkit.getLogger().info(dsender.getName() + " issued command from Discord: /" + cmd); if (clmd != null) channel.set(chtmp); }); -- 2.30.2 From 2963990b5e62fd50ac7e45f6f3baa7d03b582162 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 23 Aug 2019 21:52:52 +0200 Subject: [PATCH 090/108] Check if Minecraft is a game role --- .../discordplugin/role/GameRoleModule.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 0ab0cac..3c6e775 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin.role; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ReadOnlyConfigData; import discord4j.core.event.domain.role.RoleCreateEvent; @@ -89,11 +90,24 @@ public class GameRoleModule extends Component { } private Mono isGameRole(Role r) { - if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) + boolean debug = r.getName().equalsIgnoreCase("Minecraft"); + if (debug) TBMCCoreAPI.sendDebugMessage("Checking if Minecraft is a game role..."); + if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) { + if (debug) TBMCCoreAPI.sendDebugMessage("Not in the main server: " + r.getGuildId().asString()); return Mono.just(false); //Only allow on the main server + } val rc = new Color(149, 165, 166, 0); - 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); + if (debug) TBMCCoreAPI.sendDebugMessage("Game role color: " + rc + " - MC color: " + r.getColor()); + return Mono.just(r.getColor().equals(rc)) + .doAfterSuccessOrError((b, e) -> { + if (debug) TBMCCoreAPI.sendDebugMessage("1. b: " + b + " - e: " + e); + }).filter(b -> b).flatMap(b -> + DiscordPlugin.dc.getSelf().flatMap(u -> u.asMember(DiscordPlugin.mainServer.getId())) + .doAfterSuccessOrError((m, e) -> { + if (debug) TBMCCoreAPI.sendDebugMessage("2. m: " + m.getDisplayName() + " e: " + e); + }).flatMap(m -> m.hasHigherRoles(Collections.singleton(r)))) //Below one of our roles + .doAfterSuccessOrError((b, e) -> { + if (debug) TBMCCoreAPI.sendDebugMessage("3. b: " + b + " - e: " + e); + }).defaultIfEmpty(false); } } -- 2.30.2 From 91f1c8c4f75673580b91b389ccb485dc58870fd8 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 25 Aug 2019 03:23:14 +0200 Subject: [PATCH 091/108] Probably fixed PLW Mostly yesterday --- .../broadcaster/PlayerListWatcher.java | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index e2b795f..e1fbbe2 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin.broadcaster; +import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.TBMCCoreAPI; import lombok.val; import org.bukkit.Bukkit; @@ -8,6 +9,7 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class PlayerListWatcher { @@ -62,13 +64,38 @@ public class PlayerListWatcher { val dplc = Class.forName(nms + ".DedicatedPlayerList"); val currentPL = server.getClass().getMethod("getPlayerList").invoke(server); if (up) { + val icbcl = Class.forName(nms + ".IChatBaseComponent"); + val sendMessage = server.getClass().getMethod("sendMessage", icbcl); + val cmtcl = Class.forName(nms + ".ChatMessageType"); + val systemType = cmtcl.getDeclaredField("SYSTEM").get(null); + val chatType = cmtcl.getDeclaredField("CHAT").get(null); + + val obc = csc.getPackage().getName(); + val ccmcl = Class.forName(obc + ".util.CraftChatMessage"); + val fixComponent = ccmcl.getMethod("fixComponent", icbcl); + val ppoc = Class.forName(nms + ".PacketPlayOutChat"); + val ppocC = Class.forName(nms + ".PacketPlayOutChat").getConstructor(icbcl, cmtcl); + val sendAll = dplc.getMethod("sendAll", Class.forName(nms + ".Packet")); + Method tpt; + try { + tpt = icbcl.getMethod("toPlainText"); + } catch (NoSuchMethodException e) { + tpt = icbcl.getMethod("getString"); + } + val toPlainText = tpt; mock = Mockito.mock(dplc, new Answer() { // Cannot call super constructor @Override public Object answer(InvocationOnMock invocation) throws Throwable { - if (!invocation.getMethod().getName().equals("sendMessage")) - return invocation.getMethod().invoke(plist, invocation.getArguments()); + final Method method = invocation.getMethod(); + if (!method.getName().equals("sendMessage")) { + if (method.getName().equals("sendAll")) { + sendAll(invocation.getArgument(0)); + return null; + } + return method.invoke(plist, invocation.getArguments()); + } val args = invocation.getArguments(); - val params = invocation.getMethod().getParameterTypes(); + val params = method.getParameterTypes(); if (params.length == 0) { TBMCCoreAPI.SendException("Found a strange method", new Exception("Found a sendMessage() method without arguments.")); @@ -89,7 +116,29 @@ public class PlayerListWatcher { } private void sendMessage(Object chatComponent, boolean system) { - //TODO + try { //Converted to use reflection + sendMessage.invoke(server, chatComponent); + Object chatmessagetype = system ? systemType : chatType; + + // CraftBukkit start - we run this through our processor first so we can get web links etc + this.sendAll(ppocC.newInstance(fixComponent.invoke(null, chatComponent), chatmessagetype)); + // CraftBukkit end + } catch (Exception e) { + TBMCCoreAPI.SendException("An error occurred while passing a vanilla message through the player list", e); + } + } + + private void sendAll(Object packet) { + try { // Some messages get sent by directly constructing a packet + sendAll.invoke(plist, packet); + if (packet.getClass() == ppoc) { + Field msgf = ppoc.getDeclaredField("a"); + msgf.setAccessible(true); + MCChatUtils.forAllMCChat(MCChatUtils.send((String) toPlainText.invoke(msgf.get(packet)))); + } + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e); + } } }); plist = currentPL; -- 2.30.2 From e4d5dcd0a2ad242669a80fd35eb52c29b6553936 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 26 Aug 2019 00:57:16 +0200 Subject: [PATCH 092/108] Update D4J & role debug refined & fixed a ) PLW tested and confirmed working Moved a ) to fix #105 --- pom.xml | 2 +- .../discordplugin/mcchat/MCChatListener.java | 4 ++-- .../discordplugin/role/GameRoleModule.java | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index c9d1eb8..1b74b55 100755 --- a/pom.xml +++ b/pom.xml @@ -193,7 +193,7 @@ com.discord4j discord4j-core - 3.0.6 + 3.0.8 diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index f1f81d6..2314994 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -233,8 +233,8 @@ public class MCChatListener implements Listener { 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 + && author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false)) + && !hasCustomChat); //Chat isn't enabled on this channel }).filter(channel -> { timings.printElapsed("Filter 2"); return !(channel instanceof PrivateChannel //Only in private chat diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index 3c6e775..babb47c 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -27,7 +27,7 @@ public class GameRoleModule extends Component { @Override protected void enable() { getPlugin().getManager().registerCommand(new RoleCommand(this)); - GameRoles = DiscordPlugin.mainServer.getRoles().filterWhen(this::isGameRole).map(Role::getName).collect(Collectors.toList()).block(); + GameRoles = DiscordPlugin.mainServer.getRoles().filterWhen(r -> isGameRole(r, false)).map(Role::getName).collect(Collectors.toList()).block(); } @Override @@ -47,7 +47,7 @@ public class GameRoleModule extends Component { if (roleEvent instanceof RoleCreateEvent) { Bukkit.getScheduler().runTaskLaterAsynchronously(DiscordPlugin.plugin, () -> { Role role=((RoleCreateEvent) roleEvent).getRole(); - grm.isGameRole(role).flatMap(b -> { + grm.isGameRole(role, false).flatMap(b -> { if (!b) return Mono.empty(); //Deleted or not a game role GameRoles.add(role.getName()); @@ -68,7 +68,7 @@ public class GameRoleModule extends Component { return; } Role or=event.getOld().get(); - grm.isGameRole(event.getCurrent()).flatMap(b -> { + grm.isGameRole(event.getCurrent(), true).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.")); @@ -89,8 +89,8 @@ public class GameRoleModule extends Component { } } - private Mono isGameRole(Role r) { - boolean debug = r.getName().equalsIgnoreCase("Minecraft"); + private Mono isGameRole(Role r, boolean debugMC) { + boolean debug = debugMC && r.getName().equalsIgnoreCase("Minecraft"); if (debug) TBMCCoreAPI.sendDebugMessage("Checking if Minecraft is a game role..."); if (r.getGuildId().asLong() != DiscordPlugin.mainServer.getId().asLong()) { if (debug) TBMCCoreAPI.sendDebugMessage("Not in the main server: " + r.getGuildId().asString()); -- 2.30.2 From ea0ef88068300f57d4b1d57331cd40ad098db24d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 26 Aug 2019 22:26:10 +0200 Subject: [PATCH 093/108] Automatically get client ID for link, improvements Literally 2 improvements --- src/main/java/buttondevteam/discordplugin/DiscordPlugin.java | 5 ++++- .../discordplugin/mcchat/ChannelconCommand.java | 4 ++-- .../discordplugin/mcchat/MinecraftChatModule.java | 3 +++ src/main/resources/plugin.yml | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index b5a0efc..ab63ebe 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -142,9 +142,13 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards + getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); + dc.getApplicationInfo().subscribe(info -> { + getLogger().severe("Click here: https://discordapp.com/oauth2/authorize?client_id=" + info.getId().asString() + "&scope=bot&permissions=268509264"); + }); saveConfig(); //Put default there return; //We should have all guilds by now, no need to retry } @@ -200,7 +204,6 @@ public class DiscordPlugin extends ButtonPlugin { CommonListeners.register(dc.getEventDispatcher()); 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)); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index d51a4b0..be1d284 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -31,7 +31,7 @@ import java.util.stream.Collectors; "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 / prefix only works in #bot.", // - "Invite link: " // + "Invite link: " // }) @RequiredArgsConstructor public class ChannelconCommand extends ICommand2DC { @@ -155,7 +155,7 @@ public class ChannelconCommand extends ICommand2DC { "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() + ".", // - "Invite link: " // TODO: Set correct client ID + "Invite link: " }; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index a44986a..b4586e1 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -104,10 +104,13 @@ public class MinecraftChatModule extends Component { return getConfig().getData("allowPrivateChat", true); } + String clientID; + @Override protected void enable() { if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) return; + DiscordPlugin.dc.getApplicationInfo().subscribe(info -> clientID = info.getId().asString()); 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 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6507c5b..e045c2b 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,8 @@ -name: Thorpe-Discord +name: Chroma-Discord main: buttondevteam.discordplugin.DiscordPlugin version: 1.0 author: NorbiPeti -depend: [ThorpeCore] +depend: [ChromaCore] commands: discord: website: 'https://github.com/TBMCPlugins/DiscordPlugin' -- 2.30.2 From acd45ce4aebe5d6a33299bf2ac917a1fbf24ad33 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 11 Sep 2019 15:30:07 +0200 Subject: [PATCH 094/108] Hopefully fixed the issue of multiple ready events #107 --- .../java/buttondevteam/discordplugin/DiscordPlugin.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index ab63ebe..38afecc 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -141,6 +141,10 @@ public class DiscordPlugin extends ButtonPlugin { private void handleReady(List event) { try { + if(!SafeMode) { + getLogger().info("Ready again, already enabled."); //TODO: It should probably handle disconnections + return; + } mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works if (mainServer == null) { @@ -264,8 +268,8 @@ public class DiscordPlugin extends ButtonPlugin { try { SafeMode = true; // Stop interacting with Discord ChromaBot.delete(); - timings.printElapsed("Updating presence..."); - dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing + //timings.printElapsed("Updating presence..."); + //dc.updatePresence(Presence.idle(Activity.playing("logging out"))).block(); //No longer using the same account for testing timings.printElapsed("Logging out..."); dc.logout().block(); //Configs are emptied so channels and servers are fetched again -- 2.30.2 From ef44aa883064e4270c1322b8a207a98abcb5d78d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 11 Sep 2019 15:33:02 +0200 Subject: [PATCH 095/108] Fix build (Java 8) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 808d9b0..1d962ae 100755 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ language: java jdk: - oraclejdk8 sudo: true +dist: trusty # Needed for Java 8, although we might not need Java 8 deploy: # deploy develop to the staging environment - provider: script -- 2.30.2 From 3bd7b879c4bac3dbb35641d99571aabf559e1ade Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 15 Sep 2019 03:33:30 +0200 Subject: [PATCH 096/108] Hopefully fixed the #106 issue Also removed mock check a while ago --- .../discordplugin/DiscordConnectedPlayer.java | 11 +++++++++++ .../discordplugin/broadcaster/PlayerListWatcher.java | 3 --- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index b5d7da4..33fae6b 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -9,6 +9,7 @@ import lombok.Setter; import lombok.experimental.Delegate; import org.bukkit.*; import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.permissions.PermissibleBase; @@ -144,6 +145,16 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement location.getYaw(), location.getPitch()); } + @Override + public double getMaxHealth() { + return 20; + } + + @Override + public Player getPlayer() { + return this; + } + @Getter @Setter private String displayName; diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index e1fbbe2..6bfb220 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -158,9 +158,6 @@ public class PlayerListWatcher { modf.setAccessible(true); modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); plf.set(mock, plf.get(plist)); - } else { - if (!(mock instanceof PlayerListWatcher)) - return false; } try { server.getClass().getMethod("a", dplc).invoke(server, up ? mock : plist); -- 2.30.2 From f1cec2ced1f954390102ba756e599fdeaeb68333 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 20 Oct 2019 20:50:29 +0200 Subject: [PATCH 097/108] Update to Java 10/11 & fake player remove Apparently --- pom.xml | 10 +- .../discordplugin/mcchat/MCChatListener.java | 2 +- .../discordplugin/mcchat/MCChatUtils.java | 1 - .../playerfaker/DiscordEntity.java | 308 -------- .../playerfaker/DiscordFakePlayer.java | 746 ------------------ .../playerfaker/DiscordHumanEntity.java | 168 ---- .../playerfaker/DiscordInventory.java | 212 ----- .../playerfaker/DiscordLivingEntity.java | 288 ------- .../playerfaker/DiscordPlayerInventory.java | 105 --- .../playerfaker/perm/LPInjector.java | 14 +- 10 files changed, 13 insertions(+), 1841 deletions(-) delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordEntity.java delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordFakePlayer.java delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordHumanEntity.java delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordLivingEntity.java delete mode 100755 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordPlayerInventory.java diff --git a/pom.xml b/pom.xml index 1b74b55..20b2069 100755 --- a/pom.xml +++ b/pom.xml @@ -38,8 +38,8 @@ maven-compiler-plugin 3.6.2 - 1.8 - 1.8 + 10 + 10 @@ -223,7 +223,7 @@ org.projectlombok lombok - 1.16.16 + 1.18.10 provided - - - org.apache.maven.plugins maven-shade-plugin diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index 6bfb220..a424555 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -142,22 +142,15 @@ public class PlayerListWatcher { } }); plist = currentPL; - try { - Field mpf = mock.getClass().getField("maxPlayers"); - mpf.setAccessible(true); - Field modf = mpf.getClass().getDeclaredField("modifiers"); - modf.setAccessible(true); - modf.set(mpf, mpf.getModifiers() & ~Modifier.FINAL); - mpf.set(mock, mpf.get(plist)); - } catch (NoSuchFieldException ignored) { - //The field no longer exists on 1.14 + for (var plc = dplc; plc != null; plc = plc.getSuperclass()) { //Set all fields + for (var f : plc.getDeclaredFields()) { + f.setAccessible(true); + Field modf = f.getClass().getDeclaredField("modifiers"); + modf.setAccessible(true); + modf.set(f, f.getModifiers() & ~Modifier.FINAL); + f.set(mock, f.get(plist)); + } } - Field plf = mock.getClass().getField("players"); - plf.setAccessible(true); - Field modf = plf.getClass().getDeclaredField("modifiers"); - modf.setAccessible(true); - modf.set(plf, plf.getModifiers() & ~Modifier.FINAL); - plf.set(mock, plf.get(plist)); } try { server.getClass().getMethod("a", dplc).invoke(server, up ? mock : plist); -- 2.30.2 From 73fc4aedcc7e1413dbffd1aee656eb296dc67aeb Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 27 Oct 2019 02:33:13 +0100 Subject: [PATCH 099/108] Fixed DCP inventory, have no idea about MassiveCore Essentials error is fixed #106 --- .../discordplugin/DiscordConnectedPlayer.java | 47 +++- .../playerfaker/DiscordInventory.java | 208 ++++++++++++++++++ .../buttondevteam/DiscordPlugin/AppTest.java | 76 ++++--- 3 files changed, 293 insertions(+), 38 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index 33fae6b..31311b8 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.playerfaker.DiscordInventory; import buttondevteam.discordplugin.playerfaker.VCMDWrapper; import discord4j.core.object.entity.MessageChannel; import discord4j.core.object.entity.User; @@ -12,14 +13,19 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.PlayerInventory; import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.ServerOperator; -import org.mockito.Answers; +import org.mockito.MockSettings; import org.mockito.Mockito; +import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.UUID; +import static org.mockito.Answers.RETURNS_DEFAULTS; + public abstract class DiscordConnectedPlayer extends DiscordSenderBase implements IMCPlayer { private @Getter VCMDWrapper vanillaCmdListener; @Getter @@ -37,7 +43,7 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement @Setter private PermissibleBase perm; - private Location location = Bukkit.getWorlds().get(0).getSpawnLocation(); + private Location location; private final MinecraftChatModule module; @@ -50,6 +56,7 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement protected DiscordConnectedPlayer(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { super(user, channel); + location = Bukkit.getWorlds().get(0).getSpawnLocation(); origPerm = perm = new PermissibleBase(basePlayer = Bukkit.getOfflinePlayer(uuid)); name = mcname; this.module = module; @@ -64,6 +71,15 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement } } + /** + * For testing + */ + protected DiscordConnectedPlayer(User user, MessageChannel channel) { + super(user, channel); + module = null; + uniqueId = UUID.randomUUID(); + } + public void setOp(boolean value) { //CraftPlayer-compatible implementation this.origPerm.setOp(value); this.perm.recalculatePermissions(); @@ -161,7 +177,30 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { - return Mockito.mock(DiscordConnectedPlayer.class, Mockito.withSettings() - .defaultAnswer(Answers.CALLS_REAL_METHODS).useConstructor(user, channel, uuid, mcname, module)); + return Mockito.mock(DiscordConnectedPlayer.class, + getSettings().useConstructor(user, channel, uuid, mcname, module)); + } + + public static DiscordConnectedPlayer createTest() { + return Mockito.mock(DiscordConnectedPlayer.class, getSettings().useConstructor(null, null)); + } + + private static MockSettings getSettings() { + return Mockito.withSettings() + .defaultAnswer(invocation -> { + try { + if (!Modifier.isAbstract(invocation.getMethod().getModifiers())) + return invocation.callRealMethod(); + if (PlayerInventory.class.isAssignableFrom(invocation.getMethod().getReturnType())) + return Mockito.mock(DiscordInventory.class, Mockito.withSettings().extraInterfaces(PlayerInventory.class)); + if (Inventory.class.isAssignableFrom(invocation.getMethod().getReturnType())) + return new DiscordInventory(); + return RETURNS_DEFAULTS.answer(invocation); + } catch (Exception e) { + System.err.println("Error in mocked player!"); + e.printStackTrace(); + return RETURNS_DEFAULTS.answer(invocation); + } + }); } } diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java new file mode 100644 index 0000000..ab22f52 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/DiscordInventory.java @@ -0,0 +1,208 @@ +package buttondevteam.discordplugin.playerfaker; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import java.util.*; +import java.util.stream.IntStream; + +public class DiscordInventory implements Inventory { + private ItemStack[] items = new ItemStack[27]; + private List itemStacks = Arrays.asList(items); + @Getter + @Setter + public int maxStackSize; + private static ItemStack emptyStack = new ItemStack(Material.AIR, 0); + + @Override + public int getSize() { + return items.length; + } + + @Override + public String getName() { + return "Discord inventory"; + } + + @Override + public ItemStack getItem(int index) { + if (index >= items.length) + return emptyStack; + else + return items[index]; + } + + @Override + public void setItem(int index, ItemStack item) { + if (index < items.length) + items[index] = item; + } + + @Override + public HashMap addItem(ItemStack... items) throws IllegalArgumentException { + return IntStream.range(0, items.length).collect(HashMap::new, (map, i) -> map.put(i, items[i]), HashMap::putAll); //Pretend that we can't add anything + } + + @Override + public HashMap removeItem(ItemStack... items) throws IllegalArgumentException { + return IntStream.range(0, items.length).collect(HashMap::new, (map, i) -> map.put(i, items[i]), HashMap::putAll); //Pretend that we can't add anything + } + + @Override + public ItemStack[] getContents() { + return items; + } + + @Override + public void setContents(ItemStack[] items) throws IllegalArgumentException { + this.items = items; + } + + @Override + public ItemStack[] getStorageContents() { + return items; + } + + @Override + public void setStorageContents(ItemStack[] items) throws IllegalArgumentException { + this.items = items; + } + + @SuppressWarnings("deprecation") + @Override + public boolean contains(int materialId) { + return itemStacks.stream().anyMatch(is -> is.getType().getId() == materialId); + } + + @Override + public boolean contains(Material material) throws IllegalArgumentException { + return itemStacks.stream().anyMatch(is -> is.getType() == material); + } + + @Override + public boolean contains(ItemStack item) { + return itemStacks.stream().anyMatch(is -> is.getType() == item.getType() && is.getAmount() == item.getAmount()); + } + + @SuppressWarnings("deprecation") + @Override + public boolean contains(int materialId, int amount) { + return itemStacks.stream().anyMatch(is -> is.getType().getId() == materialId && is.getAmount() == amount); + } + + @Override + public boolean contains(Material material, int amount) throws IllegalArgumentException { + return itemStacks.stream().anyMatch(is -> is.getType() == material && is.getAmount() == amount); + } + + @Override + public boolean contains(ItemStack item, int amount) { //Not correct implementation but whatever + return itemStacks.stream().anyMatch(is -> is.getType() == item.getType() && is.getAmount() == amount); + } + + @Override + public boolean containsAtLeast(ItemStack item, int amount) { + return false; + } + + @Override + public HashMap all(int materialId) { + return new HashMap<>(); + } + + @Override + public HashMap all(Material material) throws IllegalArgumentException { + return new HashMap<>(); + } + + @Override + public HashMap all(ItemStack item) { + return new HashMap<>(); + } + + @Override + public int first(int materialId) { + return -1; + } + + @Override + public int first(Material material) throws IllegalArgumentException { + return -1; + } + + @Override + public int first(ItemStack item) { + return -1; + } + + @Override + public int firstEmpty() { + return -1; + } + + @Override + public void remove(int materialId) { + } + + @Override + public void remove(Material material) throws IllegalArgumentException { + } + + @Override + public void remove(ItemStack item) { + } + + @Override + public void clear(int index) { + if (index < items.length) + items[index] = null; + } + + @Override + public void clear() { + Arrays.fill(items, null); + } + + @Override + public List getViewers() { + return Collections.emptyList(); + } + + @Override + public String getTitle() { + return "Discord inventory"; + } + + @Override + public InventoryType getType() { + return InventoryType.CHEST; + } + + @Override + public InventoryHolder getHolder() { + return null; + } + + @SuppressWarnings("NullableProblems") + @Override + public ListIterator iterator() { + return itemStacks.listIterator(); + } + + @Override + public ListIterator iterator(int index) { + return itemStacks.listIterator(index); + } + + @Override + public Location getLocation() { + return null; + } +} diff --git a/src/test/java/buttondevteam/DiscordPlugin/AppTest.java b/src/test/java/buttondevteam/DiscordPlugin/AppTest.java index 46ad699..93dbbb4 100755 --- a/src/test/java/buttondevteam/DiscordPlugin/AppTest.java +++ b/src/test/java/buttondevteam/DiscordPlugin/AppTest.java @@ -1,34 +1,42 @@ -package buttondevteam.DiscordPlugin; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest extends TestCase { - /** - * Create the test case - * - * @param testName - * name of the test case - */ - public AppTest(String testName) { - super(testName); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() { - return new TestSuite(AppTest.class); - } - - /** - * Rigourous Test :-) - */ - public void testApp() { - assertTrue(true); - } -} +package buttondevteam.DiscordPlugin; + +import buttondevteam.discordplugin.DiscordConnectedPlayer; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.bukkit.entity.Damageable; +import org.bukkit.entity.Player; + +/** + * Unit test for simple App. + */ +public class AppTest extends TestCase { + /** + * Create the test case + * + * @param testName + * name of the test case + */ + public AppTest(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(AppTest.class); + } + + /** + * Rigourous Test :-) + */ + public void testApp() { + Player dcp = DiscordConnectedPlayer.createTest(); + + double h = dcp.getMaxHealth(); + System.out.println(h); + Damageable d = (Damageable) dcp; + System.out.println(d.getMaxHealth()); + } +} -- 2.30.2 From 98ee2ce771242f81fbe2402e18d0d7954eeb4e50 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 27 Oct 2019 23:27:54 +0100 Subject: [PATCH 100/108] Fixed the MassiveCore error but there's more #106 --- .../discordplugin/DiscordConnectedPlayer.java | 47 +++++++++++++++++++ .../buttondevteam/DiscordPlugin/AppTest.java | 6 +-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index 31311b8..c457d2a 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -9,6 +9,9 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Delegate; import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.player.AsyncPlayerChatEvent; @@ -21,6 +24,8 @@ import org.mockito.MockSettings; import org.mockito.Mockito; import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.UUID; @@ -175,6 +180,48 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement @Setter private String displayName; + @Override + public AttributeInstance getAttribute(Attribute attribute) { + return new AttributeInstance() { + @Override + public Attribute getAttribute() { + return attribute; + } + + @Override + public double getBaseValue() { + return getDefaultValue(); + } + + @Override + public void setBaseValue(double value) { + } + + @Override + public Collection getModifiers() { + return Collections.emptyList(); + } + + @Override + public void addModifier(AttributeModifier modifier) { + } + + @Override + public void removeModifier(AttributeModifier modifier) { + } + + @Override + public double getValue() { + return getDefaultValue(); + } + + @Override + public double getDefaultValue() { + return 20; //Works for max health, should be okay for the rest + } + }; + } + public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { return Mockito.mock(DiscordConnectedPlayer.class, diff --git a/src/test/java/buttondevteam/DiscordPlugin/AppTest.java b/src/test/java/buttondevteam/DiscordPlugin/AppTest.java index 93dbbb4..4b8bbb9 100755 --- a/src/test/java/buttondevteam/DiscordPlugin/AppTest.java +++ b/src/test/java/buttondevteam/DiscordPlugin/AppTest.java @@ -4,7 +4,7 @@ import buttondevteam.discordplugin.DiscordConnectedPlayer; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; -import org.bukkit.entity.Damageable; +import org.bukkit.attribute.Attribute; import org.bukkit.entity.Player; /** @@ -34,9 +34,7 @@ public class AppTest extends TestCase { public void testApp() { Player dcp = DiscordConnectedPlayer.createTest(); - double h = dcp.getMaxHealth(); + double h = dcp.getAttribute(Attribute.GENERIC_MAX_HEALTH).getDefaultValue(); ; ; System.out.println(h); - Damageable d = (Damageable) dcp; - System.out.println(d.getMaxHealth()); } } -- 2.30.2 From 9caf4c54edd0021f4d5431f929d41f0adf051c59 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Oct 2019 15:05:31 +0100 Subject: [PATCH 101/108] Fixed that last error #106 --- .../buttondevteam/discordplugin/DiscordConnectedPlayer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index c457d2a..ee0aa81 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -222,6 +222,11 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement }; } + @Override + public GameMode getGameMode() { + return GameMode.SPECTATOR; + } + public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { return Mockito.mock(DiscordConnectedPlayer.class, -- 2.30.2 From 02f60c2162ae81ec39c1aa0e5ffba86c1f1e47c7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 7 Nov 2019 00:20:57 +0100 Subject: [PATCH 102/108] Fix client ID race condition, attempt to fix URL escaping --- .../buttondevteam/discordplugin/DPUtils.java | 23 ++++++++++++++++--- .../mcchat/ChannelconCommand.java | 2 +- .../mcchat/MinecraftChatModule.java | 5 ++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 84d2ced..ff81da4 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -15,11 +15,19 @@ import lombok.val; import reactor.core.publisher.Mono; import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.Optional; +import java.util.TreeSet; +import java.util.function.Function; import java.util.logging.Logger; -import java.util.regex.Matcher; +import java.util.regex.MatchResult; +import java.util.regex.Pattern; public final class DPUtils { + public static final Pattern URL_PATTERN = Pattern.compile("https?://\\S*"); + public static final Pattern FORMAT_PATTERN = Pattern.compile("[*_~]"); + public static EmbedCreateSpec embedWithHead(EmbedCreateSpec ecs, String displayname, String playername, String profileUrl) { return ecs.setAuthor(displayname, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png"); } @@ -51,8 +59,17 @@ public final class DPUtils { } private static String escape(String message) { - return message.replaceAll("([*_~])", Matcher.quoteReplacement("\\") + "$1"); - } + //var ts = new TreeSet<>(); + var ts = new TreeSet(Comparator.comparingInt(a -> a[0])); //Compare the start, then check the end + var matcher = URL_PATTERN.matcher(message); + while (matcher.find()) + ts.add(new int[]{matcher.start(), matcher.end()}); + matcher = FORMAT_PATTERN.matcher(message); + Function aFunctionalInterface = result -> + Optional.ofNullable(ts.floor(new int[]{result.start(), 0})).map(a -> a[1]).orElse(0) < result.start() + ? "\\\\" + result.group() : result.group(); + return matcher.replaceAll(aFunctionalInterface); //Find nearest URL match and if it's not reaching to the char then escape + } //TODO: Java 11 method overload, not present in Java 8 public static Logger getLogger() { if (DiscordPlugin.plugin == null || DiscordPlugin.plugin.getLogger() == null) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index be1d284..38a0229 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -155,7 +155,7 @@ public class ChannelconCommand extends ICommand2DC { "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() + ".", // - "Invite link: " + "Invite link: " }; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index b4586e1..4862c6a 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -104,13 +104,12 @@ public class MinecraftChatModule extends Component { return getConfig().getData("allowPrivateChat", true); } - String clientID; - @Override protected void enable() { if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) return; - DiscordPlugin.dc.getApplicationInfo().subscribe(info -> clientID = info.getId().asString()); + /*clientID = DiscordPlugin.dc.getApplicationInfo().blockOptional().map(info->info.getId().asString()) + .orElse("Unknown"); //Need to block because otherwise it may not be set in time*/ 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 -- 2.30.2 From 19463963e3bdbe1d3dc28d20df59d2442f7684df Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Nov 2019 01:52:49 +0100 Subject: [PATCH 103/108] Make channels default to 0, profile URL config Fix URL not-escaping Made the plugin only attempt to access channels that are not set to 0 #110 --- .../buttondevteam/discordplugin/DPUtils.java | 28 ++++++++++++++----- .../discordplugin/DiscordPlugin.java | 2 +- .../announcer/AnnouncerModule.java | 4 +-- .../exceptions/ExceptionListenerModule.java | 2 +- .../discordplugin/fun/FunModule.java | 2 +- .../discordplugin/mcchat/MCChatListener.java | 9 +++--- .../mcchat/MinecraftChatModule.java | 9 +++++- .../discordplugin/role/GameRoleModule.java | 2 +- 8 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index ff81da4..6f3b82c 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -18,9 +18,7 @@ import javax.annotation.Nullable; import java.util.Comparator; import java.util.Optional; import java.util.TreeSet; -import java.util.function.Function; import java.util.logging.Logger; -import java.util.regex.MatchResult; import java.util.regex.Pattern; public final class DPUtils { @@ -65,11 +63,19 @@ public final class DPUtils { while (matcher.find()) ts.add(new int[]{matcher.start(), matcher.end()}); matcher = FORMAT_PATTERN.matcher(message); - Function aFunctionalInterface = result -> + /*Function aFunctionalInterface = result -> Optional.ofNullable(ts.floor(new int[]{result.start(), 0})).map(a -> a[1]).orElse(0) < result.start() ? "\\\\" + result.group() : result.group(); - return matcher.replaceAll(aFunctionalInterface); //Find nearest URL match and if it's not reaching to the char then escape - } //TODO: Java 11 method overload, not present in Java 8 + return matcher.replaceAll(aFunctionalInterface); //Find nearest URL match and if it's not reaching to the char then escape*/ + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, Optional.ofNullable(ts.floor(new int[]{matcher.start(), 0})) //Find a URL start <= our start + .map(a -> a[1]).orElse(-1) < matcher.start() //Check if URL end < our start + ? "\\\\" + matcher.group() : matcher.group()); + } + matcher.appendTail(sb); + return sb.toString(); + } public static Logger getLogger() { if (DiscordPlugin.plugin == null || DiscordPlugin.plugin.getLogger() == null) @@ -77,8 +83,8 @@ public final class DPUtils { return DiscordPlugin.plugin.getLogger(); } - 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 ReadOnlyConfigData> channelData(IHaveConfig config, String key) { + return config.getReadOnlyDataPrimDef(key, 0L, id -> getMessageChannel(key, Snowflake.of((Long) id)), ch -> 0L); //We can afford to search for the channel in the cache once (instead of using mainServer) } public static ReadOnlyConfigData> roleData(IHaveConfig config, String key, String defName) { @@ -169,7 +175,15 @@ public final class DPUtils { return "<#" + channelId.asString() + ">"; } + /** + * Gets a message channel for a config. Returns empty for ID 0. + * + * @param key The config key + * @param id The channel ID + * @return A message channel + */ public static Mono getMessageChannel(String key, Snowflake id) { + if (id.asLong() == 0L) return Mono.empty(); return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> { getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage()); return Mono.empty(); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 3c4bc68..11d9f29 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -201,7 +201,7 @@ public class DiscordPlugin extends ButtonPlugin { "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.)" - + "\nYou can disable test mode in ThorpeCore config.")); + + "\nYou can disable test mode in ChromaCore config.")); Bukkit.getPluginManager().disablePlugin(this); } TBMCCoreAPI.SendUnsentExceptions(); diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index 11250a8..5a28ece 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -26,14 +26,14 @@ public class AnnouncerModule extends Component { * Channel to post new posts. */ public ReadOnlyConfigData> channel() { - return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); + return DPUtils.channelData(getConfig(), "channel"); } /** * Channel where distinguished (moderator) posts go. */ public ReadOnlyConfigData> modChannel() { - return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L); + return DPUtils.channelData(getConfig(), "modChannel"); } /** diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index 17d029a..bfb3048 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -85,7 +85,7 @@ public class ExceptionListenerModule extends Component implements } private ReadOnlyConfigData> channel() { - return DPUtils.channelData(getConfig(), "channel", 239519012529111040L); + return DPUtils.channelData(getConfig(), "channel"); } private ConfigData> pingRole(Mono guild) { diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index fa5e7d3..2ec9e2b 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -125,7 +125,7 @@ public class FunModule extends Component implements Listener { private ReadOnlyConfigData> fullHouseChannel() { - return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L); + return DPUtils.channelData(getConfig(), "fullHouseChannel"); } private static long lasttime = 0; diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 52cc604..2487f30 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -84,13 +84,14 @@ public class MCChatListener implements Listener { final Consumer embed = ecs -> { ecs.setDescription(e.getMessage()).setColor(new Color(color.getRed(), color.getGreen(), color.getBlue())); + String url = module.profileURL().get(); 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()); + url.length() > 0 ? url + "?type=minecraft&id=" + + ((Player) e.getSender()).getUniqueId() : null); 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(), + ecs.setAuthor(authorPlayer, url.length() > 0 ? url + "?type=discord&id=" + + ((DiscordSenderBase) e.getSender()).getUser().getId().asString() : null, ((DiscordSenderBase) e.getSender()).getUser().getAvatarUrl()); else DPUtils.embedWithHead(ecs, authorPlayer, e.getSender().getName(), null); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index 4862c6a..eacf823 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -58,7 +58,7 @@ public class MinecraftChatModule extends Component { * The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute */ public ReadOnlyConfigData> modlogChannel() { - return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L); + return DPUtils.channelData(getConfig(), "modlogChannel"); } /** @@ -104,6 +104,13 @@ public class MinecraftChatModule extends Component { return getConfig().getData("allowPrivateChat", true); } + /** + * If set, message authors appearing on Discord will link to this URL. A 'type' and 'id' parameter will be added with the user's platform (Discord, Minecraft, ...) and ID. + */ + public ConfigData profileURL() { + return getConfig().getData("profileURL", ""); + } + @Override protected void enable() { if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index babb47c..e4713b7 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -36,7 +36,7 @@ public class GameRoleModule extends Component { } private ReadOnlyConfigData> logChannel() { - return DPUtils.channelData(getConfig(), "logChannel", 239519012529111040L); + return DPUtils.channelData(getConfig(), "logChannel"); } public static void handleRoleEvent(RoleEvent roleEvent) { -- 2.30.2 From 3a94b6191b3c54aedaccd036b37d15923502df67 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 28 Nov 2019 00:16:58 +0100 Subject: [PATCH 104/108] Update D4J and some bugfixes The update fixes the numerous errors about a missing status constant Remove test check (#114) Improvements and checking for admin permission (#115) It also checks for channel perms now --- pom.xml | 2 +- .../buttondevteam/discordplugin/DPUtils.java | 15 ++++ .../discordplugin/DiscordPlugin.java | 9 --- .../discordplugin/fun/FunModule.java | 4 +- .../listeners/CommandListener.java | 2 +- .../mcchat/ChannelconCommand.java | 74 +++++++++++-------- .../discordplugin/mcchat/MCChatCommand.java | 4 +- 7 files changed, 65 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index 65d6d72..40f2734 100755 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,7 @@ com.discord4j discord4j-core - 3.0.10 + 3.0.11 diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index 6f3b82c..b0c0990 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -157,12 +157,27 @@ public final class DPUtils { return false; } + /** + * Send a response in the form of "@User, message". Use Mono.empty() if you don't have a channel object. + * + * @param original The original message to reply to + * @param channel The channel to send the message in, defaults to the original + * @param message The message to send + * @return A mono to send the message + */ 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 reply(original, ch, message); + } + + /** + * @see #reply(Message, MessageChannel, String) + */ + public static Mono reply(Message original, Mono ch, String message) { return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent() ? original.getAuthor().get().getMention() + ", " : "") + message)); } diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 11d9f29..08225ff 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -44,7 +44,6 @@ import java.awt.*; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -196,14 +195,6 @@ public class DiscordPlugin extends ButtonPlugin { 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 its name.)" - + "\nYou can disable test mode in ChromaCore config.")); - Bukkit.getPluginManager().disablePlugin(this); - } TBMCCoreAPI.SendUnsentExceptions(); TBMCCoreAPI.SendUnsentDebugMessages(); diff --git a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java index 2ec9e2b..46e98c5 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -96,7 +96,7 @@ public class FunModule extends Component implements Listener { } if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already { - DPUtils.reply(message, null, "Stop it. You know the answer.").subscribe(); + DPUtils.reply(message, Mono.empty(), "stop it. You know the answer.").subscribe(); lastlist = 0; lastlistp = (short) Bukkit.getOnlinePlayers().size(); return true; //Handled @@ -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, fm.serverReadyAnswers().get().get(next)).subscribe(); + DPUtils.reply(message, Mono.empty(), fm.serverReadyAnswers().get().get(next)).subscribe(); return false; //Still process it as a command/mcchat if needed } return false; diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 45aa261..1892e99 100644 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -62,7 +62,7 @@ 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); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java index 38a0229..e8307f3 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/ChannelconCommand.java @@ -9,12 +9,17 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.player.TBMCPlayer; +import discord4j.core.object.entity.GuildChannel; import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.MessageChannel; +import discord4j.core.object.entity.User; import discord4j.core.object.util.Permission; import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.Bukkit; +import reactor.core.publisher.Mono; +import javax.annotation.Nullable; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; @@ -22,6 +27,7 @@ import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Collectors; +@SuppressWarnings("SimplifyOptionalCallChains") //Java 11 @CommandClass(helpText = {"Channel connect", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "You need to have access to the MC channel and have manage permissions on the Discord channel.", // @@ -36,28 +42,29 @@ import java.util.stream.Collectors; @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 (checkPerms(message, null)) return true; if (MCChatCustom.removeCustomChat(message.getChannelId())) - DPUtils.reply(message, null, "channel connection removed.").subscribe(); + DPUtils.reply(message, Mono.empty(), "channel connection removed.").subscribe(); else - DPUtils.reply(message, null, "this channel isn't connected.").subscribe(); + DPUtils.reply(message, Mono.empty(), "this channel isn't connected.").subscribe(); return true; } @Command2.Subcommand public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) { val message = sender.getMessage(); - if (checkPerms(message)) return true; + if (checkPerms(message, null)) return true; 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) { - DPUtils.reply(message, null, "toggles:\n" + togglesString.get()).subscribe(); + DPUtils.reply(message, Mono.empty(), "toggles:\n" + togglesString.get()).subscribe(); return true; } String arg = toggle.toUpperCase(); @@ -65,7 +72,7 @@ public class ChannelconCommand extends ICommand2DC { if (!b.isPresent()) { val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg); if (bt == null) { - DPUtils.reply(message, null, "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe(); + DPUtils.reply(message, Mono.empty(), "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe(); return true; } final boolean add; @@ -83,7 +90,7 @@ public class ChannelconCommand extends ICommand2DC { //1 1 | 0 // XOR cc.toggles ^= b.get().flag; - DPUtils.reply(message, null, "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe(); + DPUtils.reply(message, Mono.empty(), "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe(); return true; } @@ -94,12 +101,13 @@ public class ChannelconCommand extends ICommand2DC { sender.sendMessage("channel connection is not allowed on this Minecraft server."); return true; } - if (checkPerms(message)) return true; + val channel = message.getChannel().block(); + if (checkPerms(message, channel)) return true; 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) - DPUtils.reply(message, null, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe(); + DPUtils.reply(message, channel, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe(); return true; } if (!message.getAuthor().isPresent()) return true; @@ -107,19 +115,18 @@ public class ChannelconCommand extends ICommand2DC { val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class); val chp = dp.getAs(TBMCPlayer.class); if (chp == null) { - DPUtils.reply(message, null, "you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect ").subscribe(); + DPUtils.reply(message, channel, "you need to connect your Minecraft account. On the main server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect ").subscribe(); return true; } - val channel = message.getChannel().block(); DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(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 - DPUtils.reply(message, null, "sorry, you cannot use that Minecraft channel.").subscribe(); + DPUtils.reply(message, channel, "sorry, you cannot use that Minecraft channel.").subscribe(); return true; } if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well - DPUtils.reply(message, null, "chat rooms are not supported yet.").subscribe(); + DPUtils.reply(message, channel, "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))) { @@ -128,16 +135,23 @@ public class ChannelconCommand extends ICommand2DC { }*/ //TODO: "Channel admins" that can connect channels? MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>()); if (chan.get() instanceof ChatRoom) - DPUtils.reply(message, null, "alright, connection made to the room!").subscribe(); + DPUtils.reply(message, channel, "alright, connection made to the room!").subscribe(); else - DPUtils.reply(message, null, "alright, connection made to group `" + groupid + "`!").subscribe(); + DPUtils.reply(message, channel, "alright, connection made to group `" + groupid + "`!").subscribe(); return true; } @SuppressWarnings("ConstantConditions") - private boolean checkPerms(Message message) { - if (!message.getAuthorAsMember().block().getBasePermissions().block().contains(Permission.MANAGE_CHANNELS)) { - DPUtils.reply(message, null, "you need to have manage permissions for this channel!").subscribe(); + private boolean checkPerms(Message message, @Nullable MessageChannel channel) { + if (channel == null) + channel = message.getChannel().block(); + if (!(channel instanceof GuildChannel)) { + DPUtils.reply(message, channel, "you can only use this command in a server!").subscribe(); + return true; + } + var perms = ((GuildChannel) channel).getEffectivePermissions(message.getAuthor().map(User::getId).get()).block(); + if (!perms.contains(Permission.ADMINISTRATOR) && !perms.contains(Permission.MANAGE_CHANNELS)) { + DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe(); return true; } return false; @@ -145,17 +159,17 @@ public class ChannelconCommand extends ICommand2DC { @Override public String[] getHelpText(Method method, Command2.Subcommand ann) { - return new String[]{ // - "Channel connect", // - "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // - "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.", // + return new String[]{ // + "Channel connect", // + "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // + "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: " + 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() + ".", // - "Invite link: " - }; - } + "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() + ".", // + "Invite link: " + }; + } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java index f068a12..4319cf9 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatCommand.java @@ -33,13 +33,13 @@ public class MCChatCommand extends ICommand2DC { 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(); + DPUtils.reply(message, channel, "this command can only be issued in a direct message with the bot.").subscribe(); return true; } try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); MCChatPrivate.privateMCChat(channel, mcchat, author, user); - DPUtils.reply(message, null, "Minecraft chat " + (mcchat // + DPUtils.reply(message, channel, "Minecraft chat " + (mcchat // ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // : "disabled.")).subscribe(); } catch (Exception e) { -- 2.30.2 From b481bb0aa998537adfc93a92149a5b73607af8af Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 27 Dec 2019 21:14:52 +0100 Subject: [PATCH 105/108] Fixed join msgs, vanished players in desc. and others Update D4J Fixed join messages appearing when they shouldn't (#119) Only showing players who can see the channel (#91) Fixed vanished players appearing in the channel descriptions (#120) --- pom.xml | 2 +- .../discordplugin/mcchat/MCChatUtils.java | 21 ++++++++++++++-- .../discordplugin/mcchat/MCListener.java | 24 ++++++++++--------- src/main/resources/plugin.yml | 4 +++- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/pom.xml b/pom.xml index 40f2734..299d605 100755 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,7 @@ com.discord4j discord4j-core - 3.0.11 + 3.0.12 diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index 6c085db..6b1c61d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -1,6 +1,7 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; +import buttondevteam.core.MainPlugin; import buttondevteam.discordplugin.*; import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule; import buttondevteam.lib.TBMCCoreAPI; @@ -13,6 +14,7 @@ import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.event.player.AsyncPlayerPreLoginEvent; @@ -30,6 +32,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Level; @@ -81,13 +84,27 @@ public class MCChatUtils { String[] s = topic.split("\\n----\\n"); if (s.length < 3) return; - s[0] = Bukkit.getOnlinePlayers().size() + " player" + (Bukkit.getOnlinePlayers().size() != 1 ? "s" : "") - + " online"; + String gid; + if (lmd instanceof MCChatCustom.CustomLMD) + gid = ((MCChatCustom.CustomLMD) lmd).groupID; + else //If we're not using a custom chat then it's either can ("everyone") or can't (null) see at most + gid = buttondevteam.core.component.channel.Channel.GROUP_EVERYONE; // (Though it's a public chat then rn) + AtomicInteger C = new AtomicInteger(); s[s.length - 1] = "Players: " + Bukkit.getOnlinePlayers().stream() + .filter(p -> gid.equals(lmd.mcchannel.getGroupID(p))) //If they can see it + .filter(MCChatUtils::checkEssentials) + .filter(p -> C.incrementAndGet() > 0) //Always true .map(p -> DPUtils.sanitizeString(p.getDisplayName())).collect(Collectors.joining(", ")); + s[0] = C + " player" + (C.get() != 1 ? "s" : "") + " online"; ((TextChannel) lmd.channel).edit(tce -> tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe(); //Don't wait } + private static boolean checkEssentials(Player p) { + var ess = MainPlugin.ess; + if (ess == null) return true; + return !ess.getUser(p).isHidden(); + } + public static T addSender(HashMap> senders, User user, T sender) { return addSender(senders, user.getId().asString(), sender); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index c3ad14a..144304d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -3,7 +3,9 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.discordplugin.*; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.player.*; +import buttondevteam.lib.player.TBMCPlayer; +import buttondevteam.lib.player.TBMCPlayerBase; +import buttondevteam.lib.player.TBMCYEEHAWEvent; import com.earth2me.essentials.CommandSource; import discord4j.core.object.entity.Role; import discord4j.core.object.util.Snowflake; @@ -18,9 +20,7 @@ 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.PlayerCommandSendEvent; -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.server.BroadcastMessageEvent; import org.bukkit.event.server.TabCompleteEvent; @@ -45,12 +45,12 @@ class MCListener implements Listener { } @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerJoin(TBMCPlayerJoinEvent e) { + public void onPlayerJoin(PlayerJoinEvent e) { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Don't show the joined message for the fake player Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { final Player p = e.getPlayer(); - DiscordPlayer dp = e.GetPlayer().getAs(DiscordPlayer.class); + DiscordPlayer dp = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class).getAs(DiscordPlayer.class); if (dp != null) { DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID())).flatMap(user -> user.getPrivateChannel().flatMap(chan -> module.chatChannelMono().flatMap(cc -> { MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID(), @@ -60,14 +60,15 @@ class MCListener implements Listener { return Mono.empty(); }))).subscribe(); } - final String message = e.GetPlayer().PlayerName().get() + " joined the game"; - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); + final String message = e.getJoinMessage(); + if (message != null && message.trim().length() > 0) + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); ChromaBot.getInstance().updatePlayerList(); }); } @EventHandler(priority = EventPriority.HIGHEST) - public void onPlayerLeave(TBMCPlayerQuitEvent e) { + public void onPlayerLeave(PlayerQuitEvent e) { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Only care about real users MCChatUtils.OnlineSenders.entrySet() @@ -78,8 +79,9 @@ class MCListener implements Listener { .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); + final String message = e.getQuitMessage(); + if (message != null && message.trim().length() > 0) + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); } @EventHandler(priority = EventPriority.HIGHEST) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e045c2b..f7ffcf1 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,10 @@ name: Chroma-Discord main: buttondevteam.discordplugin.DiscordPlugin -version: 1.0 +version: '1.0' author: NorbiPeti depend: [ChromaCore] +softdepend: + - Essentials commands: discord: website: 'https://github.com/TBMCPlugins/DiscordPlugin' -- 2.30.2 From 703f1f8cd5110850b2974be45d9570faf7a63c57 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 27 Dec 2019 23:45:49 +0100 Subject: [PATCH 106/108] Finished some of the half-completed issues and others Processing custom emotes (#48) Made role listing fancier (#80) Trying to reload config before reset (#113) Allowing /discord reset if the login fails, clarified how to get a token (#111) --- .../buttondevteam/discordplugin/DiscordPlugin.java | 12 +++++++----- .../discordplugin/mcchat/MCChatListener.java | 2 ++ .../discordplugin/mccommands/DiscordMCCommand.java | 4 ++++ .../discordplugin/role/RoleCommand.java | 14 ++++++++++++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 08225ff..81bb8bd 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -100,6 +100,7 @@ public class DiscordPlugin extends ButtonPlugin { getLogger().info("Initializing..."); plugin = this; manager = new Command2DC(); + getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works String token; File tokenFile = new File("TBMC", "Token.txt"); if (tokenFile.exists()) //Legacy support @@ -113,8 +114,9 @@ public class DiscordPlugin extends ButtonPlugin { conf.set("token", "Token goes here"); conf.save(privateFile); - getLogger().severe("Token not found! Set it in private.yml"); - Bukkit.getPluginManager().disablePlugin(this); + getLogger().severe("Token not found! Please set it in private.yml then do /discord reset"); + getLogger().severe("You need to have a bot account to use with your server."); + getLogger().severe("If you don't have one, go to https://discordapp.com/developers/applications/ and create an application, then create a bot for it and copy the bot token."); return; } } @@ -132,8 +134,8 @@ public class DiscordPlugin extends ButtonPlugin { //dc.getEventDispatcher().on(DisconnectEvent.class); dc.login().subscribe(); } catch (Exception e) { - e.printStackTrace(); - Bukkit.getPluginManager().disablePlugin(this); + TBMCCoreAPI.SendException("Failed to enable the Discord plugin!", e); + getLogger().severe("You may be able to reset the plugin using /discord reset"); } } @@ -143,10 +145,10 @@ public class DiscordPlugin extends ButtonPlugin { try { if (mainServer != null) { //This is not the first ready event getLogger().info("Ready event already handled"); //TODO: It should probably handle disconnections + dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); //Update from the initial presence return; } mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards - getCommand2MC().registerCommand(new DiscordMCCommand()); //Register so that the reset command works if (mainServer == null) { if (event.size() == 0) { getLogger().severe("Main server not found! Invite the bot and do /discord reset"); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 2487f30..401d6e3 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -293,6 +293,8 @@ public class MCChatListener implements Listener { 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 = dmessage.replaceAll("", ":$1:"); //We don't need info about the custom emojis, just display their text + Function getChatMessage = msg -> // msg + (event.getMessage().getAttachments().size() > 0 ? "\n" + event.getMessage() .getAttachments().stream().map(Attachment::getUrl).collect(Collectors.joining("\n")) diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 29eb5ce..1f2d7a7 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -73,6 +73,10 @@ public class DiscordMCCommand extends ICommand2MC { }) public void reset(CommandSender sender) { Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, () -> { + if (!DiscordPlugin.plugin.tryReloadConfig()) { + sender.sendMessage("§cFailed to reload config so not resetting. Check the console."); + return; + } resetting = true; //Turned off after sending enable message (ReadyEvent) sender.sendMessage("§bDisabling DiscordPlugin..."); Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index d47007b..2dab969 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -11,7 +11,6 @@ import lombok.val; import reactor.core.publisher.Mono; import java.util.List; -import java.util.stream.Collectors; @CommandClass public class RoleCommand extends ICommand2DC { @@ -62,7 +61,18 @@ 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"))); + var sb = new StringBuilder(); + boolean b = false; + for (String role : (Iterable) grm.GameRoles.stream().sorted()::iterator) { + sb.append(role); + if (!b) + for (int j = 0; j < Math.min(0, 20 - role.length()); j++) + sb.append(" "); + else + sb.append("\n"); + b = !b; + } + sender.sendMessage("list of roles:\n```\n" + sb + "```"); } private Role checkAndGetRole(Command2DCSender sender, String rolename) { -- 2.30.2 From bdb7381ab4de5d1401e0a0dbd956fbbf44cb8272 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 18 Jan 2020 03:54:17 +0100 Subject: [PATCH 107/108] Finished some issues Fixed join messages appearing in addition to custom ones (#119) For real this time Not saying the game role color is the default one (#118) Fixed role listing (#80) --- .../discordplugin/mcchat/MCListener.java | 4 ++-- .../discordplugin/role/GameRoleModule.java | 11 +++++++++-- .../buttondevteam/discordplugin/role/RoleCommand.java | 4 +++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 144304d..50843e6 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -44,7 +44,7 @@ class MCListener implements Listener { .ifPresent(dcp -> MCChatUtils.callLogoutEvent(dcp, false)); } - @EventHandler(priority = EventPriority.LOWEST) + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent e) { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Don't show the joined message for the fake player @@ -67,7 +67,7 @@ class MCListener implements Listener { }); } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerLeave(PlayerQuitEvent e) { if (e.getPlayer() instanceof DiscordConnectedPlayer) return; // Only care about real users diff --git a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java index e4713b7..d666a13 100644 --- a/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java +++ b/src/main/java/buttondevteam/discordplugin/role/GameRoleModule.java @@ -21,6 +21,10 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +/** + * Automatically collects roles with a certain color (the second to last in the upper row - #95a5a6). + * Users can add these roles to themselves using the /role Discord command. + */ public class GameRoleModule extends Component { public List GameRoles; @@ -35,6 +39,9 @@ public class GameRoleModule extends Component { } + /** + * The channel where the bot logs when it detects a role change that results in a new game role or one being removed. + */ private ReadOnlyConfigData> logChannel() { return DPUtils.channelData(getConfig(), "logChannel"); } @@ -52,7 +59,7 @@ public class GameRoleModule extends Component { 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 logChannel.flatMap(ch -> ch.createMessage("Added " + role.getName() + " as game role. If you don't want this, change the role's color from the game role color.")); return Mono.empty(); }).subscribe(); }, 100); @@ -81,7 +88,7 @@ public class GameRoleModule extends Component { 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 logChannel.flatMap(ch -> ch.createMessage("Added " + event.getCurrent().getName() + " as game role because it has the color of one.")); } } return Mono.empty(); diff --git a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java index 2dab969..d484ef2 100755 --- a/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/role/RoleCommand.java @@ -66,12 +66,14 @@ public class RoleCommand extends ICommand2DC { for (String role : (Iterable) grm.GameRoles.stream().sorted()::iterator) { sb.append(role); if (!b) - for (int j = 0; j < Math.min(0, 20 - role.length()); j++) + for (int j = 0; j < Math.max(1, 20 - role.length()); j++) sb.append(" "); else sb.append("\n"); b = !b; } + if (sb.charAt(sb.length() - 1) != '\n') + sb.append('\n'); sender.sendMessage("list of roles:\n```\n" + sb + "```"); } -- 2.30.2 From de07503bc3c7ff313a8ec00a32de93361c794529 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 1 Feb 2020 19:10:13 +0100 Subject: [PATCH 108/108] Documentation, split messages that are too big #122 Removed some default values Disallowing MC commands that could error when not loaded (#121) Other fixes --- .../buttondevteam/discordplugin/DPUtils.java | 11 ++++-- .../discordplugin/DiscordPlugin.java | 16 ++++++-- .../announcer/AnnouncerModule.java | 23 ++++++----- .../GeneralEventBroadcasterModule.java | 4 ++ .../commands/Command2DCSender.java | 6 +++ .../exceptions/ExceptionListenerModule.java | 9 +++++ .../discordplugin/fun/FunModule.java | 39 +++++++++++-------- .../discordplugin/mcchat/MCChatListener.java | 3 +- .../mcchat/MinecraftChatModule.java | 11 ++---- .../mccommands/DiscordMCCommand.java | 11 ++++++ 10 files changed, 91 insertions(+), 42 deletions(-) diff --git a/src/main/java/buttondevteam/discordplugin/DPUtils.java b/src/main/java/buttondevteam/discordplugin/DPUtils.java index b0c0990..d118672 100755 --- a/src/main/java/buttondevteam/discordplugin/DPUtils.java +++ b/src/main/java/buttondevteam/discordplugin/DPUtils.java @@ -96,13 +96,16 @@ 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)).next(); + if (!(name instanceof String) || ((String) name).length() == 0) return Mono.empty(); + return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).onErrorResume(e -> { + getLogger().warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage()); + return Mono.empty(); + }).next(); }, r -> defName); } - public static ConfigData snowflakeData(IHaveConfig config, String key, long defID) { - return config.getDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong); + public static ReadOnlyConfigData snowflakeData(IHaveConfig config, String key, long defID) { + return config.getReadOnlyDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong); } /** diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 81bb8bd..a38389a 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -55,6 +55,9 @@ public class DiscordPlugin extends ButtonPlugin { @Getter private Command2DC manager; + /** + * The prefix to use with Discord commands like /role. It only works in the bot channel. + */ private ConfigData prefix() { return getIConfig().getData("prefix", '/', str -> ((String) str).charAt(0), Object::toString); } @@ -64,6 +67,9 @@ public class DiscordPlugin extends ButtonPlugin { return plugin.prefix().get(); } + /** + * The main server where the roles and other information is pulled from. It's automatically set to the first server the bot's invited to. + */ private ConfigData> mainServer() { return getIConfig().getDataPrimDef("mainServer", 0L, id -> { @@ -76,12 +82,16 @@ public class DiscordPlugin extends ButtonPlugin { g -> g.map(gg -> gg.getId().asLong()).orElse(0L)); } + /** + * The (bot) channel to use for Discord commands like /role. + */ public ConfigData commandChannel() { - return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L); + return DPUtils.snowflakeData(getIConfig(), "commandChannel", 0L); } /** - * If the role doesn't exist, then it will only allow for the owner. + * The role that allows using mod-only Discord commands. + * If empty (''), then it will only allow for the owner. */ public ConfigData> modRole() { return DPUtils.roleData(getIConfig(), "modRole", "Moderator"); @@ -164,7 +174,7 @@ public class DiscordPlugin extends ButtonPlugin { } SafeMode = false; DPUtils.disableIfConfigErrorRes(null, commandChannel(), DPUtils.getMessageChannel(commandChannel())); - DPUtils.disableIfConfigError(null, modRole()); //Won't disable, just prints the warning here + //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 5a28ece..2b68de0 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ReadOnlyConfigData; import buttondevteam.lib.player.ChromaGamerBase; @@ -15,12 +16,13 @@ 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 reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.io.File; - +/** + * Posts new posts from Reddit to the specified channel(s). It will pin the regular posts (not the mod posts). + */ +@ComponentMetadata(enabledByDefault = false) public class AnnouncerModule extends Component { /** * Channel to post new posts. @@ -51,7 +53,13 @@ public class AnnouncerModule extends Component { return getConfig().getData("lastSeenTime", 0L); } - private static final String SubredditURL = "https://www.reddit.com/r/ChromaGamers"; + /** + * The subreddit to pull the posts from + */ + private ConfigData subredditURL() { + return getConfig().getData("subredditURL", "https://www.reddit.com/r/ChromaGamers"); + } + private static boolean stop = false; @Override @@ -62,11 +70,6 @@ public class AnnouncerModule extends Component { if (keepPinned == 0) return; 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")); new Thread(this::AnnouncementGetterThreadMethod).start(); } @@ -82,7 +85,7 @@ public class AnnouncerModule extends Component { Thread.sleep(10000); continue; } - String body = TBMCCoreAPI.DownloadString(SubredditURL + "/new/.json?limit=10"); + String body = TBMCCoreAPI.DownloadString(subredditURL().get() + "/new/.json?limit=10"); JsonArray json = new JsonParser().parse(body).getAsJsonObject().get("data").getAsJsonObject() .get("children").getAsJsonArray(); StringBuilder msgsb = new StringBuilder(); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java index 44c2d79..5a0317e 100644 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/GeneralEventBroadcasterModule.java @@ -6,6 +6,10 @@ import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import lombok.Getter; +/** + * Uses a bit of a hacky method of getting all broadcasted messages, including advancements and any other message that's for everyone. + * If this component is enabled then these messages will show up on Discord. + */ public class GeneralEventBroadcasterModule extends Component { private static @Getter boolean hooked = false; diff --git a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java index 8b705fd..ab22e37 100644 --- a/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java +++ b/src/main/java/buttondevteam/discordplugin/commands/Command2DCSender.java @@ -3,6 +3,7 @@ package buttondevteam.discordplugin.commands; import buttondevteam.discordplugin.DPUtils; import buttondevteam.lib.chat.Command2Sender; import discord4j.core.object.entity.Message; +import discord4j.core.object.entity.User; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.val; @@ -30,4 +31,9 @@ public class Command2DCSender implements Command2Sender { public void sendMessage(String[] message) { sendMessage(String.join("\n", message)); } + + @Override + public String getName() { + return message.getAuthor().map(User::getUsername).orElse("Discord"); + } } diff --git a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java index bfb3048..6263e85 100755 --- a/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java +++ b/src/main/java/buttondevteam/discordplugin/exceptions/ExceptionListenerModule.java @@ -23,6 +23,9 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +/** + * Listens for errors from the Chroma plugins and posts them to Discord, ignoring repeating errors so it's not that spammy. + */ public class ExceptionListenerModule extends Component implements Listener { private List lastthrown = new ArrayList<>(); private List lastsourcemsg = new ArrayList<>(); @@ -84,10 +87,16 @@ public class ExceptionListenerModule extends Component implements return Mono.empty(); } + /** + * The channel to post the errors to. + */ private ReadOnlyConfigData> channel() { return DPUtils.channelData(getConfig(), "channel"); } + /** + * The role to ping if an error occurs. Set to empty ('') to disable. + */ 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 46e98c5..189a026 100644 --- a/src/main/java/buttondevteam/discordplugin/fun/FunModule.java +++ b/src/main/java/buttondevteam/discordplugin/fun/FunModule.java @@ -26,23 +26,24 @@ import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; /** + * All kinds of random things. * 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 - "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 + 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 }; /** @@ -52,14 +53,14 @@ public class FunModule extends Component implements Listener { 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?"}); + "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 + return getConfig().getData("serverReadyAnswers", () -> Lists.newArrayList(serverReadyStrings)); } private static final Random serverReadyRandom = new Random(); @@ -119,11 +120,17 @@ public class FunModule extends Component implements Listener { ListC = 0; } + /** + * If all of the people who have this role are online, the bot will post a full house. + */ private ConfigData> fullHouseDevRole(Mono guild) { return DPUtils.roleData(getConfig(), "fullHouseDevRole", "Developer", guild); } + /** + * The channel to post the full house to. + */ private ReadOnlyConfigData> fullHouseChannel() { return DPUtils.channelData(getConfig(), "fullHouseChannel"); } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index 401d6e3..202fd93 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -102,7 +102,8 @@ public class MCChatListener implements Listener { 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.mcchannel.ID.equals(e.getChannel().ID) + || lastmsgdata.content.length() + e.getMessage().length() + 1 > 2048) { lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block(); lastmsgdata.time = nanoTime; lastmsgdata.mcchannel = e.getChannel(); diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index eacf823..1018ba8 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -28,12 +28,7 @@ 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; - - /*public MCChatListener getListener() { //It doesn't want to generate - return listener; - And now ButtonProcessor didn't look beyond this - return instead of continue... - }*/ + private @Getter MCChatListener listener; /** * 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! @@ -46,8 +41,8 @@ public class MinecraftChatModule extends Component { /** * The channel to use as the public Minecraft chat - everything public gets broadcasted here */ - public ConfigData chatChannel() { - return DPUtils.snowflakeData(getConfig(), "chatChannel", 239519012529111040L); + public ReadOnlyConfigData chatChannel() { + return DPUtils.snowflakeData(getConfig(), "chatChannel", 0L); } public Mono chatChannelMono() { diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 1f2d7a7..61d9d6b 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -27,6 +27,7 @@ import java.lang.reflect.Method; public class DiscordMCCommand extends ICommand2MC { @Command2.Subcommand public boolean accept(Player player) { + if (checkSafeMode(player)) return true; String did = ConnectCommand.WaitingToConnect.get(player.getName()); if (did == null) { player.sendMessage("§cYou don't have a pending connection to Discord."); @@ -45,6 +46,7 @@ public class DiscordMCCommand extends ICommand2MC { @Command2.Subcommand public boolean decline(Player player) { + if (checkSafeMode(player)) return true; String did = ConnectCommand.WaitingToConnect.remove(player.getName()); if (did == null) { player.sendMessage("§cYou don't have a pending connection to Discord."); @@ -101,6 +103,7 @@ public class DiscordMCCommand extends ICommand2MC { "Shows an invite link to the server" }) public void invite(CommandSender sender) { + if (checkSafeMode(sender)) return; String invi = DiscordPlugin.plugin.inviteLink().get(); if (invi.length() > 0) { sender.sendMessage("§bInvite link: " + invi); @@ -132,4 +135,12 @@ public class DiscordMCCommand extends ICommand2MC { return super.getHelpText(method, ann); } } + + private boolean checkSafeMode(CommandSender sender) { + if (DiscordPlugin.SafeMode) { + sender.sendMessage("§cThe plugin isn't initialized. Check console for details."); + return true; + } + return false; + } } -- 2.30.2