From 50c9649b23852f2c6aac643f512c846be8262e1a Mon Sep 17 00:00:00 2001 From: GJ Date: Sat, 13 Apr 2013 23:16:25 -0400 Subject: [PATCH] mcMMO - Now with 100% more scoreboards! mcMMO now allows for the use of scoreboards to display information in several instances. By default, all scoreboards are enabled in the config, and will only display for 10 seconds. After 10 seconds, the scoreboard will go away and revert to the previously displayed scoreboard, if one exists. A global scoreboard now exists for tracking all player stats, and will be displayed when /mctop is used. Your name will be highlighted in gold when looking through the scoreboard. Additionally, the scoreboard will display players in groups of 15, rather than groups of 10 like in chat. Unfortunately, due to the limitations of scoreboards, the player's rank will not be displayed in front of their name. The scoreboard area is now also used for displaying data for /mcrank, /inspect. and /mcstats. Due to the way scoreboards are handled, the power level is not guarenteed to show up at any given location in the scoreboard, but is instead displayed in gold so that it can be easily found. Lastly, the scoreboard area is also now used for displaying current data on skills when the relevant / command is used. The effects and ability stats will still be shown in chat, but the current level, xp, and remaining xp will be shown in the scoreboard. --- Changelog.txt | 2 + .../commands/player/InspectCommand.java | 16 + .../commands/player/McrankCommand.java | 20 +- .../commands/player/McstatsCommand.java | 32 +- .../nossr50/commands/player/MctopCommand.java | 30 +- .../nossr50/commands/skills/SkillCommand.java | 11 +- .../java/com/gmail/nossr50/config/Config.java | 16 + .../database/FlatfileDatabaseManager.java | 31 +- .../datatypes/player/PlayerProfile.java | 19 ++ .../commands/McrankCommandDisplayTask.java | 2 +- .../commands/MctopCommandAsyncTask.java | 7 +- .../commands/MctopCommandDisplayTask.java | 17 +- .../scoreboards/ScoreboardChangeTask.java | 23 ++ .../util/scoreboards/ScoreboardManager.java | 312 ++++++++++++++++++ src/main/resources/config.yml | 28 ++ 15 files changed, 497 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/runnables/scoreboards/ScoreboardChangeTask.java create mode 100644 src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java diff --git a/Changelog.txt b/Changelog.txt index 8ffec4f87..bb5555621 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -8,6 +8,8 @@ Key: - Removal Version 1.4.06-dev + + Added global scoreboards to track skill rankings (display using /mctop) + + Added per-player scoreboard displays for the /inspect, /mcrank, /mcstats, and / commands + Added tab-complete support for all commands + Added ability to configure drops from Shake in treasures.yml + Added "Master Angler" ability to Fishing. diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index cfd78c4e5..b1b95628a 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -10,6 +10,7 @@ import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; +import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.SkillType; @@ -17,6 +18,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; @@ -25,6 +27,10 @@ public class InspectCommand implements TabExecutor { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { switch (args.length) { case 1: + if (sender instanceof Player && Config.getInstance().getInspectScoreboardEnabled()) { + ScoreboardManager.setupPlayerScoreboard(sender.getName()); + } + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(args[0]); // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. @@ -35,6 +41,11 @@ public class InspectCommand implements TabExecutor { return true; } + if (sender instanceof Player && Config.getInstance().getInspectScoreboardEnabled()) { + ScoreboardManager.enablePlayerInspectScoreboardOffline((Player) sender, profile); + return true; + } + sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", args[0])); sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering")); @@ -62,6 +73,11 @@ public class InspectCommand implements TabExecutor { return true; } + if (sender instanceof Player && Config.getInstance().getInspectScoreboardEnabled()) { + ScoreboardManager.enablePlayerInspectScoreboardOnline((Player) sender, mcMMOPlayer); + return true; + } + sender.sendMessage(LocaleLoader.getString("Inspect.Stats", target.getName())); CommandUtils.printGatheringSkills(target, sender); CommandUtils.printCombatSkills(target, sender); diff --git a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java index f007bda10..4ec06d233 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java @@ -7,15 +7,18 @@ import java.util.Set; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.runnables.commands.McrankCommandAsyncTask; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; public class McrankCommand implements TabExecutor { @@ -32,7 +35,14 @@ public class McrankCommand implements TabExecutor { return true; } - display(sender, sender.getName()); + if (Config.getInstance().getMcrankScoreboardEnabled()) { + ScoreboardManager.setupPlayerScoreboard(sender.getName()); + ScoreboardManager.enablePlayerRankScoreboard((Player) sender); + } + else { + display(sender, sender.getName()); + } + return true; case 1: @@ -55,7 +65,13 @@ public class McrankCommand implements TabExecutor { return true; } - display(sender, playerName); + if (sender instanceof Player && Config.getInstance().getMcrankScoreboardEnabled()) { + ScoreboardManager.setupPlayerScoreboard(sender.getName()); + ScoreboardManager.enablePlayerRankScoreboardOthers((Player) sender, playerName); + } + else { + display(sender, playerName); + } return true; default: diff --git a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java index eccca9189..8218e7aa3 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java @@ -12,7 +12,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; - +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; public class McstatsCommand implements TabExecutor { @@ -27,20 +27,26 @@ public class McstatsCommand implements TabExecutor { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(sender.getName()); Player player = mcMMOPlayer.getPlayer(); - player.sendMessage(LocaleLoader.getString("Stats.Own.Stats")); - player.sendMessage(LocaleLoader.getString("mcMMO.NoSkillNote")); - - CommandUtils.printGatheringSkills(player); - CommandUtils.printCombatSkills(player); - CommandUtils.printMiscSkills(player); - - int powerLevelCap = Config.getInstance().getPowerLevelCap(); - - if (powerLevelCap != Integer.MAX_VALUE) { - player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); + if (Config.getInstance().getMcstatsScoreboardsEnabled()) { + ScoreboardManager.setupPlayerScoreboard(player.getName()); + ScoreboardManager.enablePlayerStatsScoreboard(mcMMOPlayer); } else { - player.sendMessage(LocaleLoader.getString("Commands.PowerLevel", UserManager.getPlayer(player).getPowerLevel())); + player.sendMessage(LocaleLoader.getString("Stats.Own.Stats")); + player.sendMessage(LocaleLoader.getString("mcMMO.NoSkillNote")); + + CommandUtils.printGatheringSkills(player); + CommandUtils.printCombatSkills(player); + CommandUtils.printMiscSkills(player); + + int powerLevelCap = Config.getInstance().getPowerLevelCap(); + + if (powerLevelCap != Integer.MAX_VALUE) { + player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); + } + else { + player.sendMessage(LocaleLoader.getString("Commands.PowerLevel", UserManager.getPlayer(player).getPowerLevel())); + } } return true; diff --git a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java index 663912609..cc296cfca 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java @@ -7,17 +7,20 @@ import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.database.FlatfileDatabaseManager; +import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.skills.SkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.runnables.commands.MctopCommandAsyncTask; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.StringUtils; import com.gmail.nossr50.util.commands.CommandUtils; +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; @@ -77,11 +80,16 @@ public class MctopCommand implements TabExecutor { return; } - if (Config.getInstance().getUseMySQL()) { - sqlDisplay(page, skill, sender); + if (sender instanceof Player && Config.getInstance().getMctopScoreboardEnabled()) { + ScoreboardManager.enableGlobalStatsScoreboard((Player) sender, skill, page); } else { - flatfileDisplay(page, skill, sender); + if (Config.getInstance().getUseMySQL()) { + sqlDisplay(page, skill, sender); + } + else { + flatfileDisplay(page, skill, sender); + } } } @@ -97,21 +105,11 @@ public class MctopCommand implements TabExecutor { int position = (page * 10) - 9; - for (String playerStat : FlatfileDatabaseManager.retrieveInfo(skill, page)) { - if (playerStat == null) { - continue; - } - - String digit = String.valueOf(position); - - if (position < 10) { - digit = "0" + digit; - } - - String[] splitStat = playerStat.split(":"); + for (PlayerStat stat : FlatfileDatabaseManager.retrieveInfo(skill, page, 10)) { + String digit = (position < 10) ? "0" : "" + String.valueOf(position); // Format: 1. Playername - skill value - sender.sendMessage(digit + ". " + ChatColor.GREEN + splitStat[1] + " - " + ChatColor.WHITE + splitStat[0]); + sender.sendMessage(digit + ". " + ChatColor.GREEN + stat.name + " - " + ChatColor.WHITE + stat.statVal); position++; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 6635d68fb..9c68bf3a1 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -11,6 +11,7 @@ import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.SkillType; @@ -20,6 +21,7 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.StringUtils; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.SkillUtils; @@ -71,7 +73,14 @@ public abstract class SkillCommand implements TabExecutor { if (!skill.isChildSkill()) { player.sendMessage(LocaleLoader.getString("Skills.Header", skillName)); player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); - player.sendMessage(LocaleLoader.getString("Effects.Level", (int) skillValue, profile.getSkillXpLevel(skill), profile.getXpToLevel(skill))); + + if (Config.getInstance().getSkillScoreboardEnabled()) { + ScoreboardManager.setupPlayerScoreboard(player.getName()); + ScoreboardManager.enablePlayerSkillScoreboard(mcMMOPlayer, skill); + } + else { + player.sendMessage(LocaleLoader.getString("Effects.Level", (int) skillValue, profile.getSkillXpLevel(skill), profile.getXpToLevel(skill))); + } } else { player.sendMessage(LocaleLoader.getString("Skills.Header", skillName + " " + LocaleLoader.getString("Skills.Child"))); diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 1b6599e20..adf70a2fd 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -61,6 +61,22 @@ public class Config extends AutoUpdateConfigLoader { public int getMobHealthbarTime() { return config.getInt("Mob_Healthbar.Display_Time", 3); } + /* Scoreboards */ + public boolean getMcrankScoreboardEnabled() { return config.getBoolean("Scoreboards.Mcrank.Use", true); } + public int getMcrankScoreboardTime() { return config.getInt("Scoreboards.Mcrank.Display_Time", 10); } + + public boolean getMcstatsScoreboardsEnabled() { return config.getBoolean("Scoreboards.Mcstats.Use", true); } + public int getMcstatsScoreboardTime() { return config.getInt("Scoreboards.Mctop.Display_Time", 10); } + + public boolean getMctopScoreboardEnabled() { return config.getBoolean("Scoreboards.Mctop.Use", true); } + public int getMctopScoreboardTime() { return config.getInt("Scoreboards.Mctop.Display_Time", 10); } + + public boolean getInspectScoreboardEnabled() { return config.getBoolean("Scoreboards.Inspect.Use", true); } + public int getInspectScoreboardTime() { return config.getInt("Scoreboards.Inspect.Display_Time", 10); } + + public boolean getSkillScoreboardEnabled() { return config.getBoolean("Scoreboards.Skillname.Use", true); } + public int getSkillScoreboardTime() { return config.getInt("Scoreboards.Skillname.Display_Time", 10); } + /* Database Purging */ public int getPurgeInterval() { return config.getInt("Database_Purging.Purge_Interval", -1); } public int getOldUsersCutoff() { return config.getInt("Database_Purging.Old_User_Cutoff", 6); } diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index 1206ee713..0b0921e78 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -131,30 +131,11 @@ public final class FlatfileDatabaseManager { * @param pageNumber Which page in the leaderboards to retrieve * @return the requested leaderboard information */ - public static String[] retrieveInfo(String skillType, int pageNumber) { - String[] info = new String[10]; - List statsList; + public static List retrieveInfo(String skillType, int pageNumber, int statsPerPage) { + List statsList = skillType.equalsIgnoreCase("all") ? powerLevels : playerStatHash.get(SkillType.getSkill(skillType)); + int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage; - if (skillType.equalsIgnoreCase("all")) { - statsList = powerLevels; - } - else { - statsList = playerStatHash.get(SkillType.getSkill(skillType)); - } - - if (pageNumber < 1) { - pageNumber = 1; - } - int destination = (pageNumber - 1) * 10; - - for (int i = 0; i < 10; i++) { - if (destination + i < statsList.size()) { - PlayerStat ps = statsList.get(destination + i); - info[i] = ps.name + ":" + ps.statVal; - } - } - - return info; + return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); } public static boolean removeFlatFileUser(String playerName) { @@ -326,6 +307,10 @@ public final class FlatfileDatabaseManager { return skills; } + public static List getPlayerStats(String skillName) { + return (skillName.equalsIgnoreCase("all")) ? powerLevels : playerStatHash.get(SkillType.getSkill(skillName)); + } + private static int loadStat(List statList, String playerName, String[] data, int dataIndex) { if (data.length > dataIndex) { int statValue = Integer.parseInt(data[dataIndex]); diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index bb52dfc0a..1d07d713f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -9,6 +9,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.bukkit.scoreboard.Scoreboard; + import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.spout.SpoutConfig; @@ -30,6 +32,7 @@ public class PlayerProfile { private HudType hudType; private MobHealthbarType mobHealthbarType; private McMMOHud spoutHud; + private Scoreboard playerStatsScoreboard; /* Skill Data */ private final Map skills = new HashMap(); // Skill & Level @@ -70,6 +73,10 @@ public class PlayerProfile { } } + public String getPlayerName() { + return playerName; + } + public boolean isLoaded() { return loaded; } @@ -106,6 +113,18 @@ public class PlayerProfile { this.mobHealthbarType = mobHealthbarType; } + /* + * Scoreboards + */ + + public Scoreboard getPlayerStatsScoreboard() { + return playerStatsScoreboard; + } + + public void setPlayerStatsScoreboard(Scoreboard statsScoreboard) { + this.playerStatsScoreboard = statsScoreboard; + } + /* * Cooldowns */ diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 08cf68db3..d5c5053cc 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -32,7 +32,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable { sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); for (SkillType skill : SkillType.values()) { - if (skill.isChildSkill() || !Permissions.skillEnabled(player, skill)) { + if (skill.isChildSkill() || (player != null && !Permissions.skillEnabled(player, skill))) { continue; } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java index ad29b1abb..a74757a1b 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandAsyncTask.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.runnables.commands; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitRunnable; @@ -11,7 +11,6 @@ import com.gmail.nossr50.config.Config; import com.gmail.nossr50.database.SQLDatabaseManager; public class MctopCommandAsyncTask extends BukkitRunnable { - private CommandSender sender; private String query; private int page; @@ -25,8 +24,8 @@ public class MctopCommandAsyncTask extends BukkitRunnable { @Override public void run() { String tablePrefix = Config.getInstance().getMySQLTablePrefix(); - final HashMap> userslist = SQLDatabaseManager.read("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT " + ((page * 10) - 10) + ",10"); + final Collection> userStats = SQLDatabaseManager.read("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT " + ((page * 10) - 10) + ",10").values(); - new MctopCommandDisplayTask(userslist, page, tablePrefix, sender).runTaskLater(mcMMO.p, 1); + new MctopCommandDisplayTask(userStats, page, tablePrefix, sender).runTaskLater(mcMMO.p, 1); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index 472bb8e8b..d50eba990 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.runnables.commands; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -11,13 +11,13 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.StringUtils; public class MctopCommandDisplayTask extends BukkitRunnable { - private HashMap> userslist; + private Collection> userStats; private CommandSender sender; private String query; private int page; - public MctopCommandDisplayTask(HashMap> userslist, int page, String query, CommandSender sender) { - this.userslist = userslist; + public MctopCommandDisplayTask(Collection> userStats, int page, String query, CommandSender sender) { + this.userStats = userStats; this.page = page; this.query = query; this.sender = sender; @@ -33,13 +33,12 @@ public class MctopCommandDisplayTask extends BukkitRunnable { } int place = (page * 10) - 9; - for (int i = 1; i <= 10; i++) { - if (userslist.get(i) == null) { - break; - } + + for (ArrayList stat : userStats) { + String digit = (place < 10) ? "0" : "" + String.valueOf(place); // Format: 1. Playername - skill value - sender.sendMessage(place + ". " + ChatColor.GREEN + userslist.get(i).get(1) + " - " + ChatColor.WHITE + userslist.get(i).get(0)); + sender.sendMessage(digit + ". " + ChatColor.GREEN + stat.get(1) + " - " + ChatColor.WHITE + stat.get(0)); place++; } diff --git a/src/main/java/com/gmail/nossr50/runnables/scoreboards/ScoreboardChangeTask.java b/src/main/java/com/gmail/nossr50/runnables/scoreboards/ScoreboardChangeTask.java new file mode 100644 index 000000000..c24766114 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/runnables/scoreboards/ScoreboardChangeTask.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.runnables.scoreboards; + +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.Scoreboard; + +import com.gmail.nossr50.util.scoreboards.ScoreboardManager; + +public class ScoreboardChangeTask extends BukkitRunnable { + private Player player; + private Scoreboard oldScoreboard; + + public ScoreboardChangeTask(Player player, Scoreboard oldScoreboard) { + this.player = player; + this.oldScoreboard = oldScoreboard; + } + + @Override + public void run() { + player.setScoreboard(oldScoreboard); + ScoreboardManager.clearPendingTask(player.getName()); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java new file mode 100644 index 000000000..84b3a421f --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -0,0 +1,312 @@ +package com.gmail.nossr50.util.scoreboards; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Scoreboard; + +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.database.FlatfileDatabaseManager; +import com.gmail.nossr50.database.SQLDatabaseManager; +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.SkillType; +import com.gmail.nossr50.runnables.scoreboards.ScoreboardChangeTask; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.skills.SkillUtils; + +public class ScoreboardManager { + private static final Map PLAYER_SCOREBOARDS = new HashMap(); + private static final Scoreboard GLOBAL_STATS_SCOREBOARD = mcMMO.p.getServer().getScoreboardManager().getNewScoreboard(); + + private final static String PLAYER_STATS_HEADER = "mcMMO Stats"; + private final static String PLAYER_RANK_HEADER = "mcMMO Rankings"; + private final static String PLAYER_INSPECT_HEADER = "mcMMO Stats: "; + + private final static List SCOREBOARD_TASKS = new ArrayList(); + + public static void setupPlayerScoreboard(String playerName) { + if (PLAYER_SCOREBOARDS.containsKey(playerName)) { + return; + } + + PLAYER_SCOREBOARDS.put(playerName, mcMMO.p.getServer().getScoreboardManager().getNewScoreboard()); + } + + public static void enablePlayerSkillScoreboard(McMMOPlayer mcMMOPlayer, SkillType skill) { + Player player = mcMMOPlayer.getPlayer(); + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(SkillUtils.getSkillName(skill)); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(SkillUtils.getSkillName(skill), "dummy"); + } + + updatePlayerSkillScores(mcMMOPlayer.getProfile(), skill, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getSkillScoreboardTime()); + } + + public static void enablePlayerStatsScoreboard(McMMOPlayer mcMMOPlayer) { + Player player = mcMMOPlayer.getPlayer(); + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(PLAYER_STATS_HEADER); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(PLAYER_STATS_HEADER, "dummy"); + } + + updatePlayerStatsScores(mcMMOPlayer, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getMcstatsScoreboardTime()); + } + + public static void enablePlayerRankScoreboard(Player player) { + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(PLAYER_RANK_HEADER); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(PLAYER_RANK_HEADER, "dummy"); + } + + updatePlayerRankScores(player, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getMcrankScoreboardTime()); + } + + public static void enablePlayerRankScoreboardOthers(Player player, String targetName) { + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(PLAYER_RANK_HEADER); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(PLAYER_RANK_HEADER, "dummy"); + } + + updatePlayerRankOthersScores(targetName, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getMcrankScoreboardTime()); + } + + public static void enablePlayerInspectScoreboardOnline(Player player, McMMOPlayer mcMMOTarget) { + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(PLAYER_INSPECT_HEADER); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(PLAYER_INSPECT_HEADER, "dummy"); + } + + updatePlayerInspectOnlineScores(mcMMOTarget, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getInspectScoreboardTime()); + } + + public static void enablePlayerInspectScoreboardOffline(Player player, PlayerProfile targetProfile) { + Scoreboard oldScoreboard = player.getScoreboard(); + Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName()); + Objective objective = newScoreboard.getObjective(PLAYER_INSPECT_HEADER); + + if (objective == null) { + objective = newScoreboard.registerNewObjective(PLAYER_INSPECT_HEADER, "dummy"); + } + + updatePlayerInspectOfflineScores(targetProfile, objective); + changeScoreboard(player, oldScoreboard, newScoreboard, Config.getInstance().getInspectScoreboardTime()); + } + + public static void enableGlobalStatsScoreboard(Player player, String skillName, int pageNumber) { + Objective oldObjective = GLOBAL_STATS_SCOREBOARD.getObjective(skillName); + Scoreboard oldScoreboard = player.getScoreboard(); + + if (oldObjective != null) { + oldObjective.unregister(); + } + + Objective newObjective = GLOBAL_STATS_SCOREBOARD.registerNewObjective(skillName, "dummy"); + newObjective.setDisplayName(ChatColor.GOLD + (skillName.equalsIgnoreCase("all") ? "Power Level" : SkillUtils.getSkillName(SkillType.getSkill(skillName)))); + + updateGlobalStatsScores(player, newObjective, skillName, pageNumber); + changeScoreboard(player, oldScoreboard, GLOBAL_STATS_SCOREBOARD, Config.getInstance().getMctopScoreboardTime()); + } + + private static void updatePlayerSkillScores(PlayerProfile profile, SkillType skill, Objective objective) { + Server server = mcMMO.p.getServer(); + + objective.getScore(server.getOfflinePlayer("Level")).setScore(profile.getSkillLevel(skill)); + objective.getScore(server.getOfflinePlayer("Current XP")).setScore(profile.getSkillXpLevel(skill)); + objective.getScore(server.getOfflinePlayer("Remaining XP")).setScore(profile.getXpToLevel(skill)); + + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void updatePlayerStatsScores(McMMOPlayer mcMMOPlayer, Objective objective) { + Player player = mcMMOPlayer.getPlayer(); + PlayerProfile profile = mcMMOPlayer.getProfile(); + Server server = mcMMO.p.getServer(); + + for (SkillType skill : SkillType.values()) { + if (skill.isChildSkill() || !Permissions.skillEnabled(player, skill)) { + continue; + } + + objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(profile.getSkillLevel(skill)); + } + + objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + "Power Level")).setScore(mcMMOPlayer.getPowerLevel()); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void updatePlayerRankScores(Player player, Objective objective) { + String playerName = player.getName(); + Server server = mcMMO.p.getServer(); + Integer rank; + + Map skills = Config.getInstance().getUseMySQL() ? SQLDatabaseManager.readSQLRank(playerName) : FlatfileDatabaseManager.getPlayerRanks(playerName); + + for (SkillType skill : SkillType.values()) { + if (skill.isChildSkill() || !Permissions.skillEnabled(player, skill)) { + continue; + } + + rank = skills.get(skill.name()); + + if (rank != null) { + objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(rank); + } + } + + rank = skills.get("ALL"); + + if (rank != null) { + objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + "Overall")).setScore(rank); + } + + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void updatePlayerRankOthersScores(String targetName, Objective objective) { + Server server = mcMMO.p.getServer(); + Integer rank; + + Map skills = Config.getInstance().getUseMySQL() ? SQLDatabaseManager.readSQLRank(targetName) : FlatfileDatabaseManager.getPlayerRanks(targetName); + + for (SkillType skill : SkillType.values()) { + if (skill.isChildSkill()) { + continue; + } + + rank = skills.get(skill.name()); + + if (rank != null) { + objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(rank); + } + } + + rank = skills.get("ALL"); + + if (rank != null) { + objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + "Overall")).setScore(rank); + } + + objective.setDisplayName(PLAYER_RANK_HEADER + ": " + targetName); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void updatePlayerInspectOnlineScores(McMMOPlayer mcMMOTarget, Objective objective) { + Player target = mcMMOTarget.getPlayer(); + PlayerProfile profile = mcMMOTarget.getProfile(); + Server server = mcMMO.p.getServer(); + int powerLevel = 0; + int skillLevel; + + for (SkillType skill : SkillType.values()) { + if (skill.isChildSkill() || !Permissions.skillEnabled(target, skill)) { + continue; + } + + skillLevel = profile.getSkillLevel(skill); + objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(skillLevel); + powerLevel += skillLevel; + } + + objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + "Power Level")).setScore(powerLevel); + objective.setDisplayName(PLAYER_INSPECT_HEADER + target.getName()); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void updatePlayerInspectOfflineScores(PlayerProfile targetProfile, Objective objective) { + Server server = mcMMO.p.getServer(); + int powerLevel = 0; + int skillLevel; + + for (SkillType skill : SkillType.values()) { + if (skill.isChildSkill()) { + continue; + } + + skillLevel = targetProfile.getSkillLevel(skill); + objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(skillLevel); + powerLevel += skillLevel; + } + + objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + "Power Level")).setScore(powerLevel); + objective.setDisplayName(PLAYER_INSPECT_HEADER + targetProfile.getPlayerName()); + } + + private static void updateGlobalStatsScores(Player player, Objective objective, String skillName, int pageNumber) { + int position = (pageNumber * 15) - 14; + String startPosition = ((position < 10) ? "0" : "") + String.valueOf(position); + String endPosition = String.valueOf(position + 14); + Server server = mcMMO.p.getServer(); + + if (Config.getInstance().getUseMySQL()) { + String tablePrefix = Config.getInstance().getMySQLTablePrefix(); + String query = (skillName.equalsIgnoreCase("all") ? "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing" : skillName); + final Collection> userStats = SQLDatabaseManager.read("SELECT " + query + ", user, NOW() FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT " + ((pageNumber * 15) - 15) + ",15").values(); + + for (ArrayList stat : userStats) { + String playerName = stat.get(1); + playerName = (playerName.equals(player.getName()) ? ChatColor.GOLD : "") + playerName; + + objective.getScore(server.getOfflinePlayer(playerName)).setScore(Integer.valueOf(stat.get(0))); + } + } + else { + for (PlayerStat stat : FlatfileDatabaseManager.retrieveInfo(skillName, pageNumber, 15)) { + String playerName = stat.name; + playerName = (playerName.equals(player.getName()) ? ChatColor.GOLD : "") + playerName; + + objective.getScore(server.getOfflinePlayer(playerName)).setScore(stat.statVal); + } + } + + objective.setDisplayName(objective.getDisplayName() + " (" + startPosition + " - " + endPosition + ")"); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } + + private static void changeScoreboard(Player player, Scoreboard oldScoreboard, Scoreboard newScoreboard, int displayTime) { + if (oldScoreboard != newScoreboard) { + String playerName = player.getName(); + + player.setScoreboard(newScoreboard); + + if (displayTime != -1 && !SCOREBOARD_TASKS.contains(playerName)) { + new ScoreboardChangeTask(player, oldScoreboard).runTaskLater(mcMMO.p, displayTime * 20); + SCOREBOARD_TASKS.add(playerName); + } + } + } + + public static void clearPendingTask(String playerName) { + SCOREBOARD_TASKS.remove(playerName); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index f9a7e3e27..f287d0421 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -27,6 +27,34 @@ General: # Should mcMMO over-write configs to update, or make new ones ending in .new? Config_Update_Overwrite: true +Scoreboards: + Inspect: + # Should mcMMO use scoreboards for /inspect? + Use: true + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 10 + Mcrank: + # Should mcMMO use scoreboards for /mcrank? + Use: true + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 10 + Mcstats: + # Should mcMMO use scoreboards for /mcstats? + Use: true + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 10 + Mctop: + # Should mcMMO use scoreboards for /mctop? + Use: true + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 10 + Skillname: + # Should mcMMO use scoreboards for /skillname (/mining, /fishing, etc.)? + Use: true + # Amount of time (in seconds) to display. To display permanently, set to -1 + Display_Time: 10 + + Mob_Healthbar: # Default display for mob health bars - HEARTS, BAR, or DISABLED Display_Type: HEARTS