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'