From 7c15495fab18f81b66129c593a2dd78878075c7d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 28 Jan 2019 23:21:17 +0100 Subject: [PATCH 1/3] 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' From 2659170c4dd7757765e9ca38eb0f841c2e4adc82 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 01:09:18 +0100 Subject: [PATCH 2/3] 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) { From abd4050786745a0994252e3ce8d34ff943826dff Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 23:41:52 +0100 Subject: [PATCH 3/3] 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();