Advertisement
megamichiel

ScoreboardManager

Jul 11th, 2015
1,954
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package somePackage;
  2.  
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.UUID;
  11.  
  12. import org.bukkit.Bukkit;
  13. import org.bukkit.entity.Player;
  14. import org.bukkit.scoreboard.DisplaySlot;
  15. import org.bukkit.scoreboard.Objective;
  16. import org.bukkit.scoreboard.Team;
  17.  
  18. public class Scoreboard {
  19.  
  20.         static {
  21.                 manager = new ScoreboardManager();
  22.         }
  23.        
  24.         private static final ScoreboardManager manager;
  25.         private static org.bukkit.scoreboard.Scoreboard board;
  26.         private static Objective obj;
  27.        
  28.         /**
  29.          * Returns the scoreboard manager
  30.          * @return the scoreboard manager
  31.          */
  32.         public static ScoreboardManager getManager() {
  33.                 return manager;
  34.         }
  35.        
  36.         private final String name;
  37.         private List<String> lastUpdate = new ArrayList<>();
  38.         private List<String> scores = new ArrayList<>();
  39.         private String header;
  40.        
  41.         private Scoreboard(Player p) {
  42.                 name = p == null ? null : p.getName();
  43.                 if(p != null) {
  44.                         p.setScoreboard(board);
  45.                         header = p.getName();
  46.                 }
  47.         }
  48.        
  49.         /**
  50.          * Returns the scoreboard header of the player
  51.          * @return the scoreboard header
  52.          */
  53.         public String getHeader() {
  54.                 return header;
  55.         }
  56.        
  57.         /**
  58.          * Sets the header
  59.          * @param header the new header
  60.          * @return the scoreboard instance, useful for chaining actions
  61.          */
  62.         public Scoreboard setHeader(String header) {
  63.                 this.header = header;
  64.                 return this;
  65.         }
  66.        
  67.         /**
  68.          * Returns the scoreboard's player
  69.          * @return the scoreboard's player
  70.          */
  71.         @SuppressWarnings("deprecation")
  72.         public Player getPlayer() {
  73.                 return Bukkit.getPlayer(name);
  74.         }
  75.        
  76.         /**
  77.          * Returns the scores
  78.          * @return the scores, where the keys are the score names and the values their score value
  79.          */
  80.         public List<String> getScores() {
  81.                 return scores;
  82.         }
  83.        
  84.         /**
  85.          * Sets the scoreboard scores in descending order
  86.          * @param scores the score names
  87.          * @return the scoreboard instance
  88.          */
  89.         public Scoreboard setScores(List<String> scores) {
  90.                 this.scores = new ArrayList<String>(scores);
  91.                 return this;
  92.         }
  93.        
  94.         /**
  95.          * Sets the scoreboard scores in descending order, this method simply calls setScores(Arrays.asList(scores))
  96.          * @param scores the score names
  97.          * @return the scoreboard instance
  98.          */
  99.         public Scoreboard setScores(String... scores) {
  100.                 return setScores(Arrays.asList(scores));
  101.         }
  102.        
  103.         /**
  104.          * Updates the scoreboard with the current scores and header
  105.          * @return the scoreboard instance
  106.          */
  107.         public Scoreboard update() {
  108.                 Player p = getPlayer();
  109.                 if(p == null) return this;
  110.                 if(scores.size() == lastUpdate.size()) {
  111.                         int size = scores.size() - 1;
  112.                         for(int i=0;i<=size;i++) {
  113.                                 String entry = scores.get(i);
  114.                                 String last = lastUpdate.get(i);
  115.                                 if(!entry.equals(last)) {
  116.                                         Object remove = manager.getRemovePacket(obj, last);
  117.                                         Object add = manager.getChangePacket(obj, entry, size - i);
  118.                                         ReflectUtil.sendPacket(p, remove, add);
  119.                                 }
  120.                         }
  121.                 } else {
  122.                         for(int i=0;i<lastUpdate.size();i++) {
  123.                                 Object packet = manager.getRemovePacket(obj, lastUpdate.get(i));
  124.                                 ReflectUtil.sendPacket(p, packet);
  125.                         }
  126.                         int size = scores.size() - 1;
  127.                         for(int i=0;i<=size;i++) {
  128.                                 Object packet = manager.getChangePacket(obj, scores.get(i), size-i);
  129.                                 ReflectUtil.sendPacket(p, packet);
  130.                         }
  131.                 }
  132.                 try {
  133.                         Object packet = ReflectUtil.getNMSClass(NMSClass.PACKET_OBJECTIVE).newInstance();
  134.                         NMSClass clazz = NMSClass.ENUM_HEALTH_DISPLAY;
  135.                        
  136.                         String[] keys = "a, b, c, d".split(", ");
  137.                         Object[] values;
  138.                         if(clazz.name != null)
  139.                             values = new Object[] {
  140.                                 "Board", header, ReflectUtil.getField(ReflectUtil.getNMSClass(clazz),
  141.                                         null, "INTEGER"), 2};
  142.                         else values = new Object[] {"Board", header, 2};
  143.                         for(int i=0;i<values.length;i++)
  144.                                 ReflectUtil.setField(packet.getClass(), packet, keys[i], values[i]);
  145.                         ReflectUtil.sendPacket(p, packet);
  146.                 } catch (Exception ex) {
  147.                         ex.printStackTrace();
  148.                 }
  149.                 this.lastUpdate = new ArrayList<String>(scores);
  150.                 return this;
  151.         }
  152.        
  153.         /**
  154.          * Unregisters the scoreboard from the system
  155.          */
  156.         public void unregister() {
  157.                 Player p = getPlayer();
  158.                 if(p != null) {
  159.                         manager.boards.remove(p.getUniqueId());
  160.                         p.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
  161.                 }
  162.         }
  163.        
  164.         public static class ScoreboardManager {
  165.                
  166.                 private final Map<UUID, Scoreboard> boards;
  167.                
  168.                 private ScoreboardManager() {
  169.                         boards = new HashMap<>();
  170.                 }
  171.                
  172.                 /**
  173.                  * Sets a scoreboard up for the player, this should be called in a join listener, use getScoreboard(Player) to get a player's board
  174.                  * @param p the player to set the board for
  175.                  * @return the newly created scoreboard instance
  176.                  */
  177.                 public Scoreboard setupBoard(Player p) {
  178.                         Scoreboard board = new Scoreboard(p);
  179.                         boards.put(p.getUniqueId(), board);
  180.                         return board;
  181.                 }
  182.                
  183.                 /**
  184.                  * Returns the player's scoreboard
  185.                  * @param p the player's scoreboard
  186.                  * @return the scoreboard of the player
  187.                  */
  188.                 public Scoreboard getScoreboard(Player p) {
  189.                         return boards.get(p.getUniqueId());
  190.                 }
  191.                
  192.                 /**
  193.                  * Gets the main scoreboard, use this to register/unregister/manipulate teams
  194.                  * @return
  195.                  */
  196.                 public org.bukkit.scoreboard.Scoreboard getScoreboard() {
  197.                         return board;
  198.                 }
  199.                
  200.                 /**
  201.                  * Resets all teams
  202.                  */
  203.                 public void resetTeams() {
  204.                         //Converting it to an array because when unregistering a team, it gets removed from the board's teams list,
  205.                         //and even by calling Iterator#remove() it will throw a ConcurrentModificationException
  206.                         Team[] teams = board.getTeams().toArray(new Team[0]);
  207.                         for(Team team : teams) {
  208.                                 team.unregister();
  209.                         }
  210.                 }
  211.                
  212.                 private Object getChangePacket(Objective obj, String entry, int score) {
  213.                         try {
  214.                                 Object packet = ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE).newInstance();
  215.                                 NMSClass clazz = NMSClass.ENUM_ACTION;
  216.                                 String[] keys = "a, b, c, d".split(", ");
  217.                                 Object[] values;
  218.                                 if(clazz.name != null)
  219.                                     values = new Object[] {entry, obj.getName(), score,
  220.                                             ReflectUtil.getField(ReflectUtil.getNMSClass(clazz),
  221.                                                             null, "CHANGE")};
  222.                                 else values = new Object[] {entry, obj.getName(), score, 0};
  223.                                 for(int i=0;i<keys.length;i++)
  224.                                         ReflectUtil.setField(packet.getClass(), packet, keys[i], values[i]);
  225.                                 return packet;
  226.                         } catch (Exception ex) {
  227.                                 ex.printStackTrace();
  228.                                 return null;
  229.                         }
  230.                 }
  231.                
  232.                 private Object getRemovePacket(Objective obj, String entry) {
  233.                         Object handle = ReflectUtil.getHandle(obj);
  234.                         try {
  235.                             Class<?> objective = ReflectUtil.getNMSClassByName("ScoreboardObjective");
  236.                             if(ReflectUtil.isAbove("v1_8_R1"))
  237.                                 return ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE)
  238.                                                 .getConstructor(String.class, objective)
  239.                                                 .newInstance(entry, handle);
  240.                             else {
  241.                                 return ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE)
  242.                                         .getConstructor(String.class).newInstance(entry);
  243.                             }
  244.                         } catch (Exception ex) {
  245.                                 ex.printStackTrace();
  246.                                 return null;
  247.                         }
  248.                 }
  249.                
  250.                 public void start() {
  251.                         board = Bukkit.getScoreboardManager().getNewScoreboard();
  252.                         obj = board.registerNewObjective("Board", "dummy");
  253.                         obj.setDisplaySlot(DisplaySlot.SIDEBAR);
  254.                 }
  255.         }
  256.        
  257.         private static enum NMSClass {
  258.            
  259.             PACKET_OBJECTIVE(new String[0], "PacketPlayOutScoreboardObjective"),
  260.             ENUM_HEALTH_DISPLAY(new String[] {"v1_8_R1"}, null, "EnumScoreboardHealthDisplay"),
  261.             PACKET_SCORE(new String[0], "PacketPlayOutScoreboardScore"),
  262.             ENUM_ACTION(new String[] {"v1_8_R1"}, null, "EnumScoreboardAction");
  263.            
  264.             String name;
  265.            
  266.             NMSClass(String[] versions, String... s) {
  267.                 if(versions.length == 0)
  268.                     name = s[0];
  269.                 for(int i=versions.length - 1;i>=0;i--) {
  270.                     if(ReflectUtil.isAbove(versions[i]))
  271.                         name = s[i + 1];
  272.                 }
  273.             }
  274.             /*PacketPlayOutScoreboardObjective
  275.             EnumScoreboardHealthDisplay
  276.             PacketPlayOutScoreboardScore
  277.             EnumScoreboardAction*/
  278.         }
  279.        
  280.         private static class ReflectUtil {
  281.                
  282.                 static final String CBK;
  283.                 static final boolean subclasses;
  284.                
  285.                 static {
  286.                         String pkg = Bukkit.getServer().getClass().getPackage().getName();
  287.                         CBK = pkg.substring(pkg.lastIndexOf('.') + 1);
  288.                         subclasses = isAbove("v1_8_R2");
  289.                 }
  290.                
  291.                 static boolean isAbove(String version) {
  292.                     String[] s0 = CBK.split("_");
  293.                     int i0 = Integer.parseInt(s0[0].substring(1));
  294.                     int j0 = Integer.parseInt(s0[1]);
  295.                     int k0 = Integer.parseInt(s0[2].substring(1));
  296.  
  297.                     String[] s1 = version.split("_");
  298.                    
  299.                     int i1 = Integer.parseInt(s1[0].substring(1));
  300.                     int j1 = Integer.parseInt(s1[1]);
  301.                     int k1 = Integer.parseInt(s1[2].substring(1));
  302.                     return i0 > i1 ? true : i0 == i1 ? (j0 > j1 ? true : j0 == j1 ? k0 >= k1  : false) : false;
  303.                 }
  304.                
  305.                 static Class<?> getNMSClassByName(String name) {
  306.                         if(subclasses){
  307.                                 //From v1_8_R2, some classes have become subclasses
  308.                                 if(name.equals("EnumScoreboardAction"))
  309.                                         name = "PacketPlayOutScoreboardScore$" + name;
  310.                                 else if(name.equals("EnumScoreboardHealthDisplay"))
  311.                                         name = "IScoreboardCriteria$" + name;
  312.                         }
  313.                         try {
  314.                                 return Class.forName("net.minecraft.server." + CBK + "." + name);
  315.                         } catch (ClassNotFoundException ex) {
  316.                                 ex.printStackTrace();
  317.                                 return null;
  318.                         }
  319.                 }
  320.                
  321.                 static Class<?> getNMSClass(NMSClass clazz) {
  322.                     return getNMSClassByName(clazz.name);
  323.                 }
  324.                
  325.                 static Object getField(Class<?> clazz, Object instance, String field) {
  326.                         try {
  327.                                 Field f = clazz.getDeclaredField(field);
  328.                                 f.setAccessible(true);
  329.                                 return f.get(instance);
  330.                         } catch (Exception ex) {
  331.                                 ex.printStackTrace();
  332.                                 return null;
  333.                         }
  334.                 }
  335.                
  336.                 static void setField(Class<?> clazz, Object instance, String field, Object value) {
  337.                         try {
  338.                                 Field f = clazz.getDeclaredField(field);
  339.                                 f.setAccessible(true);
  340.                                 f.set(instance, value);
  341.                         } catch (Exception ex) {
  342.                                 ex.printStackTrace();
  343.                         }
  344.                 }
  345.                
  346.                 static Object getHandle(Object obj) {
  347.                         try {
  348.                                 return obj.getClass().getMethod("getHandle").invoke(obj);
  349.                         } catch (Exception ex) {
  350.                                 ex.printStackTrace();
  351.                                 return null;
  352.                         }
  353.                 }
  354.                
  355.                 static void sendPacket(Player p, Object... packets) {
  356.                         try {
  357.                                 Object handle = getHandle(p);
  358.                                 Object connection = handle.getClass().getDeclaredField("playerConnection").get(handle);
  359.                                 Method send = connection.getClass().getDeclaredMethod("sendPacket", getNMSClassByName("Packet"));
  360.                                 for(Object packet : packets)
  361.                                         send.invoke(connection, packet);
  362.                         } catch (Exception ex) {
  363.                                 ex.printStackTrace();
  364.                         }
  365.                 }
  366.         }
  367. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement