package net.essentialsx.discordlink.rolesync; import com.earth2me.essentials.UUIDPlayer; import com.google.common.collect.BiMap; import net.essentialsx.api.v2.events.discordlink.DiscordLinkStatusChangeEvent; import net.essentialsx.api.v2.services.discord.InteractionMember; import net.essentialsx.api.v2.services.discord.InteractionRole; import net.essentialsx.discordlink.EssentialsDiscordLink; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import static com.earth2me.essentials.I18n.tl; public class RoleSyncManager implements Listener { private final EssentialsDiscordLink ess; private final Map groupToRoleMap = new HashMap<>(); private final Map roleIdToGroupMap = new HashMap<>(); public RoleSyncManager(final EssentialsDiscordLink ess) { this.ess = ess; Bukkit.getPluginManager().registerEvents(this, ess); onReload(); this.ess.getEss().runTaskTimerAsynchronously(() -> { if (groupToRoleMap.isEmpty() && roleIdToGroupMap.isEmpty()) { return; } final BiMap uuidToDiscordCopy = ess.getAccountStorage().getRawStorageMap(); final Map groupToRoleMapCopy = new HashMap<>(groupToRoleMap); final Map roleIdToGroupMapCopy = new HashMap<>(roleIdToGroupMap); final boolean primaryOnly = ess.getSettings().isRoleSyncPrimaryGroupOnly(); final boolean removeGroups = ess.getSettings().isRoleSyncRemoveGroups(); final boolean removeRoles = ess.getSettings().isRoleSyncRemoveRoles(); for (final Map.Entry entry : uuidToDiscordCopy.entrySet()) { sync(new UUIDPlayer(UUID.fromString(entry.getKey())), entry.getValue(), groupToRoleMapCopy, roleIdToGroupMapCopy, primaryOnly, removeGroups, removeRoles); } }, 0, ess.getSettings().getRoleSyncResyncDelay() * 1200L); } public void sync(final UUID uuid, final String discordId) { final Map groupToRoleMapCopy = new HashMap<>(groupToRoleMap); final Map roleIdToGroupMapCopy = new HashMap<>(roleIdToGroupMap); final boolean primaryOnly = ess.getSettings().isRoleSyncPrimaryGroupOnly(); final boolean removeGroups = ess.getSettings().isRoleSyncRemoveGroups(); final boolean removeRoles = ess.getSettings().isRoleSyncRemoveRoles(); sync(new UUIDPlayer(uuid), discordId, groupToRoleMapCopy, roleIdToGroupMapCopy, primaryOnly, removeGroups, removeRoles); } public void sync(final Player player, final String discordId, final Map groupToRoleMap, final Map roleIdToGroupMap, final boolean primaryOnly, final boolean removeGroups, final boolean removeRoles) { final List groups = primaryOnly ? Collections.singletonList(ess.getEss().getPermissionsHandler().getGroup(player)) : ess.getEss().getPermissionsHandler().getGroups(player); final InteractionMember member = ess.getApi().getMemberById(discordId).join(); if (member == null) { if (ess.getSettings().isUnlinkOnLeave()) { ess.getLinkManager().removeAccount(ess.getEss().getUser(player.getUniqueId()), DiscordLinkStatusChangeEvent.Cause.UNSYNC_LEAVE); } else { unSync(player.getUniqueId(), discordId); } return; } final List toAdd = new ArrayList<>(); final List toRemove = new ArrayList<>(); for (final Map.Entry entry : groupToRoleMap.entrySet()) { if (groups.contains(entry.getKey()) && !member.hasRole(entry.getValue())) { toAdd.add(entry.getValue()); } else if (removeRoles && !groups.contains(entry.getKey()) && member.hasRole(entry.getValue())) { toRemove.add(entry.getValue()); } } for (final Map.Entry entry : roleIdToGroupMap.entrySet()) { if (member.hasRole(entry.getKey()) && !groups.contains(entry.getValue())) { ess.getEss().getPermissionsHandler().addToGroup(player, entry.getValue()); } else if (removeGroups && !member.hasRole(entry.getKey()) && groups.contains(entry.getValue())) { ess.getEss().getPermissionsHandler().removeFromGroup(player, entry.getValue()); } } if (toAdd.isEmpty() && toRemove.isEmpty()) { return; } ess.getApi().modifyMemberRoles(member, toAdd, toRemove); } public void unSync(final UUID uuid, final String discordId) { final boolean removeGroups = ess.getSettings().isRoleSyncRemoveGroups(); final boolean removeRoles = ess.getSettings().isRoleSyncRemoveRoles(); if (!removeGroups && !removeRoles) { return; } final Map groupToRoleMapCopy = new HashMap<>(groupToRoleMap); final Map roleIdToGroupMapCopy = new HashMap<>(roleIdToGroupMap); final Player player = new UUIDPlayer(uuid); final InteractionMember member = ess.getApi().getMemberById(discordId).join(); if (removeGroups) { for (final String group : roleIdToGroupMapCopy.values()) { ess.getEss().getPermissionsHandler().removeFromGroup(player, group); } } // Check if the member is no longer in the guild (null), they don't have any roles anyway. if (removeRoles && member != null) { ess.getApi().modifyMemberRoles(member, null, groupToRoleMapCopy.values()); } } @EventHandler public void onJoin(PlayerJoinEvent event) { ess.getEss().runTaskAsynchronously(() -> { if (ess.getLinkManager().isLinked(event.getPlayer().getUniqueId())) { sync(event.getPlayer().getUniqueId(), ess.getLinkManager().getDiscordId(event.getPlayer().getUniqueId())); } }); } public void onReload() { groupToRoleMap.clear(); roleIdToGroupMap.clear(); final List groups = ess.getEss().getPermissionsHandler().getGroups(); for (final Map.Entry entry : ess.getSettings().getRoleSyncGroups().entrySet()) { if (isExampleRole(entry.getValue())) { continue; } final String group = entry.getKey(); final InteractionRole role = ess.getApi().getRole(entry.getValue()); if (!groups.contains(group)) { ess.getLogger().warning(tl("discordLinkInvalidGroup", group, entry.getValue(), groups)); continue; } if (role == null) { ess.getLogger().warning(tl("discordLinkInvalidRole", entry.getValue(), group)); continue; } if (role.isManaged() || role.isPublicRole()) { ess.getLogger().warning(tl("discordLinkInvalidRoleManaged", role.getName(), role.getId())); continue; } if (!role.canInteract()) { ess.getLogger().warning(tl("discordLinkInvalidRoleInteract", role.getName(), role.getId())); continue; } groupToRoleMap.put(group, role); } for (final Map.Entry entry : ess.getSettings().getRoleSyncRoles().entrySet()) { if (isExampleRole(entry.getKey())) { continue; } final InteractionRole role = ess.getApi().getRole(entry.getKey()); final String group = entry.getValue(); if (role == null) { ess.getLogger().warning(tl("discordLinkInvalidRole", entry.getKey(), group)); continue; } if (!groups.contains(group)) { ess.getLogger().warning(tl("discordLinkInvalidGroup", group, entry.getKey(), groups)); continue; } roleIdToGroupMap.put(role.getId(), group); } } private boolean isExampleRole(final String role) { return role.equals("0") || role.equals("11111111111111111") || role.equals("22222222222222222") || role.equals("33333333333333333"); } }