diff --git a/pom.xml b/pom.xml
index f800c25c4..8d3ebd32e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -117,6 +117,13 @@
6.1.0-TF
+
+ net.dv8tion
+ JDA
+ 3.8.0_423
+ provided
+
+
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java b/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java
index 04011fc16..1d72516b5 100644
--- a/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java
+++ b/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java
@@ -21,6 +21,7 @@
import me.totalfreedom.totalfreedommod.caging.Cager;
import me.totalfreedom.totalfreedommod.command.CommandLoader;
import me.totalfreedom.totalfreedommod.config.MainConfig;
+import me.totalfreedom.totalfreedommod.discord.Discord;
import me.totalfreedom.totalfreedommod.freeze.Freezer;
import me.totalfreedom.totalfreedommod.fun.ItemFun;
import me.totalfreedom.totalfreedommod.fun.Jumppads;
@@ -74,6 +75,7 @@ public class TotalFreedomMod extends AeroPlugin
public PlayerList pl;
public Announcer an;
public ChatManager cm;
+ public Discord dc;
public BanManager bm;
public PermbanList pm;
public ProtectArea pa;
@@ -167,6 +169,7 @@ public void enable()
pl = services.registerService(PlayerList.class);
an = services.registerService(Announcer.class);
cm = services.registerService(ChatManager.class);
+ dc = services.registerService(Discord.class);
bm = services.registerService(BanManager.class);
pm = services.registerService(PermbanList.class);
pa = services.registerService(ProtectArea.class);
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java b/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java
index 35b61d631..97f9acbd6 100644
--- a/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java
+++ b/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java
@@ -39,6 +39,9 @@ public class Admin implements ConfigLoadable, ConfigSavable, Validatable
@Getter
@Setter
private String loginMessage = null;
+ @Getter
+ @Setter
+ private String discordID = null;
public Admin(Player player)
{
@@ -62,7 +65,8 @@ public String toString()
.append("- Last Login: ").append(FUtil.dateToString(lastLogin)).append("\n")
.append("- Custom Login Message: ").append(loginMessage).append("\n")
.append("- Rank: ").append(rank.getName()).append("\n")
- .append("- Is Active: ").append(active);
+ .append("- Is Active: ").append(active)
+ .append("- Discord ID: ").append(discordID).append("\n");
return output.toString();
}
@@ -85,6 +89,7 @@ public void loadFrom(ConfigurationSection cs)
ips.addAll(cs.getStringList("ips"));
lastLogin = FUtil.stringToDate(cs.getString("last_login"));
loginMessage = cs.getString("login_message", null);
+ discordID = cs.getString("discord_id", null);
}
@Override
@@ -97,6 +102,7 @@ public void saveTo(ConfigurationSection cs)
cs.set("ips", Lists.newArrayList(ips));
cs.set("last_login", FUtil.dateToString(lastLogin));
cs.set("login_message", loginMessage);
+ cs.set("discord_id", discordID);
}
public boolean isAtLeast(Rank pRank)
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java
new file mode 100644
index 000000000..7cbdc0c53
--- /dev/null
+++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java
@@ -0,0 +1,50 @@
+package me.totalfreedom.totalfreedommod.command;
+
+import java.util.Random;
+import me.totalfreedom.totalfreedommod.admin.Admin;
+import me.totalfreedom.totalfreedommod.discord.Discord;
+import me.totalfreedom.totalfreedommod.rank.Rank;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+@CommandPermissions(level = Rank.SUPER_ADMIN, source = SourceType.ONLY_IN_GAME)
+@CommandParameters(description = "Link your Discord account to your Minecraft account", usage = "/")
+public class Command_linkdiscord extends FreedomCommand
+{
+
+ @Override
+ public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
+ {
+ if (!plugin.dc.enabled)
+ {
+ msg("The Discord verification system is currently disabled.", ChatColor.RED);
+ return true;
+ }
+
+ Admin admin = plugin.al.getAdmin(playerSender);
+ if (admin.getDiscordID() != null)
+ {
+ msg("Your Minecraft account is already linked to a Discord account.", ChatColor.RED);
+ return true;
+ }
+
+ if (Discord.LINK_CODES.containsValue(admin))
+ {
+ msg("Your linking code is " + ChatColor.GREEN + Discord.getCode(admin), ChatColor.AQUA);
+ }
+ else
+ {
+ String code = "";
+ Random random = new Random();
+ for (int i = 0; i < 5; i++)
+ {
+ code += random.nextInt(10);
+ }
+ Discord.LINK_CODES.put(code, admin);
+ msg("Your linking code is " + ChatColor.GREEN + code, ChatColor.AQUA);
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java
new file mode 100644
index 000000000..b09b71dc8
--- /dev/null
+++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java
@@ -0,0 +1,35 @@
+package me.totalfreedom.totalfreedommod.command;
+
+import me.totalfreedom.totalfreedommod.admin.Admin;
+import me.totalfreedom.totalfreedommod.rank.Rank;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+@CommandPermissions(level = Rank.SUPER_ADMIN, source = SourceType.ONLY_IN_GAME)
+@CommandParameters(description = "Unlink your Discord account to your Minecraft account", usage = "/")
+public class Command_unlinkdiscord extends FreedomCommand
+{
+
+ @Override
+ public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
+ {
+ if (!plugin.dc.enabled)
+ {
+ msg("The Discord verification system is currently disabled.", ChatColor.RED);
+ return true;
+ }
+
+ Admin admin = plugin.al.getAdmin(playerSender);
+ if (admin.getDiscordID() == null)
+ {
+ msg("Your Minecraft account is not linked to a Discord account.", ChatColor.RED);
+ return true;
+ }
+ admin.setDiscordID(null);
+ plugin.al.save();
+ msg("Your Minecraft account has been successfully unlinked from the Discord account.", ChatColor.GREEN);
+ return true;
+ }
+}
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java
new file mode 100644
index 000000000..79d250da5
--- /dev/null
+++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java
@@ -0,0 +1,86 @@
+package me.totalfreedom.totalfreedommod.command;
+
+import me.totalfreedom.totalfreedommod.rank.Rank;
+import me.totalfreedom.totalfreedommod.player.FPlayer;
+import me.totalfreedom.totalfreedommod.admin.Admin;
+import me.totalfreedom.totalfreedommod.util.FUtil;
+import me.totalfreedom.totalfreedommod.config.ConfigEntry;
+import me.totalfreedom.totalfreedommod.discord.Discord;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.ChatColor;
+import java.util.Random;
+import java.util.Date;
+import net.pravian.aero.util.Ips;
+
+@CommandPermissions(level = Rank.IMPOSTOR, source = SourceType.ONLY_IN_GAME)
+@CommandParameters(description = "Sends a verification code to the player, or the player can input the sent code.", usage = "/ [code]")
+public class Command_verify extends FreedomCommand
+{
+
+ @Override
+ public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
+ {
+ if (!plugin.dc.enabled)
+ {
+ msg("The discord verification system is currently disabled", ChatColor.RED);
+ return true;
+ }
+
+ if (!plugin.al.isAdminImpostor(playerSender))
+ {
+ msg("You are not an imposter, therefore you do not need to verify.", ChatColor.RED);
+ return true;
+ }
+
+ Admin admin = plugin.al.getEntryByName(playerSender.getName());
+
+ if (admin.getDiscordID() == null)
+ {
+ msg("You do not have a discord account linked to your minecraft account, please verify the manual way.", ChatColor.RED);
+ return true;
+ }
+
+ if (args.length < 1)
+ {
+ String code = "";
+ Random random = new Random();
+ for (int i = 0; i < 10; i++)
+ {
+ code += random.nextInt(10);
+ }
+ Discord.VERIFY_CODES.add(code);
+ Discord.bot.getUserById(admin.getDiscordID()).openPrivateChannel().complete().sendMessage("A user with the ip `" + Ips.getIp(playerSender) + "` has sent a verification request. Please run the following in-game command: `/verify " + code + "`").complete();
+ msg("A verification code has been sent to your account, please copy the code and run /verify ", ChatColor.GREEN);
+ }
+ else
+ {
+ String code = args[0];
+ if (!Discord.VERIFY_CODES.contains(code))
+ {
+ msg("You have entered an invalid verification code", ChatColor.RED);
+ return true;
+ }
+ else
+ {
+ Discord.VERIFY_CODES.remove(code);
+ FUtil.bcastMsg(playerSender.getName() + " has verified themself via Discord!", ChatColor.GOLD);
+ FUtil.adminAction(ConfigEntry.SERVER_NAME.getString(), "Readding " + admin.getName() + " to the admin list", true);
+ admin.setName(playerSender.getName());
+ admin.addIp(Ips.getIp(playerSender));
+ admin.setActive(true);
+ admin.setLastLogin(new Date());
+ plugin.al.save();
+ plugin.al.updateTables();
+ final FPlayer fPlayer = plugin.pl.getPlayer(playerSender);
+ if (fPlayer.getFreezeData().isFrozen())
+ {
+ fPlayer.getFreezeData().setFrozen(false);
+ msg("You have been unfrozen.");
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java b/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java
index 01fa9ed8a..87eb8b3f1 100644
--- a/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java
+++ b/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java
@@ -38,6 +38,8 @@ public enum ConfigEntry
SERVER_BAN_URL(String.class, "server.ban_url"),
SERVER_PERMBAN_URL(String.class, "server.permban_url"),
//
+ DISCORD_TOKEN(String.class, "discord.token"),
+ //
ADMINLIST_CLEAN_THESHOLD_HOURS(Integer.class, "adminlist.clean_threshold_hours"),
ADMINLIST_CONSOLE_IS_SENIOR(Boolean.class, "adminlist.console_is_senior"),
//
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java b/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java
new file mode 100644
index 000000000..4b9751de0
--- /dev/null
+++ b/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java
@@ -0,0 +1,85 @@
+package me.totalfreedom.totalfreedommod.discord;
+
+import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import javax.security.auth.login.LoginException;
+import me.totalfreedom.totalfreedommod.FreedomService;
+import me.totalfreedom.totalfreedommod.TotalFreedomMod;
+import me.totalfreedom.totalfreedommod.admin.Admin;
+import me.totalfreedom.totalfreedommod.config.ConfigEntry;
+import me.totalfreedom.totalfreedommod.util.FLog;
+import net.dv8tion.jda.core.AccountType;
+import net.dv8tion.jda.core.JDA;
+import net.dv8tion.jda.core.JDABuilder;
+
+public class Discord extends FreedomService
+{
+ public static HashMap LINK_CODES = new HashMap<>();
+ public static List VERIFY_CODES = new ArrayList();
+ public static JDA bot = null;
+ public Boolean enabled = false;
+
+ public Discord(TotalFreedomMod plugin)
+ {
+ super(plugin);
+ }
+
+ public void startBot()
+ {
+ enabled = !Strings.isNullOrEmpty(ConfigEntry.DISCORD_TOKEN.getString());
+ if (!enabled)
+ {
+ return;
+ }
+ if (bot != null)
+ {
+ for (Object object : bot.getRegisteredListeners())
+ {
+ bot.removeEventListener(object);
+ }
+ }
+ try
+ {
+ bot = new JDABuilder(AccountType.BOT).setToken(ConfigEntry.DISCORD_TOKEN.getString()).addEventListener(new MessageListener()).setAudioEnabled(false).setAutoReconnect(true).buildBlocking();
+ FLog.info("Discord verification bot has successfully enabled!");
+ }
+ catch (LoginException e)
+ {
+ FLog.warning("An invalid token for the discord verification bot, the bot will not enable.");
+ }
+ catch (IllegalArgumentException | InterruptedException e)
+ {
+ FLog.warning("Discord verification bot failed to start.");
+ }
+ }
+
+ @Override
+ protected void onStart()
+ {
+ startBot();
+ }
+
+ public static String getCode(Admin admin)
+ {
+ for (String code : LINK_CODES.keySet())
+ {
+ if (LINK_CODES.get(code).equals(admin))
+ {
+ return code;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onStop()
+ {
+ if (bot != null)
+ {
+ bot.shutdown();
+ }
+ FLog.info("Discord verification bot has successfully shutdown.");
+ }
+}
diff --git a/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java b/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java
new file mode 100644
index 000000000..dfba67600
--- /dev/null
+++ b/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java
@@ -0,0 +1,28 @@
+package me.totalfreedom.totalfreedommod.discord;
+
+import me.totalfreedom.totalfreedommod.admin.Admin;
+import net.dv8tion.jda.core.events.message.priv.PrivateMessageReceivedEvent;
+import net.dv8tion.jda.core.hooks.ListenerAdapter;
+
+public class MessageListener extends ListenerAdapter
+{
+ public void onPrivateMessageReceived(PrivateMessageReceivedEvent event)
+ {
+ if (!event.getAuthor().getId().equals(Discord.bot.getSelfUser().getId()))
+ {
+ // Handle link code
+ if (event.getMessage().getContentRaw().matches("[0-9][0-9][0-9][0-9][0-9]"))
+ {
+ String code = event.getMessage().getContentRaw();
+ if (Discord.LINK_CODES.get(code) != null)
+ {
+ Admin admin = Discord.LINK_CODES.get(code);
+ admin.setDiscordID(event.getMessage().getAuthor().getId());
+ Discord.LINK_CODES.remove(code);
+ event.getChannel().sendMessage("Link successful. Now this Discord account is linked with the Minecraft account `" + admin.getName() + "`.\n "
+ + "Now when you are an impostor on the server, you may use `/verify` to verify.").complete();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 8c0bddb0a..d5df06d96 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -27,6 +27,11 @@ server:
# URL players should appeal for permanent bans at
permban_url: http://bit.ly/TF_PermBan
+# Discord
+discord:
+ # If you do not have a token, make a bot account and get one at https://discordapp.com/developers/applications/me
+ token: ''
+
# Admin list
adminlist: