Skip to content

Instantly share code, notes, and snippets.

@TigerHix
Created October 15, 2014 23:25
Show Gist options
  • Save TigerHix/a9d774b541300089c5af to your computer and use it in GitHub Desktop.
Save TigerHix/a9d774b541300089c5af to your computer and use it in GitHub Desktop.
package com.tigerhix.framework.game.board;
import com.google.common.base.Splitter;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.tigerhix.framework.game.soul.Profile;
import com.tigerhix.framework.util.enums.Messenger;
import com.tigerhix.framework.util.model.FakeOfflinePlayer;
import com.tigerhix.framework.util.model.task.Task;
import org.apache.commons.lang.RandomStringUtils;
import org.bukkit.Bukkit;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Represents an advanced scoreboard for a player, which can shows up to 48 characters in a single entry.
* <p/>
* Extend this class to add more functions. An example would be {@link com.tigerhix.framework.game.board.HubBoard}, which shows the amount of token of a player on the scoreboard.
*
* @author TigerHix
*/
public abstract class Board {
protected Profile profile;
private Scoreboard scoreboard;
private Objective objective;
protected long refreshTicks = 10L;
/**
* This HashMap stores already-added scoreboard entries, to avoid flickering of the scoreboard.
*/
private ConcurrentHashMap<String, Integer> addedEntries = new ConcurrentHashMap<>();
private Table<Team, String, String> teams = HashBasedTable.create();
private Task task;
public Board(Profile profile) {
this.profile = profile;
// Setup scoreboard
scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
scoreboard.registerNewObjective("board", "dummy").setDisplaySlot(DisplaySlot.SIDEBAR);
objective = scoreboard.getObjective(DisplaySlot.SIDEBAR);
}
/**
* Register the board.
*/
public void register() {
// Set scoreboard
profile.getPlayer().setScoreboard(scoreboard);
// Refresh scoreboard every .5 seconds
task = new Task() {
@Override
public void run() {
update();
}
}.repeat(refreshTicks, true);
}
/**
* Unregister the board.
*/
public void unregister() {
if (profile.getPlayer() != null) {
synchronized (this) {
profile.getPlayer().setScoreboard((Bukkit.getScoreboardManager().getMainScoreboard()));
}
}
for (Team team : teams.rowKeySet()) {
team.unregister();
}
task.cancel();
}
/**
* Intended for overriding by subclasses, to dynamically getAttribute the title of the scoreboard.
*
* @return title
*/
protected abstract String getTitle();
/**
* Intended for overriding by subclasses, to dynamically getAttribute entries of the scoreboard.
*
* @return entries
*/
protected abstract ConcurrentHashMap<String, Integer> getEntries();
/**
* Update the board.
*/
@SuppressWarnings("deprecation")
private void update() {
if (!profile.isOnline()) {
unregister();
return;
}
// Title
String title = Messenger.format(getTitle());
if (!objective.getDisplayName().equals(title)) objective.setDisplayName(Messenger.format(title));
// Entries
ConcurrentHashMap<String, Integer> data = getEntries();
HashMap<String, Integer> added = new HashMap<>();
HashMap<String, Integer> modified = new HashMap<>();
for (String string : data.keySet()) modified.put(Messenger.format(string), data.get(string)); // Colorize
for (String key : modified.keySet()) {
Integer score = modified.get(key);
while (added.containsKey(key)) key += Messenger.format("&r ");
if (key.length() > 48) key = key.substring(0, 47);
if (addedEntries.containsKey(key) && addedEntries.get(key).equals(score)) {
continue;
}
added.put(key, score);
addedEntries.put(key, score);
Map.Entry<Team, String> team = createTeam(key);
FakeOfflinePlayer player = new FakeOfflinePlayer(team.getValue());
if (team.getKey() != null) team.getKey().addPlayer(player);
objective.getScore(player).setScore(score);
}
for (String key : addedEntries.keySet()) {
if (!modified.containsKey(key) || !modified.get(key).equals(addedEntries.get(key))) {
if (key.length() <= 16) scoreboard.resetScores(key);
else {
Iterator<String> iterator = Splitter.fixedLength(16).split(key).iterator();
iterator.next();
scoreboard.resetScores(iterator.next());
}
addedEntries.remove(key); // Remove no-longer-exists data
}
}
}
/**
* The trick of 48 characters.
*
* @param text team name
* @return entries
*/
private Map.Entry<Team, String> createTeam(String text) {
String result;
if (text.length() <= 16) return new AbstractMap.SimpleEntry<>(null, text);
String prefix;
String suffix = "";
Iterator<String> iterator = Splitter.fixedLength(16).split(text).iterator();
prefix = iterator.next();
result = iterator.next();
if (text.length() > 32) suffix = iterator.next();
for (Team team : teams.rowKeySet()) {
if (team.getPrefix().equals(prefix) && team.getSuffix().equals(suffix))
return new AbstractMap.SimpleEntry<>(team, result);
}
Team team = scoreboard.registerNewTeam("board_" + RandomStringUtils.randomAlphanumeric(10));
team.setPrefix(prefix);
team.setSuffix(suffix);
teams.put(team, prefix, suffix);
return new AbstractMap.SimpleEntry<>(team, result);
}
/**
* Return the board's target soul.
*
* @return soul
*/
public Profile getProfile() {
return profile;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment