-
-
Save mkotb/d99eccdcc78a43ffb707 to your computer and use it in GitHub Desktop.
| 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); | |
| } | |
| } | |
| } |
you suck ducks
ok
It doesn't work on Java 7.
Amazing class! Thank you.
Small bug: Line 195 should read "obj.setDisplayName(this.title);"
@M44rtenz Java 7 doesn't have streams. Idek why you're using Java 7, that's outdated now.
Mine is still flickering 1.8 - 1.9 Any fixes? The community needs this.
This is how I am making my scoreboard and it flickers:
`public void hubScoreboard(Player p) {
new BukkitRunnable() {
final ColorScrollPlus cs = new ColorScrollPlus(ChatColor.WHITE, "VenomSurge", "§a", "§f", "§a", true, false,
ScrollType.FORWARD);
ScoreboardAPI scoreboard;
public void run() {
if (cs.getScrollType() == ScrollType.FORWARD) {
if (cs.getPosition() >= cs.getString().length()) {
cs.setScrollType(ScrollType.BACKWARD);
}
} else {
if (cs.getPosition() <= -1) {
cs.setScrollType(ScrollType.FORWARD);
}
}
scoreboard = new ScoreboardAPI(cs.next());
scoreboard.add(C.dgray + C.bold + C.strike + "---------------", 7);
if (plugin.permPlug.getRank(p).equals(RankType.OWNER)) {
scoreboard.add(C.white + "Rank: " + RankUtil.Owner, 6);
} else if (plugin.permPlug.getRank(p).equals(RankType.ADMIN)) {
scoreboard.add(C.white + "Rank: " + RankUtil.Admin, 6);
} else if (plugin.permPlug.getRank(p).equals(RankType.MOD)) {
scoreboard.add(C.white + "Rank: " + RankUtil.Mod, 6);
} else if (plugin.permPlug.getRank(p).equals(RankType.HELPER)) {
scoreboard.add(C.white + "Rank: " + RankUtil.Helper, 6);
} else if (plugin.permPlug.getRank(p).equals(RankType.MEMBER)) {
scoreboard.add(C.white + "Rank: " + C.yellow + C.bold + "MEMBER", 6);
}
scoreboard.add(C.white + "Votes: " + C.green + "0", 5);
scoreboard.add(" ", 4);
scoreboard.add(C.white + "Lobby: " + C.green + "#1", 3);
scoreboard.add(C.white + "Online: " + C.green + Bukkit.getOnlinePlayers().size(), 2);
scoreboard.add(C.dgray + C.bold + C.strike + "---------------", 1);
scoreboard.update();
scoreboard.send(p);
}
}.runTaskTimer(plugin, 0, 3);
}`
It doesn't work for multiple players, right? (I mean if someone has e.g. 200 Coins and then the scoreboard updates for a player with 500 coins, player 1 & 2 have 500 coins in the scoreboard)
I'm not getting update:
@eventhandler
public void wow(PlayerJoinEvent e) {
SimpleScoreboard ss = new SimpleScoreboard("WoW");
ss.add("Money: "+ a, 13);
ss.update();
ss.send(e.getPlayer());
new BukkitRunnable() {
@Override
public void run() {
a = new Random().nextInt(900);
ss.update();
for (Player p : Bukkit.getServer().getOnlinePlayers()) {
ss.update();
ss.send(p);
}
}
}.runTaskTimerAsynchronously(this, 20, 10);
It works perfect on 1.8, thanks a lot 👍
I just wrote some new code in it ;)
Anyway I can get this to work for 1.7 with 40 lines I'm guessing using suffix and prefix?
nice credit 😢