Created
October 15, 2014 23:25
-
-
Save TigerHix/a9d774b541300089c5af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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