package com.gmail.nossr50.util.scoreboards;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.database.PlayerStat;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.player.PlayerProfile;
import com.gmail.nossr50.datatypes.skills.AbilityType;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.player.UserManager;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
public class ScoreboardManager {
static final Map<String, ScoreboardWrapper> PLAYER_SCOREBOARDS = new HashMap<String, ScoreboardWrapper>();
// do not localize; these are internal identifiers
static final String SIDEBAR_OBJECTIVE = "mcmmo_sidebar";
static final String POWER_OBJECTIVE = "mcmmo_pwrlvl";
static final String HEADER_STATS = LocaleLoader.getString("Scoreboard.Header.PlayerStats");
static final String HEADER_COOLDOWNS = LocaleLoader.getString("Scoreboard.Header.PlayerCooldowns");
static final String HEADER_RANK = LocaleLoader.getString("Scoreboard.Header.PlayerRank");
static final String TAG_POWER_LEVEL = LocaleLoader.getString("Scoreboard.Header.PowerLevel");
static final String POWER_LEVEL = LocaleLoader.getString("Scoreboard.Misc.PowerLevel");
static final String LABEL_POWER_LEVEL = POWER_LEVEL;
static final String LABEL_LEVEL = LocaleLoader.getString("Scoreboard.Misc.Level");
static final String LABEL_CURRENT_XP = LocaleLoader.getString("Scoreboard.Misc.CurrentXP");
static final String LABEL_REMAINING_XP = LocaleLoader.getString("Scoreboard.Misc.RemainingXP");
static final String LABEL_ABILITY_COOLDOWN = LocaleLoader.getString("Scoreboard.Misc.Cooldown");
static final String LABEL_OVERALL = LocaleLoader.getString("Scoreboard.Misc.Overall");
static final Map<SkillType, String> skillLabels;
static final Map<AbilityType, String> abilityLabelsColored;
static final Map<AbilityType, String> abilityLabelsSkill;
static {
ImmutableMap.Builder<SkillType, String> skillLabelBuilder = ImmutableMap.builder();
ImmutableMap.Builder<AbilityType, String> abilityLabelBuilder = ImmutableMap.builder();
ImmutableMap.Builder<AbilityType, String> abilityLabelSkillBuilder = ImmutableMap.builder();
if (Config.getInstance().getScoreboardRainbows()) {
// Everything but black, gray, gold
List<ChatColor> colors = Lists.newArrayList(
ChatColor.WHITE,
ChatColor.YELLOW,
ChatColor.LIGHT_PURPLE,
ChatColor.RED,
ChatColor.AQUA,
ChatColor.GREEN,
ChatColor.DARK_GRAY,
ChatColor.BLUE,
ChatColor.DARK_PURPLE,
ChatColor.DARK_RED,
ChatColor.DARK_AQUA,
ChatColor.DARK_GREEN,
ChatColor.DARK_BLUE);
Collections.shuffle(colors, Misc.getRandom());
int i = 0;
for (SkillType type : SkillType.values()) {
// Include child skills
skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getName(), false));
if (type.getAbility() != null) {
abilityLabelBuilder.put(type.getAbility(), getShortenedName(colors.get(i) + type.getAbility().getName()));
if (type == SkillType.MINING) {
abilityLabelBuilder.put(AbilityType.BLAST_MINING, getShortenedName(colors.get(i) + AbilityType.BLAST_MINING.getName()));
}
}
if (++i == colors.size()) {
i = 0;
}
}
}
else {
for (SkillType type : SkillType.values()) {
// Include child skills
skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getName()));
if (type.getAbility() != null) {
abilityLabelBuilder.put(type.getAbility(), getShortenedName(ChatColor.AQUA + type.getAbility().getName()));
if (type == SkillType.MINING) {
abilityLabelBuilder.put(AbilityType.BLAST_MINING, getShortenedName(ChatColor.AQUA + AbilityType.BLAST_MINING.getName()));
}
}
}
}
for (AbilityType type : AbilityType.values()) {
abilityLabelSkillBuilder.put(type, getShortenedName((type == AbilityType.BLAST_MINING ? ChatColor.BLUE : ChatColor.AQUA) + type.getName()));
}
skillLabels = skillLabelBuilder.build();
abilityLabelsColored = abilityLabelBuilder.build();
abilityLabelsSkill = abilityLabelSkillBuilder.build();
}
private static List<String> dirtyPowerLevels = new ArrayList<String>();
public enum SidebarType {
NONE,
SKILL_BOARD,
STATS_BOARD,
COOLDOWNS_BOARD,
RANK_BOARD,
TOP_BOARD;
}
private static String getShortenedName(String name) {
return getShortenedName(name, true);
}
private static String getShortenedName(String name, boolean useDots) {
if (name.length() > 16) {
name = useDots ? name.substring(0, 14) + ".." : name.substring(0, 16);
}
return name;
}
// **** Listener call-ins **** //
// Called by PlayerJoinEvent listener
public static void setupPlayer(Player player) {
PLAYER_SCOREBOARDS.put(player.getName(), ScoreboardWrapper.create(player));
dirtyPowerLevels.add(player.getName());
}
// Called by PlayerQuitEvent listener
public static void teardownPlayer(Player player) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.remove(player.getName());
if (wrapper != null && wrapper.revertTask != null) {
wrapper.revertTask.cancel();
}
}
// Called in onDisable()
public static void teardownAll() {
ImmutableList<Player> onlinePlayers = ImmutableList.copyOf(mcMMO.p.getServer().getOnlinePlayers());
mcMMO.p.debug("Tearing down scoreboards... (" + onlinePlayers.size() + ")");
for (Player player : onlinePlayers) {
teardownPlayer(player);
}
}
// Called by ScoreboardWrapper when its Player logs off and an action tries to be performed
public static void cleanup(ScoreboardWrapper wrapper) {
PLAYER_SCOREBOARDS.remove(wrapper.playerName);
if (wrapper.revertTask != null) {
wrapper.revertTask.cancel();
}
}
// Called by internal level-up event listener
public static void handleLevelUp(Player player, SkillType skill) {
// Selfboards
ScoreboardWrapper selfboardWrapper = PLAYER_SCOREBOARDS.get(player.getName());
if ((selfboardWrapper.isSkillScoreboard() && selfboardWrapper.targetSkill == skill) || (selfboardWrapper.isStatsScoreboard()) && selfboardWrapper.isBoardShown()) {
selfboardWrapper.doSidebarUpdateSoon();
}
// Otherboards
String playerName = player.getName();
for (ScoreboardWrapper wrapper : PLAYER_SCOREBOARDS.values()) {
if (wrapper.isStatsScoreboard() && playerName.equals(wrapper.targetPlayer) && selfboardWrapper.isBoardShown()) {
selfboardWrapper.doSidebarUpdateSoon();
}
}
if (Config.getInstance().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) {
dirtyPowerLevels.add(playerName);
}
if (Config.getInstance().getSkillLevelUpBoard()) {
enablePlayerSkillLevelUpScoreboard(player, skill);
}
}
// Called by internal xp event listener
public static void handleXp(Player player, SkillType skill) {
// Selfboards
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
if (wrapper != null && wrapper.isSkillScoreboard() && wrapper.targetSkill == skill && wrapper.isBoardShown()) {
wrapper.doSidebarUpdateSoon();
}
}
// Called by internal ability event listeners
public static void cooldownUpdate(Player player, SkillType skill) {
// Selfboards
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
if (wrapper != null && (wrapper.isCooldownScoreboard() || wrapper.isSkillScoreboard() && wrapper.targetSkill == skill) && wrapper.isBoardShown()) {
wrapper.doSidebarUpdateSoon();
}
}
// **** Setup methods **** //
public static void enablePlayerSkillScoreboard(Player player, SkillType skill) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeSkill(skill);
changeScoreboard(wrapper, Config.getInstance().getSkillScoreboardTime());
}
public static void enablePlayerSkillLevelUpScoreboard(Player player, SkillType skill) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
// Do NOT run if already shown
if (wrapper.isBoardShown()) {
return;
}
wrapper.setOldScoreboard();
wrapper.setTypeSkill(skill);
changeScoreboard(wrapper, Config.getInstance().getSkillLevelUpTime());
}
public static void enablePlayerStatsScoreboard(Player player) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeSelfStats();
changeScoreboard(wrapper, Config.getInstance().getStatsScoreboardTime());
}
public static void enablePlayerInspectScoreboard(Player player, PlayerProfile targetProfile) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeInspectStats(targetProfile);
changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime());
}
public static void enablePlayerCooldownScoreboard(Player player) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeCooldowns();
changeScoreboard(wrapper, Config.getInstance().getCooldownScoreboardTime());
}
public static void showPlayerRankScoreboard(Player player, Map<SkillType, Integer> rank) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeSelfRank();
wrapper.acceptRankData(rank);
changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime());
}
public static void showPlayerRankScoreboardOthers(Player player, String targetName, Map<SkillType, Integer> rank) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeInspectRank(targetName);
wrapper.acceptRankData(rank);
changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime());
}
public static void showTopScoreboard(Player player, SkillType skill, int pageNumber, List<PlayerStat> stats) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeTop(skill, pageNumber);
wrapper.acceptLeaderboardData(stats);
changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime());
}
public static void showTopPowerScoreboard(Player player, int pageNumber, List<PlayerStat> stats) {
ScoreboardWrapper wrapper = PLAYER_SCOREBOARDS.get(player.getName());
wrapper.setOldScoreboard();
wrapper.setTypeTopPower(pageNumber);
wrapper.acceptLeaderboardData(stats);
changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime());
}
// **** Helper methods **** //
/**
* @return false if power levels are disabled
*/
public static boolean powerLevelHeartbeat() {
Objective mainObjective = getPowerLevelObjective();
if (mainObjective == null) {
return false; // indicates
}
for (String playerName : dirtyPowerLevels) {
McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName);
if (mcMMOPlayer == null) {
continue;
}
Player player = mcMMOPlayer.getPlayer();
int power = mcMMOPlayer.getPowerLevel();
mainObjective.getScore(playerName).setScore(power);
for (ScoreboardWrapper wrapper : PLAYER_SCOREBOARDS.values()) {
wrapper.updatePowerLevel(player, power);
}
}
dirtyPowerLevels.clear();
return true;
}
/**
* Gets or creates the power level objective on the main scoreboard.
* <p/>
* If power levels are disabled, the objective is deleted and null is
* returned.
*
* @return the main scoreboard objective, or null if disabled
*/
public static Objective getPowerLevelObjective() {
if (!Config.getInstance().getPowerLevelTagsEnabled()) {
Objective objective = mcMMO.p.getServer().getScoreboardManager().getMainScoreboard().getObjective(POWER_OBJECTIVE);
if (objective != null) {
objective.unregister();
mcMMO.p.debug("Removed leftover scoreboard objects from Power Level Tags.");
}
return null;
}
Objective powerObjective = mcMMO.p.getServer().getScoreboardManager().getMainScoreboard().getObjective(POWER_OBJECTIVE);
if (powerObjective == null) {
powerObjective = mcMMO.p.getServer().getScoreboardManager().getMainScoreboard().registerNewObjective(POWER_OBJECTIVE, "dummy");
powerObjective.setDisplayName(TAG_POWER_LEVEL);
powerObjective.setDisplaySlot(DisplaySlot.BELOW_NAME);
}
return powerObjective;
}
private static void changeScoreboard(ScoreboardWrapper wrapper, int displayTime) {
if (displayTime == -1) {
wrapper.showBoardWithNoRevert();
}
else {
wrapper.showBoardAndScheduleRevert(displayTime * Misc.TICK_CONVERSION_FACTOR);
}
}
public static boolean isBoardShown(String playerName) {
return PLAYER_SCOREBOARDS.get(playerName).isBoardShown();
}
public static void clearBoard(String playerName) {
PLAYER_SCOREBOARDS.get(playerName).tryRevertBoard();
}
public static void keepBoard(String playerName) {
PLAYER_SCOREBOARDS.get(playerName).cancelRevert();
}
public static void setRevertTimer(String playerName, int seconds) {
PLAYER_SCOREBOARDS.get(playerName).showBoardAndScheduleRevert(seconds * Misc.TICK_CONVERSION_FACTOR);
}
}