Advertisement
Guest User

ScoreboardManager

a guest
Jul 9th, 2015
26
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.70 KB | None | 0 0
  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 = 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<keys.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 = 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 is 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