diff --git a/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java b/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java index 5de8cc2..d9e145c 100644 --- a/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java +++ b/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java @@ -51,6 +51,10 @@ public class DiscordLink { cache = new Cache(); } + //TODO set up a repeating task that checks if ppl with the link role are really linked + //TODO fix unlinking in game not unlinking in discord + //TODO fix nitro booster role not being removed in game (set up a command to force check?) + //TODO fix &sync @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) { ALogger.init(logger); diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java b/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java index c640650..7698500 100644 --- a/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java +++ b/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java @@ -1,7 +1,9 @@ package com.alttd.proxydiscordlink.bot; +import com.alttd.proxydiscordlink.DiscordLink; import com.alttd.proxydiscordlink.bot.listeners.DiscordMessageListener; import com.alttd.proxydiscordlink.bot.listeners.DiscordRoleListener; +import com.alttd.proxydiscordlink.bot.tasks.CheckLinkSync; import com.alttd.proxydiscordlink.config.BotConfig; import com.alttd.proxydiscordlink.util.ALogger; import net.dv8tion.jda.api.EmbedBuilder; @@ -19,8 +21,10 @@ import net.dv8tion.jda.api.utils.MemberCachePolicy; import org.jetbrains.annotations.Nullable; import javax.security.auth.login.LoginException; +import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class Bot { private JDA jda = null; @@ -34,11 +38,19 @@ public class Bot { .enableIntents(GatewayIntent.GUILD_MEMBERS) .build(); jda.setAutoReconnect(true); + jda.awaitReady(); jda.addEventListener(new DiscordMessageListener(), new DiscordRoleListener()); + DiscordCommand.loadCommands(); + DiscordLink.getPlugin().getProxy().getScheduler().buildTask(DiscordLink.getPlugin(), new CheckLinkSync()) + .delay(120, TimeUnit.SECONDS) + .repeat(12, TimeUnit.HOURS) + .schedule(); } catch (LoginException e) { jda = null; + } catch (InterruptedException e) { + throw new RuntimeException(e); } } @@ -231,4 +243,20 @@ public class Bot { ALogger.warn("Unable to ban " + member.getAsMention() + " : " + member.getId() + " from Discord they might be above me."); } } + + public List getMembersWithRole(long guildId, long roleId) { + Guild guild = jda.getGuildById(guildId); + Role role = jda.getRoleById(roleId); + + if (guild == null) { + //TODO error + return null; + } + if (role == null) { + //TODO error + return null; + } + + return guild.getMembers().stream().filter(member -> member.getRoles().contains(role)).toList(); + } } diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckLinkSync.java b/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckLinkSync.java new file mode 100644 index 0000000..dcfc2f8 --- /dev/null +++ b/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckLinkSync.java @@ -0,0 +1,77 @@ +package com.alttd.proxydiscordlink.bot.tasks; + +import com.alttd.proxydiscordlink.DiscordLink; +import com.alttd.proxydiscordlink.bot.Bot; +import com.alttd.proxydiscordlink.config.BotConfig; +import com.alttd.proxydiscordlink.util.ALogger; +import net.dv8tion.jda.api.entities.Member; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class CheckLinkSync implements Runnable { + + private final DiscordLink plugin; + private final Bot bot; + + public CheckLinkSync() { + plugin = DiscordLink.getPlugin(); + bot = plugin.getBot(); + } + + @Override + public void run() { + List members = bot.getMembersWithRole(BotConfig.GUILD_ID, BotConfig.LINKED_ROLE_ID); + HashSet dbIdSet = plugin.getDatabase().getLinkedUsers(); + HashSet membersIdSet = members.stream().map(Member::getIdLong).collect(Collectors.toCollection(HashSet::new)); + + //give these people the link role in discord, if they are not in the discord unlink them in game + HashSet noRoleIds = dbIdSet.stream().filter(id -> !membersIdSet.contains(id)).collect(Collectors.toCollection(HashSet::new)); + + //remove the linked role from these people + HashSet notInDbIds = membersIdSet.stream().filter(id -> !dbIdSet.contains(id)).collect(Collectors.toCollection(HashSet::new)); + + fixNotInDb(members, notInDbIds); + fixNoLinkRole(members, noRoleIds); + } + + private void fixNotInDb(List members, Set notInDbIds) { + for (Long id : notInDbIds) { + members.stream() + .filter(member -> member.getIdLong() == id) + .findAny() + .ifPresent(member -> { + ALogger.info("Removing linked role from user with discord id: [" + id + "] due to them not being in the database."); +// bot.removeRole(id, BotConfig.LINKED_ROLE_ID, member.getGuild().getIdLong()); + }); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + private void fixNoLinkRole(List members, Set noRoleIds) { + for (Long id : noRoleIds) { + members.stream() + .filter(member -> member.getIdLong() == id) + .findAny() + .ifPresentOrElse( + member -> { + ALogger.info("Adding role to user with discord id: [" + id + "] due to them being in the database without having a role in discord."); +// bot.addRole(id, BotConfig.LINKED_ROLE_ID, member.getGuild().getIdLong()); + }, () -> { + ALogger.info("Removing user with discord id: [" + id + "] from the database due to them not being in the discord."); +// plugin.getDatabase().removeLinkedAccount(id); + }); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckNitroSync.java b/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckNitroSync.java new file mode 100644 index 0000000..3dfff4d --- /dev/null +++ b/src/main/java/com/alttd/proxydiscordlink/bot/tasks/CheckNitroSync.java @@ -0,0 +1,7 @@ +package com.alttd.proxydiscordlink.bot.tasks; + +public class CheckNitroSync { + + //TODO copy CheckLinkSync but for nitro + +} diff --git a/src/main/java/com/alttd/proxydiscordlink/database/Database.java b/src/main/java/com/alttd/proxydiscordlink/database/Database.java index e65c54b..cb77c29 100644 --- a/src/main/java/com/alttd/proxydiscordlink/database/Database.java +++ b/src/main/java/com/alttd/proxydiscordlink/database/Database.java @@ -1,13 +1,14 @@ package com.alttd.proxydiscordlink.database; import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer; -import com.velocitypowered.api.proxy.Player; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.UUID; public class Database { @@ -103,6 +104,19 @@ public class Database { } } + public void removeRole(UUID uuid, String roleName) { + try { + String sql = "DELETE FROM account_roles WHERE uuid = ? AND role_name = ?"; + + PreparedStatement statement = DatabaseConnection.getConnection().prepareStatement(sql); + statement.setString(1, uuid.toString()); + statement.setString(2, roleName); + statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + } + public boolean playerIsLinked(UUID uuid) { //TODO maybe this can be using the discord api instead? (or a cache idk) try { PreparedStatement statement = DatabaseConnection.getConnection() @@ -149,7 +163,17 @@ public class Database { } catch (SQLException var2) { var2.printStackTrace(); } + } + public void removeLinkedAccount(Long id) { + try { + PreparedStatement statement = DatabaseConnection.getConnection() + .prepareStatement("DELETE FROM linked_accounts WHERE discord_id = ?"); + statement.setLong(1, id); + statement.executeUpdate(); + } catch (SQLException var2) { + var2.printStackTrace(); + } } public String uuidFromName(String playerName) { @@ -269,4 +293,20 @@ public class Database { exception.printStackTrace(); } } + + public HashSet getLinkedUsers() { + String sql = "SELECT discord_id FROM linked_accounts"; + try { + PreparedStatement statement = DatabaseConnection.getConnection().prepareStatement(sql); + ResultSet resultSet = statement.executeQuery(); + HashSet results = new HashSet<>(); + while (resultSet.next()) { + results.add(resultSet.getLong("discord_id")); + } + return results; + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/src/main/java/com/alttd/proxydiscordlink/minecraft/listeners/PlayerJoin.java b/src/main/java/com/alttd/proxydiscordlink/minecraft/listeners/PlayerJoin.java index 6bb0730..7370009 100644 --- a/src/main/java/com/alttd/proxydiscordlink/minecraft/listeners/PlayerJoin.java +++ b/src/main/java/com/alttd/proxydiscordlink/minecraft/listeners/PlayerJoin.java @@ -3,9 +3,14 @@ package com.alttd.proxydiscordlink.minecraft.listeners; import com.alttd.proxydiscordlink.DiscordLink; import com.alttd.proxydiscordlink.config.BotConfig; import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer; +import com.alttd.proxydiscordlink.util.ALogger; +import com.alttd.proxydiscordlink.util.Utilities; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.player.ServerConnectedEvent; +import com.velocitypowered.api.proxy.Player; + +import java.util.UUID; public class PlayerJoin { @@ -13,14 +18,16 @@ public class PlayerJoin { public void playerConnected(ServerConnectedEvent event) { if (event.getPreviousServer().isPresent()) return; + Player player = event.getPlayer(); + UUID uuid = player.getUniqueId(); - DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(event.getPlayer().getUniqueId()); + DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(uuid); if (discordLinkPlayer == null) return; boolean sync = false; - String username = event.getPlayer().getUsername(); + String username = player.getUsername(); if (!discordLinkPlayer.getUsername().equals(username)) { //Update username if needed discordLinkPlayer.setUsername(username); @@ -39,6 +46,18 @@ public class PlayerJoin { DiscordLink.getPlugin().getBot().changeNick(BotConfig.GUILD_ID, discordLinkPlayer.getUserId(), nick); } + boolean hasMinecraftNitro = Utilities.hasMinecraftNitro(player); + boolean hasDatabaseNitro = Utilities.hasDatabaseNitro(discordLinkPlayer); + if (hasMinecraftNitro != hasDatabaseNitro) { + if (hasMinecraftNitro) { + //Utilities.removeRole(uuid, "nitro"); //TODO add nitro to config + ALogger.info("Removing nitro role from [" + player.getUsername() + "] since they shouldn't have it"); + } else { + //Utilities.addRole(uuid, "nitro"); //TODO add nitro to config + ALogger.info("Added nitro role to [" + player.getUsername() + "] since they should have it"); + } + } + if (sync) //Sync if needed DiscordLink.getPlugin().getDatabase().syncPlayer(discordLinkPlayer); } diff --git a/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java b/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java index c29b0dc..8766745 100644 --- a/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java +++ b/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java @@ -3,6 +3,7 @@ package com.alttd.proxydiscordlink.util; import com.alttd.proxydiscordlink.DiscordLink; import com.alttd.proxydiscordlink.bot.objects.DiscordRole; import com.alttd.proxydiscordlink.config.Config; +import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import net.dv8tion.jda.api.entities.Member; @@ -72,6 +73,16 @@ public class Utilities { return false; } + public static boolean hasDatabaseNitro(DiscordLinkPlayer player) { + List groups = player.getRoles(); + for (String group : Config.DISCORD_GROUPS) { + if (groups.contains(group)) { + return true; + } + } + return false; + } + public static String getAuthKey() { String randChars = "1234567890"; StringBuilder salt = new StringBuilder(); @@ -130,4 +141,30 @@ public class Utilities { }) .collect(Collectors.toList()); } + + public static boolean removeRole(UUID uuid, String group) { + User user = getLuckPerms().getUserManager().getUser(uuid); + if (user == null) + return false; + user.getNodes(NodeType.INHERITANCE) + .stream() + .filter(inheritanceNode -> inheritanceNode.getGroupName().equalsIgnoreCase(group)) + .findAny() + .ifPresent(node -> + getLuckPerms().getUserManager().modifyUser(uuid, result -> result.data().remove(node))); + return true; + } + + public static boolean addRole(UUID uuid, String group) { + User user = getLuckPerms().getUserManager().getUser(uuid); + if (user == null) + return false; + user.getNodes(NodeType.INHERITANCE) + .stream() + .filter(inheritanceNode -> inheritanceNode.getGroupName().equalsIgnoreCase(group)) + .findAny() + .ifPresent(node -> + getLuckPerms().getUserManager().modifyUser(uuid, result -> result.data().add(node))); + return true; + } }