Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package somePackage;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.UUID;
- import org.bukkit.Bukkit;
- import org.bukkit.entity.Player;
- import org.bukkit.scoreboard.DisplaySlot;
- import org.bukkit.scoreboard.Objective;
- import org.bukkit.scoreboard.Team;
- public class Scoreboard {
- static {
- manager = new ScoreboardManager();
- }
- private static final ScoreboardManager manager;
- private static org.bukkit.scoreboard.Scoreboard board;
- private static Objective obj;
- /**
- * Returns the scoreboard manager
- * @return the scoreboard manager
- */
- public static ScoreboardManager getManager() {
- return manager;
- }
- private final String name;
- private List<String> lastUpdate = new ArrayList<>();
- private List<String> scores = new ArrayList<>();
- private String header;
- private Scoreboard(Player p) {
- name = p == null ? null : p.getName();
- if(p != null) {
- p.setScoreboard(board);
- header = p.getName();
- }
- }
- /**
- * Returns the scoreboard header of the player
- * @return the scoreboard header
- */
- public String getHeader() {
- return header;
- }
- /**
- * Sets the header
- * @param header the new header
- * @return the scoreboard instance, useful for chaining actions
- */
- public Scoreboard setHeader(String header) {
- this.header = header;
- return this;
- }
- /**
- * Returns the scoreboard's player
- * @return the scoreboard's player
- */
- @SuppressWarnings("deprecation")
- public Player getPlayer() {
- return Bukkit.getPlayer(name);
- }
- /**
- * Returns the scores
- * @return the scores, where the keys are the score names and the values their score value
- */
- public List<String> getScores() {
- return scores;
- }
- /**
- * Sets the scoreboard scores in descending order
- * @param scores the score names
- * @return the scoreboard instance
- */
- public Scoreboard setScores(List<String> scores) {
- this.scores = scores;
- return this;
- }
- /**
- * Sets the scoreboard scores in descending order, this method simply calls setScores(Arrays.asList(scores))
- * @param scores the score names
- * @return the scoreboard instance
- */
- public Scoreboard setScores(String... scores) {
- return setScores(Arrays.asList(scores));
- }
- /**
- * Updates the scoreboard with the current scores and header
- * @return the scoreboard instance
- */
- public Scoreboard update() {
- Player p = getPlayer();
- if(p == null) return this;
- if(scores.size() == lastUpdate.size()) {
- int size = scores.size() - 1;
- for(int i=0;i<=size;i++) {
- String entry = scores.get(i);
- String last = lastUpdate.get(i);
- if(!entry.equals(last)) {
- Object remove = manager.getRemovePacket(obj, last);
- Object add = manager.getChangePacket(obj, entry, size - i);
- ReflectUtil.sendPacket(p, remove, add);
- }
- }
- } else {
- for(int i=0;i<lastUpdate.size();i++) {
- Object packet = manager.getRemovePacket(obj, lastUpdate.get(i));
- ReflectUtil.sendPacket(p, packet);
- }
- int size = scores.size() - 1;
- for(int i=0;i<=size;i++) {
- Object packet = manager.getChangePacket(obj, scores.get(i), size-i);
- ReflectUtil.sendPacket(p, packet);
- }
- }
- try {
- Object packet = ReflectUtil.getNMSClass(NMSClass.PACKET_OBJECTIVE).newInstance();
- NMSClass clazz = NMSClass.ENUM_HEALTH_DISPLAY;
- String[] keys = "a, b, c, d".split(", ");
- Object[] values;
- if(clazz.name != null)
- values = new Object[] {
- "Board", header, ReflectUtil.getField(ReflectUtil.getNMSClass(clazz),
- null, "INTEGER"), 2};
- else values = new Object[] {"Board", header, 2};
- for(int i=0;i<keys.length;i++)
- ReflectUtil.setField(packet.getClass(), packet, keys[i], values[i]);
- ReflectUtil.sendPacket(p, packet);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- this.lastUpdate = scores;
- return this;
- }
- /**
- * Unregisters the scoreboard from the system
- */
- public void unregister() {
- Player p = getPlayer();
- if(p != null) {
- manager.boards.remove(p.getUniqueId());
- p.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
- }
- }
- public static class ScoreboardManager {
- private final Map<UUID, Scoreboard> boards;
- private ScoreboardManager() {
- boards = new HashMap<>();
- }
- /**
- * Sets a scoreboard up for the player, this is called in a join listener, use getScoreboard(Player) to get a player's board
- * @param p the player to set the board for
- * @return the newly created scoreboard instance
- */
- public Scoreboard setupBoard(Player p) {
- Scoreboard board = new Scoreboard(p);
- boards.put(p.getUniqueId(), board);
- return board;
- }
- /**
- * Returns the player's scoreboard
- * @param p the player's scoreboard
- * @return the scoreboard of the player
- */
- public Scoreboard getScoreboard(Player p) {
- return boards.get(p.getUniqueId());
- }
- /**
- * Gets the main scoreboard, use this to register/unregister/manipulate teams
- * @return
- */
- public org.bukkit.scoreboard.Scoreboard getScoreboard() {
- return board;
- }
- /**
- * Resets all teams
- */
- public void resetTeams() {
- //Converting it to an array because when unregistering a team, it gets removed from the board's teams list,
- //and even by calling Iterator#remove() it will throw a ConcurrentModificationException
- Team[] teams = board.getTeams().toArray(new Team[0]);
- for(Team team : teams) {
- team.unregister();
- }
- }
- private Object getChangePacket(Objective obj, String entry, int score) {
- try {
- Object packet = ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE).newInstance();
- NMSClass clazz = NMSClass.ENUM_ACTION;
- String[] keys = "a, b, c, d".split(", ");
- Object[] values;
- if(clazz.name != null)
- values = new Object[] {entry, obj.getName(), score,
- ReflectUtil.getField(ReflectUtil.getNMSClass(clazz),
- null, "CHANGE")};
- else values = new Object[] {entry, obj.getName(), score, 0};
- for(int i=0;i<keys.length;i++)
- ReflectUtil.setField(packet.getClass(), packet, keys[i], values[i]);
- return packet;
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- }
- private Object getRemovePacket(Objective obj, String entry) {
- Object handle = ReflectUtil.getHandle(obj);
- try {
- Class<?> objective = ReflectUtil.getNMSClassByName("ScoreboardObjective");
- if(ReflectUtil.isAbove("v1_8_R1"))
- return ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE)
- .getConstructor(String.class, objective)
- .newInstance(entry, handle);
- else {
- return ReflectUtil.getNMSClass(NMSClass.PACKET_SCORE)
- .getConstructor(String.class).newInstance(entry);
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- }
- public void start() {
- board = Bukkit.getScoreboardManager().getNewScoreboard();
- obj = board.registerNewObjective("Board", "dummy");
- obj.setDisplaySlot(DisplaySlot.SIDEBAR);
- }
- }
- private static enum NMSClass {
- PACKET_OBJECTIVE(new String[0], "PacketPlayOutScoreboardObjective"),
- ENUM_HEALTH_DISPLAY(new String[] {"v1_8_R1"}, null, "EnumScoreboardHealthDisplay"),
- PACKET_SCORE(new String[0], "PacketPlayOutScoreboardScore"),
- ENUM_ACTION(new String[] {"v1_8_R1"}, null, "EnumScoreboardAction");
- String name;
- NMSClass(String[] versions, String... s) {
- if(versions.length == 0)
- name = s[0];
- for(int i=versions.length - 1;i>=0;i--) {
- if(ReflectUtil.isAbove(versions[i]))
- name = s[i + 1];
- }
- }
- /*PacketPlayOutScoreboardObjective
- EnumScoreboardHealthDisplay
- PacketPlayOutScoreboardScore
- EnumScoreboardAction*/
- }
- private static class ReflectUtil {
- static final String CBK;
- static final boolean subclasses;
- static {
- String pkg = Bukkit.getServer().getClass().getPackage().getName();
- CBK = pkg.substring(pkg.lastIndexOf('.') + 1);
- subclasses = isAbove("v1_8_R2");
- }
- static boolean isAbove(String version) {
- String[] s0 = CBK.split("_");
- int i0 = Integer.parseInt(s0[0].substring(1));
- int j0 = Integer.parseInt(s0[1]);
- int k0 = Integer.parseInt(s0[2].substring(1));
- String[] s1 = version.split("_");
- int i1 = Integer.parseInt(s1[0].substring(1));
- int j1 = Integer.parseInt(s1[1]);
- int k1 = Integer.parseInt(s1[2].substring(1));
- return i0 > i1 ? true : i0 == i1 ? (j0 > j1 ? true : j0 == j1 ? k0 >= k1 : false) : false;
- }
- static Class<?> getNMSClassByName(String name) {
- if(subclasses){
- //From v1_8_R2, some classes have become subclasses
- if(name.equals("EnumScoreboardAction"))
- name = "PacketPlayOutScoreboardScore$" + name;
- else if(name.equals("EnumScoreboardHealthDisplay"))
- name = "IScoreboardCriteria$" + name;
- }
- try {
- return Class.forName("net.minecraft.server." + CBK + "." + name);
- } catch (ClassNotFoundException ex) {
- ex.printStackTrace();
- return null;
- }
- }
- static Class<?> getNMSClass(NMSClass clazz) {
- return getNMSClassByName(clazz.name);
- }
- static Object getField(Class<?> clazz, Object instance, String field) {
- try {
- Field f = clazz.getDeclaredField(field);
- f.setAccessible(true);
- return f.get(instance);
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- }
- static void setField(Class<?> clazz, Object instance, String field, Object value) {
- try {
- Field f = clazz.getDeclaredField(field);
- f.setAccessible(true);
- f.set(instance, value);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- static Object getHandle(Object obj) {
- try {
- return obj.getClass().getMethod("getHandle").invoke(obj);
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
- }
- static void sendPacket(Player p, Object... packets) {
- try {
- Object handle = getHandle(p);
- Object connection = handle.getClass().getDeclaredField("playerConnection").get(handle);
- Method send = connection.getClass().getDeclaredMethod("sendPacket", getNMSClassByName("Packet"));
- for(Object packet : packets)
- send.invoke(connection, packet);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement