/** * bRanks 1.2-SNAPSHOT * Copyright (C) 2013 CodingBadgers <plugins@mcbadgercraft.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package uk.codingbadgers.branks; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.ScoreboardManager; import org.bukkit.scoreboard.Team; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.mcsg.double0negative.tabapi.TabAPI; import ru.tehkode.permissions.PermissionEntity; import ru.tehkode.permissions.PermissionGroup; import ru.tehkode.permissions.bukkit.PermissionsEx; import ru.tehkode.permissions.events.PermissionEntityEvent; import ru.tehkode.permissions.events.PermissionEntityEvent.Action; import uk.codingbadgers.bFundamentals.bFundamentals; import uk.codingbadgers.bFundamentals.module.Module; public class bRanks extends Module implements Listener, PluginMessageListener { // TeamName and Team private HashMap<String, Team> m_rankScorboards = new HashMap<String, Team>(); // Player Name and List Name private HashMap<String, String> m_allPlayers = new HashMap<String, String>(); // The maximum length a players name can be private final int m_maxNameLength = 12; // Timer for update loop private int m_updateLoopTimerID = -1; // The update loop time delay private final Long m_updateTimeRate = 100L; // Require a tab update if true private boolean m_requireUpdate = true; /** * Called when the module is disabled. */ public void onDisable() { Bukkit.getScheduler().cancelTask(m_updateLoopTimerID); for (Player player : Bukkit.getOnlinePlayers()) { TabAPI.clearTab(player); } for (Team team : m_rankScorboards.values()) { team.unregister(); } m_rankScorboards.clear(); m_allPlayers.clear(); Messenger messanger = Bukkit.getServer().getMessenger(); messanger.unregisterOutgoingPluginChannel(m_plugin); messanger.unregisterIncomingPluginChannel(m_plugin); } /** * Called when the module is loaded. */ public void onEnable() { register(this); Messenger messanger = Bukkit.getServer().getMessenger(); messanger.registerOutgoingPluginChannel(m_plugin, "BungeeCord"); messanger.registerIncomingPluginChannel(m_plugin, "BungeeCord", this); m_allPlayers.clear(); HashMap<String, String> rankMap = loadRankMappings(); // Create a scoreboard for each rank ScoreboardManager manager = Bukkit.getScoreboardManager(); Scoreboard mainScoreboard = manager.getMainScoreboard(); for (String group : this.getPermissions().getGroups()) { String prefix; if (rankMap != null && rankMap.containsKey(group)) prefix = rankMap.get(group); else prefix = bFundamentals.getChat().getGroupPrefix((String)null, group); Team team = mainScoreboard.getTeam(group); if (team == null) { team = mainScoreboard.registerNewTeam(group); } prefix = ChatColor.translateAlternateColorCodes('&', prefix); prefix = prefix.length() > 16 ? ChatColor.stripColor(prefix) : prefix; prefix = prefix.length() > 16 ? prefix.substring(0, 15) : prefix; team.setPrefix(prefix); m_rankScorboards.put(group, team); } Player[] onlinePlayers = Bukkit.getOnlinePlayers(); for (Player player : onlinePlayers) { addPlayerToTeam(player, false); } // If citizens is installed, enable the listener and update all npcs if (Bukkit.getPluginManager().getPlugin("Citizens") != null) { this.register(new NpcListener(this)); for (NPC npc : CitizensAPI.getNPCRegistry()) { if (npc.getEntity() == null || npc.getEntity().getType() != EntityType.PLAYER) continue; Player player = (Player)npc.getEntity(); addPlayerToTeam(player, true); } } if (onlinePlayers.length != 0) { requestAllPlayers(onlinePlayers[0]); } updateTabList(); doUpdateLoop(); } private void doUpdateLoop() { m_updateLoopTimerID = Bukkit.getScheduler().scheduleSyncRepeatingTask(m_plugin, new Runnable() { @Override public void run() { if (Bukkit.getOnlinePlayers().length != 0) { requestAllPlayers(Bukkit.getOnlinePlayers()[0]); } } }, m_updateTimeRate, m_updateTimeRate); } /** * Load the rank mappings from the ranks config file */ private HashMap<String, String> loadRankMappings() { File rankMapFile = new File(this.getDataFolder() + File.separator + "ranks.json"); if (!rankMapFile.exists()) { try { rankMapFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } return null; } String jsonContents = ""; try { BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(rankMapFile))); String inputLine; while ((inputLine = in.readLine()) != null) { jsonContents += inputLine; } in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } JSONObject rankJSON = (JSONObject)JSONValue.parse(jsonContents); HashMap<String, String> rankMap = new HashMap<String, String>(); for (String group : this.getPermissions().getGroups()) { String nickname = (String)rankJSON.get(group); if (nickname == null) continue; rankMap.put(group, nickname); } return rankMap; } /** * Called when a player joins */ @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { m_requireUpdate = true; final Player player = event.getPlayer(); final String playerName = player.getPlayerListName(); if (playerName.length() > m_maxNameLength) { player.setPlayerListName(playerName.substring(0, m_maxNameLength)); } addPlayerToTeam(player, false); requestAllPlayers(player); broadcastTabUpdate(player, 20L); } /** * Called when a player leaves */ @EventHandler(priority = EventPriority.LOW) public void onPlayerLeave(PlayerQuitEvent event) { final Player player = event.getPlayer(); m_allPlayers.remove(player.getName()); updateTabList(); broadcastTabUpdate(player, 0L); } /** * Called when a player is kicked */ @EventHandler(priority = EventPriority.LOW) public void onPlayerKicked(PlayerKickEvent event) { final Player player = event.getPlayer(); m_allPlayers.remove(player.getName()); updateTabList(); broadcastTabUpdate(player, 0L); } /** * Called when a players rank changes */ @EventHandler public void onRankChange(PermissionEntityEvent event) { if (event.getAction() != Action.INHERITANCE_CHANGED) return; PermissionEntity entity = event.getEntity(); Player player = Bukkit.getPlayer(entity.getName()); if (player == null) return; addPlayerToTeam(player, false); broadcastTabUpdate(player, 20L); } /** * Add a given player to a team based upon their pex rank */ public void addPlayerToTeam(Player player, boolean isNPC) { final String rank = this.getPermissions().getPrimaryGroup(player); Team team = m_rankScorboards.get(rank); if (team != null) { team.addPlayer(Bukkit.getOfflinePlayer(player.getPlayerListName())); if (!isNPC) { m_allPlayers.put(player.getName(), player.getPlayerListName()); updateTabList(); } } } /** * Request a list of all players on the bungee network */ private void requestAllPlayers(final Player player) { Bukkit.getScheduler().scheduleSyncDelayedTask(m_plugin, new Runnable() { @Override public void run() { ByteArrayOutputStream b = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(b); try { out.writeUTF("PlayerList"); out.writeUTF("ALL"); player.sendPluginMessage(m_plugin, "BungeeCord", b.toByteArray()); } catch(Exception ex) {} } }, 20L); } /** * Broadcast a tab update across the bungee network */ private void broadcastTabUpdate(final Player player, Long delay) { Bukkit.getScheduler().scheduleSyncDelayedTask(m_plugin, new Runnable() { @Override public void run() { ByteArrayOutputStream b = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(b); try { out.writeUTF("Forward"); out.writeUTF("ALL"); out.writeUTF("UpdateTab"); ByteArrayOutputStream msgbytes = new ByteArrayOutputStream(); DataOutputStream msgout = new DataOutputStream(msgbytes); msgout.writeUTF("SexyLemons"); out.writeShort(msgbytes.toByteArray().length); out.write(msgbytes.toByteArray()); player.sendPluginMessage(m_plugin, "BungeeCord", b.toByteArray()); } catch(Exception ex) {} } }, delay); } /** * Called when a plugin message is received */ @Override public void onPluginMessageReceived(String channel, Player player, byte[] message) { if (!channel.equals("BungeeCord")) { return; } try { DataInputStream in = new DataInputStream(new ByteArrayInputStream(message)); String subchannel = in.readUTF(); if (subchannel.equalsIgnoreCase("PlayerList")) { in.readUTF(); // The name of the server you got the player list of, as given in args. ArrayList<String> playerList = new ArrayList<String>(); String[] playerArray = in.readUTF().split(", "); for (String playerName : playerArray) { playerList.add(playerName); } HashMap<String, String> oldPlayerList = new HashMap<String, String>(); oldPlayerList.putAll(m_allPlayers); for (String playerName : oldPlayerList.keySet()) { if (!playerList.contains(playerName)) { m_allPlayers.remove(playerName); m_requireUpdate = true; } } for (String playerName : playerList) { if (m_allPlayers.containsKey(playerName)) continue; m_requireUpdate = true; final String rank = this.getPermissions().getPrimaryGroup((String)null, playerName); Team team = m_rankScorboards.get(rank); if (team != null) { String listName = playerName; if (listName.length() > m_maxNameLength) { listName = listName.substring(0, m_maxNameLength); } team.addPlayer(Bukkit.getOfflinePlayer(listName)); m_allPlayers.put(playerName, listName); } } updateTabList(); } else if (subchannel.equalsIgnoreCase("UpdateTab")) { Bukkit.getScheduler().scheduleSyncDelayedTask(m_plugin, new Runnable() { @Override public void run() { if (Bukkit.getOnlinePlayers().length != 0) { requestAllPlayers(Bukkit.getOnlinePlayers()[0]); } } }, 20L); } } catch(Exception ex) {} } /** * Update the tab list for all players online */ private void updateTabList() { if (!m_requireUpdate) return; for (Player player : Bukkit.getOnlinePlayers()) { updateTabList(player.getName()); } m_requireUpdate = false; } /** * Update the tablist for a given player */ private void updateTabList(final String playerToUpdateName) { Bukkit.getScheduler().scheduleSyncDelayedTask(m_plugin, new Runnable() { @Override public void run() { Player player = Bukkit.getPlayer(playerToUpdateName); if (player == null) return; TabAPI.setPriority(m_plugin, player, 2); TabAPI.clearTab(player); TabAPI.setTabString(m_plugin, player, 0, 0, ChatColor.GOLD + "||============"); TabAPI.setTabString(m_plugin, player, 0, 1, ChatColor.GOLD + Bukkit.getServerName()); TabAPI.setTabString(m_plugin, player, 0, 2, ChatColor.GOLD + "============||"); int x = 0; int y = 2; SortedMap<Integer, PermissionGroup> pexRanks = new TreeMap<Integer, PermissionGroup>(); pexRanks.putAll(PermissionsEx.getPermissionManager().getRankLadder("default")); for (PermissionGroup group : pexRanks.values()) { Team team = m_rankScorboards.get(group.getName()); if (team != null) { Set<OfflinePlayer> teamPlayers = team.getPlayers(); for (OfflinePlayer teamPlayer : teamPlayers) { if (!m_allPlayers.containsValue(teamPlayer.getName())) continue; TabAPI.setTabString(m_plugin, player, y, x, teamPlayer.getName()); x++; if (x >= 3) { y++; x = 0; } } /*if (teamPlayers.size() != 0 && x != 0) { y++; x = 0; }*/ } } TabAPI.updatePlayer(player); } }, 20L); } }