新 ScoreboardAPI
支持 1.7-1.8 + 48字符串支持
This commit is contained in:
		
							
								
								
									
										251
									
								
								src/main/java/me/skymc/taboolib/scoreboard/SimpleScoreboard.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/main/java/me/skymc/taboolib/scoreboard/SimpleScoreboard.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
				
			|||||||
 | 
					package me.skymc.taboolib.scoreboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.base.Charsets;
 | 
				
			||||||
 | 
					import com.google.common.base.Splitter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.common.collect.Lists;
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.ChatColor;
 | 
				
			||||||
 | 
					import org.bukkit.OfflinePlayer;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
 | 
					import org.bukkit.scoreboard.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.reflect.Constructor;
 | 
				
			||||||
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentHashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class SimpleScoreboard {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static Map<String, OfflinePlayer> cache = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Scoreboard scoreboard;
 | 
				
			||||||
 | 
					    private String title;
 | 
				
			||||||
 | 
					    private Map<String, Integer> scores;
 | 
				
			||||||
 | 
					    private Objective obj;
 | 
				
			||||||
 | 
					    private List<Team> teams;
 | 
				
			||||||
 | 
					    private List<Integer> removed;
 | 
				
			||||||
 | 
					    private Set<String> updated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SimpleScoreboard(String title) {
 | 
				
			||||||
 | 
					        this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
 | 
				
			||||||
 | 
					        this.title = ChatColor.translateAlternateColorCodes('&', title);
 | 
				
			||||||
 | 
					        this.scores = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					        this.teams = Collections.synchronizedList(Lists.newArrayList());
 | 
				
			||||||
 | 
					        this.removed = Lists.newArrayList();
 | 
				
			||||||
 | 
					        this.updated = Collections.synchronizedSet(new HashSet<>());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void add(String text, Integer score) {
 | 
				
			||||||
 | 
					        text = ChatColor.translateAlternateColorCodes('&', text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (remove(score, text, false) || !scores.containsValue(score)) {
 | 
				
			||||||
 | 
					            updated.add(text);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scores.put(text, score);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean remove(Integer score, String text) {
 | 
				
			||||||
 | 
					        return remove(score, text, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean remove(Integer score, String n, boolean b) {
 | 
				
			||||||
 | 
					        String toRemove = get(score, n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (toRemove == null)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scores.remove(toRemove);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(b)
 | 
				
			||||||
 | 
					            removed.add(score);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String get(int score, String n) {
 | 
				
			||||||
 | 
					        String str = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
 | 
				
			||||||
 | 
					            if (entry.getValue().equals(score) &&
 | 
				
			||||||
 | 
					                    !entry.getKey().equals(n)) {
 | 
				
			||||||
 | 
					                str = entry.getKey();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Map.Entry<Team, OfflinePlayer> createTeam(String text, int pos) {
 | 
				
			||||||
 | 
					        Team team;
 | 
				
			||||||
 | 
					        ChatColor color = ChatColor.values()[pos];
 | 
				
			||||||
 | 
					        OfflinePlayer result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!cache.containsKey(color.toString()))
 | 
				
			||||||
 | 
					            cache.put(color.toString(), getOfflinePlayerSkipLookup(color.toString()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = cache.get(color.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            team = scoreboard.registerNewTeam("text-" + (teams.size() + 1));
 | 
				
			||||||
 | 
					        } catch (IllegalArgumentException e) {
 | 
				
			||||||
 | 
					            team = scoreboard.getTeam("text-" + (teams.size()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        applyText(team, text, result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        teams.add(team);
 | 
				
			||||||
 | 
					        return new AbstractMap.SimpleEntry<>(team, result);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void applyText(Team team, String text, OfflinePlayer result) {
 | 
				
			||||||
 | 
					        Iterator<String> iterator = Splitter.fixedLength(16).split(text).iterator();
 | 
				
			||||||
 | 
					        String prefix = iterator.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        team.setPrefix(prefix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!team.hasPlayer(result))
 | 
				
			||||||
 | 
					            team.addPlayer(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (text.length() > 16) {
 | 
				
			||||||
 | 
					            String prefixColor = ChatColor.getLastColors(prefix);
 | 
				
			||||||
 | 
					            String suffix = iterator.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (prefix.endsWith(String.valueOf(ChatColor.COLOR_CHAR))) {
 | 
				
			||||||
 | 
					                prefix = prefix.substring(0, prefix.length() - 1);
 | 
				
			||||||
 | 
					                team.setPrefix(prefix);
 | 
				
			||||||
 | 
					                prefixColor = ChatColor.getByChar(suffix.charAt(0)).toString();
 | 
				
			||||||
 | 
					                suffix = suffix.substring(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (prefixColor == null)
 | 
				
			||||||
 | 
					                prefixColor = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (suffix.length() > 16) {
 | 
				
			||||||
 | 
					                suffix = suffix.substring(0, (13 - prefixColor.length())); // cut off suffix, done if text is over 30 characters
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            team.setSuffix((prefixColor.equals("") ? ChatColor.RESET : prefixColor) + suffix);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void update() {
 | 
				
			||||||
 | 
					        if (updated.isEmpty()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (obj == null) {
 | 
				
			||||||
 | 
					            obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy");
 | 
				
			||||||
 | 
					            obj.setDisplayName(title);
 | 
				
			||||||
 | 
					            obj.setDisplaySlot(DisplaySlot.SIDEBAR);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        removed.stream().forEach((remove) -> {
 | 
				
			||||||
 | 
					            for (String s : scoreboard.getEntries()) {
 | 
				
			||||||
 | 
					                Score score = obj.getScore(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (score == null)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (score.getScore() != remove)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                scoreboard.resetScores(s);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        removed.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int index = scores.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (Map.Entry<String, Integer> text : scores.entrySet()) {
 | 
				
			||||||
 | 
					            Team t = scoreboard.getTeam(ChatColor.values()[text.getValue()].toString());
 | 
				
			||||||
 | 
					            Map.Entry<Team, OfflinePlayer> team;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!updated.contains(text.getKey())) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(t != null) {
 | 
				
			||||||
 | 
					                String color = ChatColor.values()[text.getValue()].toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!cache.containsKey(color)) {
 | 
				
			||||||
 | 
					                    cache.put(color, getOfflinePlayerSkipLookup(color));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                team = new AbstractMap.SimpleEntry<>(t, cache.get(color));
 | 
				
			||||||
 | 
					                applyText(team.getKey(), text.getKey(), team.getValue());
 | 
				
			||||||
 | 
					                index -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                team = createTeam(text.getKey(), text.getValue());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Integer score = text.getValue() != null ? text.getValue() : index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            obj.getScore(team.getValue()).setScore(score);
 | 
				
			||||||
 | 
					            index -= 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        updated.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setTitle(String title) {
 | 
				
			||||||
 | 
					        this.title = ChatColor.translateAlternateColorCodes('&', title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(obj != null)
 | 
				
			||||||
 | 
					            obj.setDisplayName(this.title);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void reset() {
 | 
				
			||||||
 | 
					        for (Team t : teams)
 | 
				
			||||||
 | 
					            t.unregister();
 | 
				
			||||||
 | 
					        teams.clear();
 | 
				
			||||||
 | 
					        scores.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Scoreboard getScoreboard() {
 | 
				
			||||||
 | 
					        return scoreboard;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void send(Player... players) {
 | 
				
			||||||
 | 
					        for (Player p : players)
 | 
				
			||||||
 | 
					            p.setScoreboard(scoreboard);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8));
 | 
				
			||||||
 | 
					    private Class<?> gameProfileClass;
 | 
				
			||||||
 | 
					    private Constructor<?> gameProfileConstructor;
 | 
				
			||||||
 | 
					    private Constructor<?> craftOfflinePlayerConstructor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @SuppressWarnings("deprecation")
 | 
				
			||||||
 | 
					    private OfflinePlayer getOfflinePlayerSkipLookup(String name) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (gameProfileConstructor == null) {
 | 
				
			||||||
 | 
					                try { // 1.7
 | 
				
			||||||
 | 
					                    gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile");
 | 
				
			||||||
 | 
					                } catch (ClassNotFoundException e) { // 1.8
 | 
				
			||||||
 | 
					                    gameProfileClass = Class.forName("com.mojang.authlib.GameProfile");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                gameProfileConstructor = gameProfileClass.getDeclaredConstructor(UUID.class, String.class);
 | 
				
			||||||
 | 
					                gameProfileConstructor.setAccessible(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (craftOfflinePlayerConstructor == null) {
 | 
				
			||||||
 | 
					                Class<?> serverClass = Bukkit.getServer().getClass();
 | 
				
			||||||
 | 
					                Class<?> craftOfflinePlayerClass = Class.forName(serverClass.getName()
 | 
				
			||||||
 | 
					                        .replace("CraftServer", "CraftOfflinePlayer"));
 | 
				
			||||||
 | 
					                craftOfflinePlayerConstructor = craftOfflinePlayerClass.getDeclaredConstructor(
 | 
				
			||||||
 | 
					                        serverClass, gameProfileClass
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                craftOfflinePlayerConstructor.setAccessible(true);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Object gameProfile = gameProfileConstructor.newInstance(invalidUserUUID, name);
 | 
				
			||||||
 | 
					            Object craftOfflinePlayer = craftOfflinePlayerConstructor.newInstance(Bukkit.getServer(), gameProfile);
 | 
				
			||||||
 | 
					            return (OfflinePlayer) craftOfflinePlayer;
 | 
				
			||||||
 | 
					        } catch (Throwable t) { // Fallback if fail
 | 
				
			||||||
 | 
					            return Bukkit.getOfflinePlayer(name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user