diff --git a/.gitignore b/.gitignore index 9ec5deb..1d227f7 100755 --- a/.gitignore +++ b/.gitignore @@ -131,7 +131,7 @@ publish/ *.publishproj # NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line +## TO!DO: If you have NuGet Package Restore enabled, uncomment the next line #packages/ # Windows Azure Build Output diff --git a/pom.xml b/pom.xml index 43ce4d1..8a8fac4 100755 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ org.spigotmc:spigot-api com.github.TBMCPlugins.ButtonCore:ButtonCore net.ess3:Essentials - + @@ -180,6 +180,7 @@ net.ess3 Essentials 2.13.1 + provided com.github.xaanit diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index c2972fa..cca07b1 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -1,5 +1,6 @@ package buttondevteam.discordplugin; +import buttondevteam.discordplugin.commands.DiscordCommandBase; import buttondevteam.discordplugin.listeners.*; import buttondevteam.discordplugin.mccommands.DiscordMCCommandBase; import buttondevteam.lib.TBMCCoreAPI; @@ -132,6 +133,7 @@ public class DiscordPlugin extends JavaPlugin implements IListener { new ChromaBot(this).updatePlayerList(); //Get all roles with the default color GameRoles = mainServer.getRoles().stream().filter(r -> r.getColor().getAlpha() == 0).map(IRole::getName).collect(Collectors.toList()); + DiscordCommandBase.registerCommands(); if (getConfig().getBoolean("serverup", false)) { ChromaBot.getInstance().sendMessage("", new EmbedBuilder().withColor(Color.YELLOW) .withTitle("Server recovered from a crash - chat connected.").build()); diff --git a/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java new file mode 100644 index 0000000..51b1846 --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/commands/ChannelconCommand.java @@ -0,0 +1,68 @@ +package buttondevteam.discordplugin.commands; + +import buttondevteam.discordplugin.DiscordConnectedPlayer; +import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.listeners.MCChatListener; +import buttondevteam.lib.TBMCChannelConnectEvent; +import buttondevteam.lib.chat.Channel; +import buttondevteam.lib.player.TBMCPlayer; +import lombok.val; +import org.bukkit.Bukkit; +import sx.blah.discord.handle.obj.IMessage; +import sx.blah.discord.handle.obj.Permissions; +import sx.blah.discord.util.PermissionUtils; + +import java.util.Arrays; + +public class ChannelconCommand extends DiscordCommandBase { + @Override + public String getCommandName() { + return "here"; + } + + @Override + public boolean run(IMessage message, String args) { + if (args.length() == 0) + return false; + if (!PermissionUtils.hasPermissions(message.getChannel(), message.getAuthor(), Permissions.MANAGE_CHANNEL)) { + message.reply("you need to have manage permissions for this channel!"); + return true; + } + //TODO: What if they no longer have permission to view the channel + if (MCChatListener.hasCustomChat(message.getChannel())) { //TODO: Remove command + message.reply("this channel is already connected to a Minecraft channel."); + return true; + } + val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args) || (ch.IDs != null && Arrays.stream(ch.IDs).anyMatch(cid -> cid.equalsIgnoreCase(args)))).findAny(); + if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) + message.reply("MC channel with ID '" + args + "' not found! The ID is the command for it without the /."); + return true; + } + val chp = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class).getAs(TBMCPlayer.class); + if (chp == null) { + message.reply("you need to connect your Minecraft account. In #bot do @ChromaBot connect "); + return true; + } + val ev = new TBMCChannelConnectEvent(new DiscordConnectedPlayer(message.getAuthor(), message.getChannel(), chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName()), chan.get()); + Bukkit.getPluginManager().callEvent(ev); //Using a fake player with no login/logout, should be fine for this event + if (ev.isCancelled() || ev.getGroupid() == null) { + message.reply("sorry, that didn't work. You cannot use that Minecraft channel."); + return true; + } + MCChatListener.addCustomChat(message.getChannel(), args, ev.getChannel()); + message.reply("alright, connection made!"); + return true; + } + + @Override + public String[] getHelpText() { + return new String[]{ // + "§6---- Channel connect ---", // + "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // + "You need to have access to the MC channel and have manage permissions on the Discord channel.", // + "You also need to have your Minecraft account connected. In #bot use @ChromaBot connect .", // + "Call this command from the channel you want to use. Usage: @ChromaBot channelcon ", // + "Invite link: https://discordapp.com/oauth2/authorize?client_id=226443037893591041&scope=bot" // + }; + } +} diff --git a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java index 65ebda2..670b522 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/ConnectCommand.java @@ -25,15 +25,13 @@ public class ConnectCommand extends DiscordCommandBase { public static HashBiMap WaitingToConnect = HashBiMap.create(); @Override - public void run(IMessage message, String args) { - if (args.length() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), "Usage: connect "); - return; - } + public boolean run(IMessage message, String args) { + if (args.length() == 0) + return true; if (args.contains(" ")) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "Too many arguments.\nUsage: connect "); - return; + return true; } if (WaitingToConnect.inverse().containsKey(message.getAuthor().getStringID())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), @@ -44,13 +42,13 @@ public class ConnectCommand extends DiscordCommandBase { OfflinePlayer p = Bukkit.getOfflinePlayer(args); if (p == null) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The specified Minecraft player cannot be found"); - return; + return true; } try (TBMCPlayer pl = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class)) { DiscordPlayer dp = pl.getAs(DiscordPlayer.class); if (dp != null && message.getAuthor().getStringID().equals(dp.getDiscordID())) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "You already have this account connected."); - return; + return true; } } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while connecting a Discord account!", e); @@ -63,6 +61,7 @@ public class ConnectCommand extends DiscordCommandBase { if (p.isOnline()) ((Player) p).sendMessage("§bTo connect with the Discord account " + message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator() + " do /discord accept"); + return true; } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java index f403b49..8791c8f 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java +++ b/src/main/java/buttondevteam/discordplugin/commands/DiscordCommandBase.java @@ -4,23 +4,26 @@ import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.lib.TBMCCoreAPI; import sx.blah.discord.handle.obj.IMessage; +import java.util.Arrays; import java.util.HashMap; +import java.util.stream.Collectors; public abstract class DiscordCommandBase { public abstract String getCommandName(); - public abstract void run(IMessage message, String args); + public abstract boolean run(IMessage message, String args); public abstract String[] getHelpText(); static final HashMap commands = new HashMap(); - static { + 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()); } public static void runCommand(String cmd, String args, IMessage message) { @@ -33,11 +36,16 @@ public abstract class DiscordCommandBase { return; } try { - command.run(message, args); + 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."); } } + + protected String[] splitargs(String args) { + return args.split("\\s+"); + } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java index c7f468e..29aff28 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/HelpCommand.java @@ -14,7 +14,7 @@ public class HelpCommand extends DiscordCommandBase { } @Override - public void run(IMessage message, String args) { + public boolean run(IMessage message, String args) { DiscordCommandBase argdc; if (args.length() == 0) DiscordPlugin.sendMessageToChannel(message.getChannel(), @@ -24,6 +24,7 @@ public class HelpCommand extends DiscordCommandBase { DiscordPlugin.sendMessageToChannel(message.getChannel(), (argdc = DiscordCommandBase.commands.get(args)) == null ? "Command not found: " + args : Arrays.stream(argdc.getHelpText()).collect(Collectors.joining("\n"))); + return true; } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/HereCommand.java b/src/main/java/buttondevteam/discordplugin/commands/HereCommand.java deleted file mode 100644 index f2717d7..0000000 --- a/src/main/java/buttondevteam/discordplugin/commands/HereCommand.java +++ /dev/null @@ -1,25 +0,0 @@ -package buttondevteam.discordplugin.commands; - -import buttondevteam.discordplugin.mccommands.ChannelconMCCommand; -import lombok.val; -import sx.blah.discord.handle.obj.IMessage; - -public class HereCommand extends DiscordCommandBase { - @Override - public String getCommandName() { - return "here"; - } - - @Override - public void run(IMessage message, String args) { - val chgroup = ChannelconMCCommand.PendingConnections.get(message.getAuthor().getStringID()); - if (chgroup == null) { - message.reply("no pending connection found! "); //TODO - } - } - - @Override - public String[] getHelpText() { - return new String[0]; - } -} diff --git a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java index a629eda..05c66c0 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/MCChatCommand.java @@ -14,11 +14,11 @@ public class MCChatCommand extends DiscordCommandBase { } @Override - public void run(IMessage message, String args) { + public boolean run(IMessage message, String args) { if (!message.getChannel().isPrivate()) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "This command can only be issued in a direct message with the bot."); - return; + return true; } try (final DiscordPlayer user = DiscordPlayer.getUser(message.getAuthor().getStringID(), DiscordPlayer.class)) { boolean mcchat = !user.isMinecraftChatEnabled(); @@ -31,6 +31,7 @@ public class MCChatCommand extends DiscordCommandBase { } catch (Exception e) { TBMCCoreAPI.SendException("Error while setting mcchat for user" + message.getAuthor().getName(), e); } + return true; } @Override diff --git a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java index cf3d0c6..ed1ddaf 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/RoleCommand.java @@ -17,17 +17,14 @@ public class RoleCommand extends DiscordCommandBase { } @Override - public void run(IMessage message, String args) { - final String usagemsg = "Subcommands: add, remove, list"; - if (args.length() == 0) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), usagemsg); - return; - } - String[] argsa = args.split(" "); + public boolean run(IMessage message, String args) { + if (args.length() == 0) + return false; + String[] argsa = splitargs(args); if (argsa[0].equalsIgnoreCase("add")) { final IRole role = checkAndGetRole(message, argsa, "This command adds a game role to your account."); if (role == null) - return; + return true; try { DPUtils.perform(() -> message.getAuthor().addRole(role)); DiscordPlugin.sendMessageToChannel(message.getChannel(), "Added game role."); @@ -38,7 +35,7 @@ public class RoleCommand extends DiscordCommandBase { } else if (argsa[0].equalsIgnoreCase("remove")) { final IRole role = checkAndGetRole(message, argsa, "This command removes a game role from your account."); if (role == null) - return; + return true; try { DPUtils.perform(() -> message.getAuthor().removeRole(role)); DiscordPlugin.sendMessageToChannel(message.getChannel(), "Removed game role."); @@ -49,7 +46,8 @@ public class RoleCommand extends DiscordCommandBase { } else if (argsa[0].equalsIgnoreCase("list")) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "List of game roles:\n" + DiscordPlugin.GameRoles.stream().sorted().collect(Collectors.joining("\n"))); - } else DiscordPlugin.sendMessageToChannel(message.getChannel(), usagemsg); + } else return false; + return true; } private IRole checkAndGetRole(IMessage message, String[] argsa, String usage) { @@ -87,7 +85,7 @@ public class RoleCommand extends DiscordCommandBase { return new String[] { // "Add or remove game roles from yourself.", // "Usage: role add|remove or role list", // - "Mods can use role addrole to add a role as a game role" }; + }; } } diff --git a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java index ee613e7..b0608ed 100755 --- a/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java +++ b/src/main/java/buttondevteam/discordplugin/commands/UserinfoCommand.java @@ -20,12 +20,7 @@ public class UserinfoCommand extends DiscordCommandBase { } @Override - public void run(IMessage message, String args) { - if (args.contains(" ")) { - DiscordPlugin.sendMessageToChannel(message.getChannel(), - "Too many arguments.\nUsage: userinfo [username/nickname[#tag]/ping]\nExamples:\nuserinfo ChromaBot\nuserinfo ChromaBot#6338\nuserinfo @ChromaBot#6338"); - return; - } + public boolean run(IMessage message, String args) { IUser target = null; if (args.length() == 0) target = message.getAuthor(); @@ -40,7 +35,7 @@ public class UserinfoCommand extends DiscordCommandBase { if (targets.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The user cannot be found (by name): " + args); - return; + return true; } for (IUser ptarget : targets) { if (ptarget.getDiscriminator().equalsIgnoreCase(targettag[1])) { @@ -52,19 +47,19 @@ public class UserinfoCommand extends DiscordCommandBase { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The user cannot be found (by discriminator): " + args + "(Found " + targets.size() + " users with the name.)"); - return; + return true; } } else { final List targets = getUsers(message, args); if (targets.size() == 0) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "The user cannot be found on Discord: " + args); - return; + return true; } if (targets.size() > 1) { DiscordPlugin.sendMessageToChannel(message.getChannel(), "Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping."); - return; + return true; } target = targets.get(0); } @@ -77,6 +72,7 @@ public class UserinfoCommand extends DiscordCommandBase { DiscordPlugin.sendMessageToChannel(message.getChannel(), "An error occured while getting the user!"); TBMCCoreAPI.SendException("Error while getting info about " + target.getName() + "!", e); } + return true; } private List getUsers(IMessage message, String args) { @@ -94,7 +90,8 @@ public class UserinfoCommand extends DiscordCommandBase { return new String[] { // "---- User information ----", // "Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.", // - "Usage: userinfo " // + "If used without args, shows your info.", // + "Usage: userinfo [username/nickname[#tag]/ping]\nExamples:\nuserinfo ChromaBot\nuserinfo ChromaBot#6338\nuserinfo @ChromaBot#6338" // }; } diff --git a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java index 6fdd9b1..0103ebd 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/CommandListener.java @@ -182,7 +182,7 @@ public class CommandListener { args = ""; } else { cmd = cmdwithargs.substring(0, index); - args = cmdwithargs.substring(index + 1); + args = cmdwithargs.substring(index + 1).trim(); //In case there are multiple spaces } DiscordCommandBase.runCommand(cmd.toLowerCase(), args, message); message.getChannel().setTypingStatus(false); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java index 7aa12ff..6384b12 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCChatListener.java @@ -46,12 +46,6 @@ public class MCChatListener implements Listener, IListener private LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); private Runnable sendrunnable; - public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel) { - val lmd = new LastMsgData(channel, null, null); - lmd.mcchannel = mcchannel; - lastmsgCustom.put(groupid, lmd); - } - @EventHandler // Minecraft public void onMCChat(TBMCChatEvent ev) { if (ev.isCancelled()) @@ -186,7 +180,7 @@ public class MCChatListener implements Listener, IListener /** * Used for town or nation chats or anything else */ - private static HashMap lastmsgCustom = new HashMap<>(); + private static HashMap lastmsgCustom = new HashMap<>(); public static boolean privateMCChat(IChannel channel, boolean start, IUser user, DiscordPlayer dp) { TBMCPlayer mcp = dp.getAs(TBMCPlayer.class); @@ -230,6 +224,20 @@ public class MCChatListener implements Listener, IListener .anyMatch(lmd -> ((IPrivateChannel) lmd.channel).getRecipient().getStringID().equals(did)); } + public static void addCustomChat(IChannel channel, String groupid, Channel mcchannel) { + val lmd = new LastMsgData(channel, null, null); + lmd.mcchannel = mcchannel; + lastmsgCustom.put(lmd, groupid); + } + + public static boolean hasCustomChat(IChannel channel) { + return lastmsgCustom.entrySet().stream().anyMatch(lmd -> lmd.getKey().channel.getLongID() == channel.getLongID()); + } + + public static boolean removeCustomChat(IChannel channel) { + return lastmsgCustom.entrySet().removeIf(lmd -> lmd.getKey().channel.getLongID() == channel.getLongID()); + } + /** * May contain P<DiscordID> as key for public chat */ diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/ChannelconMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/ChannelconMCCommand.java deleted file mode 100644 index 10f871d..0000000 --- a/src/main/java/buttondevteam/discordplugin/mccommands/ChannelconMCCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -package buttondevteam.discordplugin.mccommands; - -import buttondevteam.discordplugin.DiscordPlayer; -import buttondevteam.lib.TBMCChannelConnectEvent; -import buttondevteam.lib.chat.Channel; -import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.player.TBMCPlayer; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.HashMap; - -@CommandClass(modOnly = false, path = "channelcon") -public class ChannelconMCCommand extends DiscordMCCommandBase { - @Override //TODO: Since we require connecting the accounts, it can be done entirely on Discord. - public boolean OnCommand(Player player, String alias, String[] args) { - if (args.length < 1) - return false; - val chan = Channel.getChannels().stream().filter(ch -> ch.ID.equalsIgnoreCase(args[0]) || (ch.IDs != null && Arrays.stream(ch.IDs).anyMatch(cid -> cid.equalsIgnoreCase(args[0])))).findAny(); - if (!chan.isPresent()) { - player.sendMessage("§cChannel with ID '" + args[0] + "' not found! The ID is the command for it without the /."); - return true; - } - val dp = TBMCPlayer.getPlayer(player.getUniqueId(), TBMCPlayer.class).getAs(DiscordPlayer.class); - if (dp == null) { - player.sendMessage("§cYou need to connect your Discord account. In #bot do @ChromaBot connect " + player.getName()); - return true; - } - val ev = new TBMCChannelConnectEvent(player, chan.get()); - Bukkit.getPluginManager().callEvent(ev); - if (ev.isCancelled() || ev.getGroupid() == null) { - player.sendMessage("§cSorry, that didn't work. You cannot use that channel."); - return true; - } - //MCChatListener.addCustomChat() - TODO: Call in Discord cmd - PendingConnections.put(dp.getDiscordID(), new AbstractMap.SimpleEntry<>(ev.getChannel(), ev.getGroupid())); - player.sendMessage("§bAlright! Now invite me to your server then show me the channel to use (@ChromaBot here)."); - return true; - } - - @Override - public String[] GetHelpText(String s) { - return new String[]{// - "§6---- Channel connect ---", // - "This command allows you to connect a Minecraft channel to a Discord channel.", // - "You need to have access to the MC channel and have manage permissions on the Discord channel." // - }; - } - - /** - * Key: Discord ID - * Value of value. Channel Group ID - */ - public static HashMap> PendingConnections = new HashMap<>(); -}