package ru.simsonic.rscPermissions.Bukkit; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionAttachment; import ru.simsonic.rscCommonsLibrary.RestartableThread; import ru.simsonic.rscMinecraftLibrary.Bukkit.GenericChatCodes; import ru.simsonic.rscMinecraftLibrary.Bukkit.Tools; import ru.simsonic.rscPermissions.API.Settings; import ru.simsonic.rscPermissions.BukkitPluginMain; import ru.simsonic.rscPermissions.Engine.Phrases; import ru.simsonic.rscPermissions.Engine.ResolutionParams; import ru.simsonic.rscPermissions.Engine.ResolutionResult; public class BukkitPermissionManager extends RestartableThread { private final BukkitPluginMain rscp; public BukkitPermissionManager(BukkitPluginMain plugin) { this.rscp = plugin; } private final LinkedBlockingQueue updateQueue = new LinkedBlockingQueue<>(); private final Map resolutions = new ConcurrentHashMap<>(); private final Map attachments = new HashMap<>(); private final Map> persistent = new HashMap<>(); // private final Map> temporary = new HashMap<>(); private final Set debug = new HashSet<>(); public void recalculateOnlinePlayers() { resolutions.clear(); updateQueue.addAll(Tools.getOnlinePlayers()); rscp.scheduleAutoUpdate(); } public void recalculatePlayer(Player player) { try { updateQueue.put(player); } catch(InterruptedException ex) { } } public ResolutionResult getResult(String playerIdentifier) { return resolutions.containsKey(playerIdentifier) ? resolutions.get(playerIdentifier) : resolvePlayerIdentifier(playerIdentifier); } public ResolutionResult getResult(OfflinePlayer offline) { final String key = offline.toString(); return resolutions.containsKey(key) ? resolutions.get(key) : resolveOfflinePlayer(offline); } public ResolutionResult getResult(Player player) { final String key = player.toString(); return resolutions.containsKey(key) ? resolutions.get(key) : resolvePlayer(player); } public Map listPlayerPermissions(Player player) { final PermissionAttachment attachment = rscp.permissionManager.attachments.get(player); if(attachment != null) return attachment.getPermissions(); return Collections.EMPTY_MAP; } public void removePlayer(Player player) { updateQueue.remove(player); attachments.remove(player); persistent.remove(player); // temporary.remove(player); synchronized(debug) { debug.remove(player); } } @Override public void run() { Thread.currentThread().setName("rscp:" + this.getClass().getSimpleName()); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); try { for(Player current = updateQueue.take(); current != null; current = updateQueue.take()) { final ResolutionResult result = rscp.permissionManager.resolvePlayer(current); persistent.put(current, result.getPermissions()); final Player player = current; rscp.getServer().getScheduler().runTask(rscp, new Runnable() { @Override public void run() { // Remove old if(attachments.containsKey(player)) attachments.remove(player).remove(); // Create new and fill with permissions final PermissionAttachment attachment = player.addAttachment(rscp); attachments.put(player, attachment); final Map pp = persistent.get(player); if(pp != null && !pp.isEmpty()) for(Map.Entry row : pp.entrySet()) attachment.setPermission(row.getKey(), row.getValue()); /* final Map tp = temporary.get(player); if(tp != null && !tp.isEmpty()) for(Map.Entry row : tp.entrySet()) attachment.setPermission(row.getKey(), row.getValue()); */ // Set/reset Server Operator status final Boolean asterisk = attachment.getPermissions().get("*"); if(rscp.settings.isAsteriskOP()) player.setOp(asterisk != null ? asterisk : false); // Show debugging information if(isDebugging(player)) { final String groupList = "{_LG}" + GenericChatCodes.glue(result.getDeorderedGroups(), "{_LS}, {_LG}") + "{_LS}"; final String permsSize = String.valueOf(attachment.getPermissions().size()); final String[] lines = new String[] { Phrases.DEBUG_INGAME_1.toString().replace("{:PARENTS}", groupList), Phrases.DEBUG_INGAME_2.toString().replace("{:PERMISSIONS}", permsSize), }; for(String line : lines) player.sendMessage(GenericChatCodes.processStringStatic(Settings.CHAT_PREFIX + line)); } } }); } } catch(InterruptedException ex) { } updateQueue.clear(); } public synchronized ResolutionResult resolvePlayerIdentifier(String playerIdentifier) { final ResolutionParams params = new ResolutionParams(); params.applicableIdentifiers = new String[] { playerIdentifier }; final ResolutionResult result = rscp.internalCache.resolvePlayer(params); resolutions.put(playerIdentifier, result); return result; } public synchronized ResolutionResult resolveOfflinePlayer(OfflinePlayer offline) { final ResolutionParams params = new ResolutionParams(); params.applicableIdentifiers = BukkitUtilities.getOfflinePlayerIdentifiers(offline); final ResolutionResult result = rscp.internalCache.resolvePlayer(params); for(String id : params.applicableIdentifiers) resolutions.put(id, result); resolutions.put(offline.toString(), result); return result; } public synchronized ResolutionResult resolvePlayer(Player player) { final ResolutionParams params = new ResolutionParams(); params.applicableIdentifiers = BukkitUtilities.getPlayerIdentifiers(player); if(rscp.regionListProvider != null) { Set regionSet = rscp.regionListProvider.getPlayerRegions(player); params.destRegions = regionSet.toArray(new String[regionSet.size()]); } params.destWorld = player.getLocation().getWorld().getName(); params.expirience = player.getLevel(); final ResolutionResult result = rscp.internalCache.resolvePlayer(params); for(String id : params.applicableIdentifiers) resolutions.put(id, result); resolutions.put(player.toString(), result); return result; } public synchronized void forgetOfflinePlayer(OfflinePlayer offline) { for(String id : BukkitUtilities.getOfflinePlayerIdentifiers(offline)) resolutions.remove(id); } public synchronized void forgetPlayer(Player player) { for(String id : BukkitUtilities.getPlayerIdentifiers(player)) resolutions.remove(id); } public Set getDebuggers() { synchronized(debug) { return new HashSet<>(debug); } } public boolean isConsoleDebugging() { return isDebugging(rscp.getServer().getConsoleSender()); } public boolean isDebugging(CommandSender target) { synchronized(debug) { return debug.contains(target); } } public void setDebugging(CommandSender target, boolean value) { synchronized(debug) { if(value) debug.add(target); else debug.remove(target); } } }