diff --git a/pom.xml b/pom.xml
index 3007989..d71520b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
org.spigotmc
spigot-api
- 1.18-R0.1-SNAPSHOT
+ 1.18.2-R0.1-SNAPSHOT
provided
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java
index d15d36a..e1e95a0 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/Main.java
@@ -3,6 +3,7 @@ package com.gmail.artemis.the.gr8.playerstats;
import com.gmail.artemis.the.gr8.playerstats.commands.ReloadCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.StatCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.TabCompleter;
+import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.listeners.JoinListener;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
@@ -14,17 +15,16 @@ public class Main extends JavaPlugin {
@Override
public void onEnable() {
-
ConfigHandler config = new ConfigHandler(this);
- EnumHandler enumHandler = new EnumHandler();
-
+ EnumHandler enumHandler = new EnumHandler(this);
OutputFormatter outputFormatter = new OutputFormatter(config);
- StatManager statManager = new StatManager(enumHandler, this);
- this.getCommand("statistic").setExecutor(new StatCommand(outputFormatter, statManager, this));
- this.getCommand("statistic").setTabCompleter(new TabCompleter(
- enumHandler, statManager,this));
- this.getCommand("statisticreload").setExecutor(new ReloadCommand(config, outputFormatter));
+ //prepare private hashMap of offline players
+ OfflinePlayerHandler.updateOfflinePlayers();
+
+ this.getCommand("statistic").setExecutor(new StatCommand(outputFormatter, enumHandler, this));
+ this.getCommand("statistic").setTabCompleter(new TabCompleter(enumHandler, this));
+ this.getCommand("statisticreload").setExecutor(new ReloadCommand(config, outputFormatter, this));
Bukkit.getPluginManager().registerEvents(new JoinListener(), this);
this.getLogger().info("Enabled PlayerStats!");
@@ -35,14 +35,8 @@ public class Main extends JavaPlugin {
this.getLogger().info("Disabled PlayerStats!");
}
-
- public void logStatRelatedExceptions(Exception exception) {
- if (exception instanceof IllegalArgumentException) {
- getLogger().warning("IllegalArgumentException - this is probably not a valid statistic name!");
- }
- else if (exception instanceof NullPointerException) {
- getLogger().warning("NullPointerException - no statistic name was provided");
- }
+ public long logTimeTaken(String className, String methodName, long previousTime, int lineNumber) {
+ getLogger().info(className + " " + methodName + " " + lineNumber + ": " + (System.currentTimeMillis() - previousTime));
+ return System.currentTimeMillis();
}
-
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java
deleted file mode 100644
index 70f4fd0..0000000
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.gmail.artemis.the.gr8.playerstats;
-
-import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
-import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
-import org.bukkit.Material;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.Statistic;
-import org.bukkit.entity.EntityType;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class StatManager {
-
- private final Main plugin;
- private final EnumHandler enumHandler;
- private final OfflinePlayerHandler offlinePlayerHandler;
- private final List statNames;
- private final List entityStatNames;
- private final List subStatEntryNames;
-
- public StatManager(EnumHandler e, Main p) {
- plugin = p;
- enumHandler = e;
- offlinePlayerHandler = OfflinePlayerHandler.getInstance();
-
- statNames = Arrays.stream(Statistic.values()).map(
- Statistic::toString).map(String::toLowerCase).toList();
- entityStatNames = Arrays.stream(Statistic.values()).filter(statistic ->
- statistic.getType().equals(Statistic.Type.ENTITY)).map(
- Statistic::toString).map(String::toLowerCase).collect(Collectors.toList());
-
- subStatEntryNames = new ArrayList<>();
- subStatEntryNames.addAll(enumHandler.getBlockNames());
- subStatEntryNames.addAll(enumHandler.getEntityTypeNames());
- subStatEntryNames.addAll(enumHandler.getItemNames());
- }
-
- public int getStatistic(String statName, String playerName) throws IllegalArgumentException, NullPointerException {
- return getStatistic(statName, null, playerName);
- }
-
- //returns the integer associated with a certain statistic for a player
- public int getStatistic(String statName, String subStatEntryName, String playerName) throws IllegalArgumentException, NullPointerException {
- long time = System.currentTimeMillis();
-
- OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(playerName);
-
- plugin.getLogger().info("StatManager 51: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- if (player == null) throw new NullPointerException("No player called " + playerName + " was found!");
-
- Statistic stat = getStatistic(statName);
- plugin.getLogger().info("StatManager 56: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
-
- if (stat != null) {
- switch (stat.getType()) {
- case UNTYPED -> {
- plugin.getLogger().info("StatManager 62: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- return player.getStatistic(stat);
- }
- case BLOCK -> {
- plugin.getLogger().info("StatManager 67: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- Material block = enumHandler.getBlock(subStatEntryName);
- if (block == null) throw new NullPointerException(subStatEntryName + " is not a valid block name!");
- return player.getStatistic(stat, block);
- }
- case ENTITY -> {
- plugin.getLogger().info("StatManager 74: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- EntityType entity = enumHandler.getEntityType(subStatEntryName);
- if (entity == null) throw new NullPointerException(subStatEntryName + " is not a valid entity name!");
- return player.getStatistic(stat, entity);
- }
- case ITEM -> {
- plugin.getLogger().info("StatManager 81: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- Material item = enumHandler.getItem(subStatEntryName);
- if (item == null) throw new NullPointerException(subStatEntryName + " is not a valid item name!");
- return player.getStatistic(stat, item);
- }
- }
- }
- throw new NullPointerException(statName + " is not a valid statistic name!");
- }
-
- //returns the statistic enum constant, or null if non-existent (param: statName, not case sensitive)
- private Statistic getStatistic(String statName) {
- try {
- return Statistic.valueOf(statName.toUpperCase());
- }
- catch (IllegalArgumentException | NullPointerException exception) {
- plugin.logStatRelatedExceptions(exception);
- return null;
- }
- }
-
- //gets the type of the statistic from the string, otherwise returns null (param: statName, not case sensitive)
- public Statistic.Type getStatType(String statName) {
- try {
- return Statistic.valueOf(statName.toUpperCase()).getType();
- }
- catch (IllegalArgumentException | NullPointerException exception) {
- plugin.logStatRelatedExceptions(exception);
- return null;
- }
- }
-
- //checks if string is a valid statistic (param: statName, not case sensitive)
- public boolean isStatistic(String statName) {
- return statNames.contains(statName.toLowerCase());
- }
-
- //checks if string is a valid substatistic dealing with entities (param: statName, not case sensitive)
- public boolean isStatEntityType(String statName) {
- return entityStatNames.contains(statName.toLowerCase());
- }
-
- //checks in the most general sense if this statistic is a substatistic (param: statName, not case sensitive)
- public boolean isSubStatEntry(String statName) {
- return subStatEntryNames.contains(statName.toLowerCase());
- }
-
- //checks whether a subStatEntry is of the type that the statistic requires
- public boolean isMatchingSubStatEntry(String statName, String subStatEntry) {
- Statistic.Type type = getStatType(statName);
- if (type != null && subStatEntry != null) {
- switch (type) {
- case ENTITY -> {
- return enumHandler.isEntityType(subStatEntry);
- }
- case ITEM -> {
- return enumHandler.isItem(subStatEntry);
- }
- case BLOCK -> {
- return enumHandler.isBlock(subStatEntry);
- }
- case UNTYPED -> {
- return false;
- }
- }
- }
- return false;
- }
-
- //returns the names of all general statistics in lowercase
- public List getStatNames() {
- return statNames;
- }
-
- //returns all statistics that have type entities, in lowercase
- public List getEntityTypeNames() {
- return entityStatNames;
- }
-
- //returns all substatnames in lowercase
- public List getSubStatEntryNames() {
- return subStatEntryNames;
- }
-}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatRequest.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatRequest.java
new file mode 100644
index 0000000..64731da
--- /dev/null
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatRequest.java
@@ -0,0 +1,67 @@
+package com.gmail.artemis.the.gr8.playerstats;
+
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+public class StatRequest {
+
+ private final CommandSender sender;
+ private String statName;
+ private String subStatEntry;
+ private String playerName;
+ private boolean playerFlag;
+ private boolean topFlag;
+
+ //playerFlag and topFlag are false by default, will be set to true if "player" or "top" is in the args
+ public StatRequest(@NotNull CommandSender s) {
+ sender = s;
+ playerFlag = false;
+ topFlag = false;
+ }
+
+ public CommandSender getCommandSender() {
+ return sender;
+ }
+
+ public String getStatName() {
+ return statName;
+ }
+
+ public void setStatName(String statName) {
+ this.statName = statName;
+ }
+
+ public String getSubStatEntry() {
+ return subStatEntry;
+ }
+
+ public void setSubStatEntry(String subStatEntry) {
+ this.subStatEntry = subStatEntry;
+ }
+
+ public String getPlayerName() {
+ return playerName;
+ }
+
+ public void setPlayerName(String playerName) {
+ this.playerName = playerName;
+ }
+
+ //the "player" arg in the statCommand is a special case, because it could either be a valid subStatEntry, or indicate that the lookup action should target a specific player
+ //this is why the playerFlag exists - if this is true, and playerName is null, subStatEntry will be "player"
+ public boolean playerFlag() {
+ return playerFlag;
+ }
+
+ public void setPlayerFlag(boolean playerFlag) {
+ this.playerFlag = playerFlag;
+ }
+
+ public boolean topFlag() {
+ return topFlag;
+ }
+
+ public void setTopFlag(boolean topFlag) {
+ this.topFlag = topFlag;
+ }
+}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatThread.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatThread.java
new file mode 100644
index 0000000..822b02b
--- /dev/null
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatThread.java
@@ -0,0 +1,154 @@
+package com.gmail.artemis.the.gr8.playerstats;
+
+import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
+import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
+import com.gmail.artemis.the.gr8.playerstats.utils.OutputFormatter;
+import org.bukkit.Material;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.Statistic;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.EntityType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class StatThread extends Thread {
+
+ private final StatRequest request;
+ private final EnumHandler enumHandler;
+ private final OutputFormatter outputFormatter;
+ private final Main plugin;
+ private String className = "StatThread";
+
+ //constructor (called on thread creation)
+ public StatThread(StatRequest s, EnumHandler e, OutputFormatter o, Main p) {
+ request = s;
+
+ enumHandler = e;
+ outputFormatter = o;
+ plugin = p;
+ }
+
+ //what the thread will do once started
+ @Override
+ public void run() throws IllegalStateException, NullPointerException {
+ long time = System.currentTimeMillis();
+
+ if (outputFormatter == null || plugin == null) {
+ throw new IllegalStateException("Not all classes off the plugin are running!");
+ }
+ if (request == null) {
+ throw new NullPointerException("No statistic request was found!");
+ }
+
+ CommandSender sender = request.getCommandSender();
+ String playerName = request.getPlayerName();
+ String statName = request.getStatName();
+ String subStatEntry = request.getSubStatEntry();
+ boolean topFlag = request.topFlag();
+
+ if (playerName != null) {
+ try {
+ sender.sendMessage(
+ outputFormatter.formatPlayerStat(
+ playerName, statName, subStatEntry, getStatistic(
+ statName, subStatEntry, playerName)));
+ plugin.logTimeTaken(className, "run(): individual stat", time, 60);
+
+ } catch (Exception e) {
+ sender.sendMessage(outputFormatter.formatExceptions(e.toString()));
+ }
+
+ } else if (topFlag) {
+ try {
+ LinkedHashMap topStats = getTopStatistics(statName, subStatEntry);
+ plugin.logTimeTaken(className, "run(): for each loop", time, 69);
+
+ String top = outputFormatter.formatTopStats(topStats, statName, subStatEntry);
+ sender.sendMessage(top);
+ plugin.logTimeTaken(className, "run(): format output", time, 73);
+
+ } catch (Exception e) {
+ sender.sendMessage(outputFormatter.formatExceptions(e.toString()));
+ e.printStackTrace();
+ }
+ }
+ }
+
+ //returns the integer associated with a certain statistic for a player
+ private int getStatistic(String statName, String subStatEntryName, String playerName) throws IllegalArgumentException, NullPointerException {
+ OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName);
+ if (player != null) {
+ Statistic stat = enumHandler.getStatEnum(statName);
+ if (stat != null) {
+ return getPlayerStat(player, stat, subStatEntryName);
+ }
+ throw new IllegalArgumentException("Statistic " + statName + " could not be retrieved!");
+ }
+ throw new IllegalArgumentException("Player object for " + playerName + " could not be retrieved!");
+ }
+
+ private LinkedHashMap getTopStatistics(String statName, String subStatEntry) {
+ Statistic stat = enumHandler.getStatEnum(statName);
+
+ if (stat != null) {
+ HashMap playerStats = new HashMap<>((int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05));
+ OfflinePlayerHandler.getAllOfflinePlayerNames().forEach(playerName -> {
+ OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName);
+ if (player != null)
+ try {
+ int statistic = getPlayerStat(player, stat, subStatEntry);
+ if (statistic > 0) {
+ playerStats.put(playerName, statistic);
+ }
+ } catch (IllegalArgumentException ignored) {
+ }
+ });
+ return playerStats.entrySet().stream()
+ .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
+ .limit(10).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
+ }
+ throw new NullPointerException("Statistic " + statName + " could not be retrieved!");
+ }
+
+ private int getPlayerStat(@NotNull OfflinePlayer player, @NotNull Statistic stat, String subStatEntryName) throws IllegalArgumentException {
+ switch (stat.getType()) {
+ case UNTYPED -> {
+ return player.getStatistic(stat);
+ }
+ case BLOCK -> {
+ Material block = enumHandler.getBlock(subStatEntryName);
+ if (block != null) {
+ return player.getStatistic(stat, block);
+ }
+ else {
+ throw new IllegalArgumentException(subStatEntryName + " is not a valid block name!");
+ }
+ }
+ case ENTITY -> {
+ EntityType entity = enumHandler.getEntityType(subStatEntryName);
+ if (entity != null) {
+ return player.getStatistic(stat, entity);
+ }
+ else {
+ throw new IllegalArgumentException(subStatEntryName + " is not a valid entity name!");
+ }
+ }
+ case ITEM -> {
+ Material item = enumHandler.getItem(subStatEntryName);
+ if (item != null) {
+ return player.getStatistic(stat, item);
+ }
+ else {
+ throw new IllegalArgumentException(subStatEntryName + " is not a valid item name!");
+ }
+ }
+ default ->
+ throw new IllegalArgumentException("This statistic does not seem to be of type:untyped/block/entity/item, I think we should panic");
+ }
+ }
+}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java
index 2702d55..96d2400 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/ReloadCommand.java
@@ -1,6 +1,8 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
-import com.gmail.artemis.the.gr8.playerstats.ConfigHandler;
+import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
+import com.gmail.artemis.the.gr8.playerstats.Main;
+import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OutputFormatter;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
@@ -12,17 +14,27 @@ public class ReloadCommand implements CommandExecutor {
private final ConfigHandler config;
private final OutputFormatter outputFormatter;
+ private final Main plugin;
- public ReloadCommand(ConfigHandler c, OutputFormatter o) {
+ public ReloadCommand(ConfigHandler c, OutputFormatter o, Main p) {
outputFormatter = o;
config = c;
+ plugin = p;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (config.reloadConfig()) {
+ long time = System.currentTimeMillis();
+
outputFormatter.updateOutputColors();
+ time = plugin.logTimeTaken("ReloadCommand", "onCommand", time, 33);
+
+ OfflinePlayerHandler.updateOfflinePlayers();
+ time = plugin.logTimeTaken("ReloadCommand", "onCommand", time, 36);
+
sender.sendMessage(ChatColor.GREEN + "Config reloaded!");
+ plugin.logTimeTaken("ReloadCommand", "onCommand", time, 39);
return true;
}
return false;
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
index 5f82ec9..7eb7f29 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
@@ -1,7 +1,9 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.Main;
-import com.gmail.artemis.the.gr8.playerstats.StatManager;
+import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
+import com.gmail.artemis.the.gr8.playerstats.StatRequest;
+import com.gmail.artemis.the.gr8.playerstats.StatThread;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OutputFormatter;
import org.bukkit.command.Command;
@@ -13,98 +15,81 @@ import org.jetbrains.annotations.NotNull;
public class StatCommand implements CommandExecutor {
- private final OfflinePlayerHandler offlinePlayerHandler;
private final OutputFormatter outputFormatter;
- private final StatManager statManager;
+ private final EnumHandler enumHandler;
private final Main plugin;
- public StatCommand(OutputFormatter o, StatManager s, Main p) {
+ public StatCommand(OutputFormatter o, EnumHandler e, Main p) {
outputFormatter = o;
- statManager = s;
+ enumHandler = e;
plugin = p;
-
- offlinePlayerHandler = OfflinePlayerHandler.getInstance();
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
long time = System.currentTimeMillis();
- long startTime = System.currentTimeMillis();
+ //part 1: collecting all relevant information from the args
if (args.length >= 2) {
+ StatRequest request = new StatRequest(sender);
- String statName = null;
- String subStatEntry = null;
- String playerName = null;
- boolean playerFlag = false;
-
- plugin.getLogger().info("onCommand 40: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
-
- //all args are in lowercase
for (String arg : args) {
- if (statManager.isStatistic(arg)) {
- statName = (statName == null) ? arg : statName;
- plugin.getLogger().info("onCommand 48: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ if (enumHandler.isStatistic(arg) && request.getStatName() == null) {
+ request.setStatName(arg);
}
- else if (statManager.isSubStatEntry(arg)) {
+ else if (enumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player")) {
- if (!playerFlag) {
- subStatEntry = (subStatEntry == null) ? arg : subStatEntry;
- playerFlag = true;
- plugin.getLogger().info("onCommand 56: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ if (request.playerFlag()) {
+ if (request.getSubStatEntry() == null) request.setSubStatEntry(arg);
+ }
+ else {
+ request.setPlayerFlag(true);
}
}
+
else {
- subStatEntry = (subStatEntry == null || playerFlag) ? arg : subStatEntry;
- plugin.getLogger().info("onCommand 62: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ if (request.getSubStatEntry() == null) request.setSubStatEntry(arg);
}
}
- else if (arg.equalsIgnoreCase("me") && sender instanceof Player) {
- playerName = sender.getName();
- plugin.getLogger().info("onCommand 69: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ else if (arg.equalsIgnoreCase("top")) {
+ request.setTopFlag(true);
}
- else if (offlinePlayerHandler.isOfflinePlayerName(arg)) {
- playerName = (playerName == null) ? arg : playerName;
- plugin.getLogger().info("onCommand 74: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ else if (arg.equalsIgnoreCase("me") && sender instanceof Player) {
+ request.setPlayerName(sender.getName());
+ }
+ else if (OfflinePlayerHandler.isOfflinePlayerName(arg) && request.getPlayerName() == null) {
+ request.setPlayerName(arg);
}
}
- if (playerName != null && statName != null) {
- plugin.getLogger().info("onCommand 79: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- subStatEntry = statManager.isMatchingSubStatEntry(statName, subStatEntry) ? subStatEntry : null;
- plugin.getLogger().info("onCommand 82: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- try {
- plugin.getLogger().info("onCommand 85: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- int stat = statManager.getStatistic(statName, subStatEntry, playerName);
- plugin.getLogger().info("onCommand 89: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
-
- String msg = outputFormatter.formatPlayerStat(playerName, statName, subStatEntry, stat);
- plugin.getLogger().info("onCommand 93: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
-
- sender.sendMessage(msg);
- plugin.getLogger().info("onCommand 97: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
- }
- catch (Exception e) {
- sender.sendMessage(e.toString());
- }
+ //part 2: sending the information to the StatThread
+ if (isValidStatRequest(request)) {
+ StatThread statThread = new StatThread(request, enumHandler, outputFormatter, plugin);
+ statThread.start();
+ plugin.logTimeTaken("StatCommand", "onCommand", time, 71);
+ return true;
}
}
- plugin.getLogger().info("onCommand 106: " + (System.currentTimeMillis() - time));
- plugin.getLogger().info("Total time elapsed: " + (System.currentTimeMillis() - startTime));
- return true;
+ return false;
+ }
+
+ //check whether all necessary ingredients are present to proceed with a lookup
+ private boolean isValidStatRequest(StatRequest request) {
+ if (request.getStatName() != null) {
+ if (request.topFlag() || request.getPlayerName() != null) {
+ validatePlayerFlag(request);
+ return enumHandler.isValidStatEntry(request.getStatName(), request.getSubStatEntry());
+ }
+ }
+ return false;
+ }
+
+ //account for the fact that "player" could be either a subStatEntry or a flag to indicate the target for the lookup, and correct the request if necessary
+ private void validatePlayerFlag(StatRequest request) {
+ if (!enumHandler.isValidStatEntry(request.getStatName(), request.getSubStatEntry()) && request.playerFlag()) {
+ request.setSubStatEntry("player");
+ }
}
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/TabCompleter.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/TabCompleter.java
index 3ace0a9..29a0f08 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/TabCompleter.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/TabCompleter.java
@@ -1,7 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.Main;
-import com.gmail.artemis.the.gr8.playerstats.StatManager;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import org.bukkit.command.Command;
@@ -15,16 +14,12 @@ import java.util.stream.Collectors;
public class TabCompleter implements org.bukkit.command.TabCompleter {
private final EnumHandler enumHandler;
- private final OfflinePlayerHandler offlinePlayerHandler;
- private final StatManager statManager;
private final Main plugin;
private final List commandOptions;
- public TabCompleter(EnumHandler e, StatManager s, Main p) {
+ public TabCompleter(EnumHandler e, Main p) {
enumHandler = e;
- offlinePlayerHandler = OfflinePlayerHandler.getInstance();
- statManager = s;
plugin = p;
commandOptions = new ArrayList<>();
@@ -45,14 +40,14 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
//after typing "stat", suggest a list of viable statistics
if (args.length >= 1) {
if (args.length == 1) {
- tabSuggestions = statManager.getStatNames().stream().filter(stat ->
+ tabSuggestions = enumHandler.getStatNames().stream().filter(stat ->
stat.contains(args[0].toLowerCase())).collect(Collectors.toList());
}
//after checking if args[0] is a viable statistic, suggest substatistic OR commandOptions
else {
- if (statManager.isStatistic(args[args.length-2])) {
- tabSuggestions = switch (statManager.getStatType(args[args.length-2])) {
+ if (enumHandler.isStatistic(args[args.length-2])) {
+ tabSuggestions = switch (enumHandler.getStatType(args[args.length-2])) {
case UNTYPED -> commandOptions;
case BLOCK -> enumHandler.getBlockNames().stream().filter(block ->
block.contains(args[args.length - 1])).collect(Collectors.toList());
@@ -61,23 +56,22 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
case ENTITY -> enumHandler.getEntityTypeNames().stream().filter(entity ->
entity.contains(args[args.length - 1])).collect(Collectors.toList());
};
-
}
//if previous arg = "player", suggest playerNames
else if (args[args.length-2].equalsIgnoreCase("player")) {
- if (args.length >= 3 && statManager.getEntityTypeNames().contains(args[args.length-3].toLowerCase())) {
+ if (args.length >= 3 && enumHandler.getEntityStatNames().contains(args[args.length-3].toLowerCase())) {
tabSuggestions = commandOptions;
}
else {
- tabSuggestions = offlinePlayerHandler.getAllOfflinePlayerNames().stream().filter(player ->
+ tabSuggestions = OfflinePlayerHandler.getAllOfflinePlayerNames().stream().filter(player ->
player.toLowerCase().contains(args[args.length-1].toLowerCase())).collect(Collectors.toList());
}
}
//after a substatistic, suggest commandOptions
- else if (statManager.isSubStatEntry(args[args.length-2])) {
+ else if (enumHandler.isSubStatEntry(args[args.length-2])) {
tabSuggestions = commandOptions;
}
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/filehandlers/ConfigHandler.java
similarity index 65%
rename from src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java
rename to src/main/java/com/gmail/artemis/the/gr8/playerstats/filehandlers/ConfigHandler.java
index 2bbe46b..172aa18 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/filehandlers/ConfigHandler.java
@@ -1,5 +1,6 @@
-package com.gmail.artemis.the.gr8.playerstats;
+package com.gmail.artemis.the.gr8.playerstats.filehandlers;
+import com.gmail.artemis.the.gr8.playerstats.Main;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
@@ -19,24 +20,53 @@ public class ConfigHandler {
saveDefaultConfig();
}
+ //returns the config setting for use-dots, or the default value "true" if no value can be retrieved
+ public boolean getUseDots() {
+ ConfigurationSection ranked = config.getConfigurationSection("ranked-list");
+ try {
+ return ranked == null || ranked.getBoolean("use-dots");
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return true;
+ }
+ }
+
//returns a HashMap with all the available color choices, or a ChatColor.RESET if no colors were found
public HashMap getChatColors() {
HashMap chatColors = new HashMap<>();
ConfigurationSection individual = config.getConfigurationSection("individual-statistics");
- chatColors.put("playerNames", getChatColor(individual, "player-names"));
- chatColors.put("statNames", getChatColor(individual, "stat-names"));
- chatColors.put("subStatNames", getChatColor(individual, "sub-stat-names"));
- chatColors.put("numbers", getChatColor(individual, "numbers"));
+ chatColors.put("player-names", getChatColor(individual, "player-names"));
+ chatColors.put("stat-names", getChatColor(individual, "stat-names"));
+ chatColors.put("sub-stat-names", getChatColor(individual, "sub-stat-names"));
+ chatColors.put("stat-numbers", getChatColor(individual, "stat-numbers"));
ConfigurationSection ranked = config.getConfigurationSection("ranked-list");
- chatColors.put("playerNamesRanked", getChatColor(ranked, "player-names"));
- chatColors.put("statNamesRanked", getChatColor(ranked, "stat-names"));
- chatColors.put("subStatNamesRanked", getChatColor(ranked, "sub-stat-names"));
- chatColors.put("numbersRanked", getChatColor(ranked, "numbers"));
+ chatColors.put("player-names-ranked", getChatColor(ranked, "player-names"));
+ chatColors.put("list-title", getChatColor(ranked, "list-title"));
+ chatColors.put("sub-stat-names-ranked", getChatColor(ranked, "sub-stat-names"));
+ chatColors.put("stat-numbers-ranked", getChatColor(ranked, "stat-numbers"));
+ chatColors.put("list-numbers", getChatColor(ranked, "list-numbers"));
+ chatColors.put("dots", getChatColor(ranked, "dots"));
return chatColors;
}
+ //reload the config after changes have been made to it
+ public boolean reloadConfig() {
+ try {
+ if (!configFile.exists()) {
+ saveDefaultConfig();
+ }
+ config = YamlConfiguration.loadConfiguration(configFile);
+ return true;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
//returns the requested entry from the provided configuration section, null if section does not exist, and ChatColor.RESET if there is no entry
private ChatColor getChatColor(ConfigurationSection section, String path) {
ChatColor color;
@@ -56,21 +86,6 @@ public class ConfigHandler {
return color;
}
- //reload the config after changes have been made to it
- public boolean reloadConfig() {
- try {
- if (!configFile.exists()) {
- saveDefaultConfig();
- }
- config = YamlConfiguration.loadConfiguration(configFile);
- return true;
- }
- catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
//create a config file if none exists yet (from the config.yml in the plugin's resources)
private void saveDefaultConfig() {
config = plugin.getConfig();
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java
index f489c26..96136cb 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/listeners/JoinListener.java
@@ -1,21 +1,20 @@
package com.gmail.artemis.the.gr8.playerstats.listeners;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
+import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class JoinListener implements Listener {
- private final OfflinePlayerHandler offlinePlayerHandler;
-
public JoinListener() {
- offlinePlayerHandler = OfflinePlayerHandler.getInstance();
}
+ @EventHandler
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
if (!joinEvent.getPlayer().hasPlayedBefore()) {
- offlinePlayerHandler.updateOfflinePlayers();
+ OfflinePlayerHandler.updateOfflinePlayers();
}
}
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/EnumHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/EnumHandler.java
index 2074569..644bbcc 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/EnumHandler.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/EnumHandler.java
@@ -1,32 +1,57 @@
package com.gmail.artemis.the.gr8.playerstats.utils;
+import com.gmail.artemis.the.gr8.playerstats.Main;
import org.bukkit.Material;
+import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
public class EnumHandler {
private final List blockNames;
private final List entityTypeNames;
private final List itemNames;
+ private final List statNames;
+ private final List entityStatNames;
+ private final List subStatEntryNames;
+ private final Main plugin;
- public EnumHandler() {
+ public EnumHandler(Main p) {
+ plugin = p;
+
blockNames = Arrays.stream(Material.values()).filter(
Material::isBlock).map(Material::toString).map(String::toLowerCase).toList();
entityTypeNames = Arrays.stream(EntityType.values()).map(
EntityType::toString).map(String::toLowerCase).toList();
itemNames = Arrays.stream(Material.values()).filter(
Material::isItem).map(Material::toString).map(String::toLowerCase).toList();
+ statNames = Arrays.stream(Statistic.values()).map(
+ Statistic::toString).map(String::toLowerCase).toList();
+
+ entityStatNames = Arrays.stream(Statistic.values()).filter(statistic ->
+ statistic.getType().equals(Statistic.Type.ENTITY)).map(
+ Statistic::toString).map(String::toLowerCase).collect(Collectors.toList());
+
+ subStatEntryNames = new ArrayList<>();
+ subStatEntryNames.addAll(getBlockNames());
+ subStatEntryNames.addAll(getEntityTypeNames());
+ subStatEntryNames.addAll(getItemNames());
}
+ //checks whether the provided string is a valid item
public boolean isItem(String itemName) {
return itemNames.contains(itemName.toLowerCase());
}
//returns corresponding item enum constant (uppercase), otherwise null (param: itemName, not case sensitive)
+ @Nullable
public Material getItem(String itemName) {
return Material.matchMaterial(itemName);
}
@@ -36,18 +61,25 @@ public class EnumHandler {
return itemNames;
}
+ //checks whether the provided string is a valid entity
public boolean isEntityType(String entityName) {
return entityTypeNames.contains(entityName.toLowerCase());
}
//returns EntityType enum constant (uppercase) if the input name is valid, otherwise null (param: entityName, not case sensitive)
+ @Nullable
public EntityType getEntityType(String entityName) {
- EntityType entityType = null;
+ EntityType entityType;
try {
entityType = EntityType.valueOf(entityName.toUpperCase());
}
- catch (IllegalArgumentException | NullPointerException exception) {
- exception.printStackTrace();
+ catch (IllegalArgumentException e) {
+ plugin.getLogger().warning("IllegalArgumentException: " + entityName + " is not a valid statistic name!");
+ return null;
+ }
+ catch (NullPointerException e) {
+ plugin.getLogger().warning("NullPointerException: please provide a statistic name!");
+ return null;
}
return entityType;
}
@@ -57,11 +89,13 @@ public class EnumHandler {
return entityTypeNames;
}
+ //checks whether the provided string is a valid block
public boolean isBlock(String materialName) {
return blockNames.contains(materialName.toLowerCase());
}
//returns corresponding block enum constant (uppercase), otherwise null (param: materialName, not case sensitive)
+ @Nullable
public Material getBlock(String materialName) {
return Material.matchMaterial(materialName);
}
@@ -71,4 +105,85 @@ public class EnumHandler {
return blockNames;
}
+ //returns the statistic enum constant, or null if non-existent (param: statName, not case sensitive)
+ public Statistic getStatEnum(String statName) {
+ try {
+ return Statistic.valueOf(statName.toUpperCase());
+ }
+ catch (IllegalArgumentException e) {
+ plugin.getLogger().warning("IllegalArgumentException: " + statName + " is not a valid statistic name!");
+ return null;
+ }
+ catch (NullPointerException e) {
+ plugin.getLogger().warning("NullPointerException: please provide a statistic name!");
+ return null;
+ }
+ }
+
+ //gets the type of the statistic from the string, otherwise returns null (param: statName, not case sensitive)
+ public Statistic.Type getStatType(String statName) {
+ try {
+ return Statistic.valueOf(statName.toUpperCase()).getType();
+ }
+ catch (IllegalArgumentException e) {
+ plugin.getLogger().warning("IllegalArgumentException: " + statName + " is not a valid statistic name!");
+ return null;
+ }
+ catch (NullPointerException e) {
+ plugin.getLogger().warning("NullPointerException: please provide a statistic name!");
+ return null;
+ }
+ }
+
+ //checks if string is a valid statistic (param: statName, not case sensitive)
+ public boolean isStatistic(String statName) {
+ return statNames.contains(statName.toLowerCase());
+ }
+
+ //returns the names of all general statistics in lowercase
+ public List getStatNames() {
+ return statNames;
+ }
+
+ //returns all statistics that have type entities, in lowercase
+ public List getEntityStatNames() {
+ return entityStatNames;
+ }
+
+ //checks if this statistic is a subStatEntry, meaning it is a block, item or entity (param: statName, not case sensitive)
+ public boolean isSubStatEntry(String statName) {
+ return subStatEntryNames.contains(statName.toLowerCase());
+ }
+
+ //checks if string is a valid statistic (param: statName, not case sensitive)
+ public boolean isValidStatEntry(String statName) {
+ return isValidStatEntry(statName, null);
+ }
+
+ //checks whether a subStatEntry is of the type that the statistic requires
+ public boolean isValidStatEntry(String statName, String subStatEntry) {
+ Statistic stat = getStatEnum(statName);
+ return (stat != null && isMatchingSubStatEntry(stat, subStatEntry));
+ }
+
+ //returns true if subStatEntry matches the type the stat requires, or if stat is untyped and subStatEntry is null
+ private boolean isMatchingSubStatEntry(@NotNull Statistic stat, String subStatEntry) {
+ switch (stat.getType()) {
+ case ENTITY -> {
+ return subStatEntry != null && isEntityType(subStatEntry);
+ }
+ case ITEM -> {
+ return subStatEntry != null && isItem(subStatEntry);
+ }
+ case BLOCK -> {
+ return subStatEntry != null && isBlock(subStatEntry);
+ }
+ case UNTYPED -> {
+ return subStatEntry==null;
+ }
+ default -> {
+ return false;
+ }
+ }
+ }
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java
index b19db79..7cc5fa7 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OfflinePlayerHandler.java
@@ -4,51 +4,60 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.util.*;
-import java.util.stream.Collectors;
public class OfflinePlayerHandler {
- private static OfflinePlayerHandler instance;
- private List offlinePlayers;
- private List offlinePlayerNames;
- private HashMap offlinePlayerMap;
+ private static HashMap offlinePlayerMap;
+ private static List offlinePlayerNames;
+ private static int totalOfflinePlayers;
private OfflinePlayerHandler() {
- updateOfflinePlayers();
}
- public static OfflinePlayerHandler getInstance() {
- if (instance == null) {
- instance = new OfflinePlayerHandler();
- }
- return instance;
- }
-
- public boolean isOfflinePlayerName(String playerName) {
+ public static boolean isOfflinePlayerName(String playerName) {
return offlinePlayerNames.contains(playerName);
}
- public OfflinePlayer getOfflinePlayer(String playerName) {
- long time = System.currentTimeMillis();
-
- OfflinePlayer player = offlinePlayerMap.get(playerName);
- System.out.println(("OfflinePlayerHandler 35: " + (System.currentTimeMillis() - time)));
- return player;
+ public static OfflinePlayer getOfflinePlayer(String playerName) {
+ return offlinePlayerMap.get(playerName);
}
- public List getAllOfflinePlayers() {
- return offlinePlayers;
+ public static int getOfflinePlayerCount() {
+ return totalOfflinePlayers > 0 ? totalOfflinePlayers : 1;
}
- public List getAllOfflinePlayerNames() {
+ public static List getAllOfflinePlayerNames() {
return offlinePlayerNames;
}
- public void updateOfflinePlayers() {
- offlinePlayerMap = new HashMap<>();
- offlinePlayers = Arrays.stream(Bukkit.getOfflinePlayers()).filter(offlinePlayer ->
- offlinePlayer.getName() != null && offlinePlayer.hasPlayedBefore()).collect(Collectors.toList());
- offlinePlayerNames = offlinePlayers.stream().map(OfflinePlayer::getName).collect(Collectors.toList());
- offlinePlayers.forEach(offlinePlayer -> offlinePlayerMap.put(offlinePlayer.getName(), offlinePlayer));
+ //stores a private HashMap with keys:playerName and values:OfflinePlayer, and a private list of the names for easy access
+ public static void updateOfflinePlayers() {
+ long totalTime = System.currentTimeMillis();
+ long time = System.currentTimeMillis();
+ if (offlinePlayerMap == null) offlinePlayerMap = new HashMap<>();
+ else if (!offlinePlayerMap.isEmpty()) {
+ offlinePlayerMap.clear();
+ }
+
+ if (offlinePlayerNames == null) offlinePlayerNames = new ArrayList<>();
+ else if (!offlinePlayerNames.isEmpty()) {
+ offlinePlayerNames.clear();
+ }
+
+ Arrays.stream(Bukkit.getOfflinePlayers()).filter(offlinePlayer ->
+ offlinePlayer.getName() != null && offlinePlayer.hasPlayedBefore()).forEach(offlinePlayer -> {
+ offlinePlayerNames.add(offlinePlayer.getName());
+ offlinePlayerMap.put(offlinePlayer.getName(), offlinePlayer);
+ });
+ System.out.println("OfflinePlayerHandler, making the HashMap and ArrayList: " + (System.currentTimeMillis() - time));
+ time = System.currentTimeMillis();
+
+ totalOfflinePlayers = offlinePlayerMap.size();
+ System.out.println("OfflinePlayerHandler, counting the HashMap: " + (System.currentTimeMillis() - time));
+ time = System.currentTimeMillis();
+
+ totalOfflinePlayers = offlinePlayerNames.size();
+ System.out.println("OfflinePlayerHandler, counting the ArrayList: " + (System.currentTimeMillis() - time));
+ System.out.println("updateOfflinePlayers total time: " + (System.currentTimeMillis() - totalTime));
}
}
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
index beb4ca6..7cf57a1 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
@@ -1,51 +1,72 @@
package com.gmail.artemis.the.gr8.playerstats.utils;
-import com.gmail.artemis.the.gr8.playerstats.ConfigHandler;
-import com.gmail.artemis.the.gr8.playerstats.Main;
+import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
import org.bukkit.ChatColor;
+import org.bukkit.map.MinecraftFont;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.*;
public class OutputFormatter {
- //keys for the HashMap are:
- //playerNames(Ranked)
- //statNames(Ranked)
- //subStatNames(Ranked)
- //numbers(Ranked)
+ //keys for the HashMap are the same as the config options (so e.g. player-names/player-names-ranked)
+
private final ConfigHandler config;
private HashMap chatColors;
+ private final String pluginPrefix;
public OutputFormatter(ConfigHandler c) {
config = c;
+ pluginPrefix = ChatColor.GRAY + "[" + ChatColor.GOLD + "PlayerStats" + ChatColor.GRAY + "] " + ChatColor.RESET;
updateOutputColors();
}
- public String formatTopStats(LinkedHashMap topStats) {
- return "";
- }
-
- public String formatPlayerStat(String playerName, String statName, int stat) {
- return formatPlayerStat(playerName, statName, null, stat);
+ public String formatExceptions(String exception) {
+ return pluginPrefix + exception;
}
public String formatPlayerStat(String playerName, String statName, String subStatEntryName, int stat) {
- long time = System.currentTimeMillis();
- System.out.println("OutputFormatter 33: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
-
String subStat = subStatEntryName != null ?
- chatColors.get("subStatNames") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
+ chatColors.get("sub-stat-names") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
- System.out.println("OutputFormatter 39: " + (System.currentTimeMillis() - time));
- time = System.currentTimeMillis();
+ return chatColors.get("player-names") + playerName + chatColors.get("stat-numbers") + ": " + stat + " " +
+ chatColors.get("stat-names") + statName.toLowerCase().replace("_", " ") + subStat;
+ }
- String msg = chatColors.get("playerNames") + playerName + chatColors.get("numbers") + ": " + stat + " " +
- chatColors.get("statNames") + statName.toLowerCase().replace("_", " ") + subStat;
+ public String formatTopStats(LinkedHashMap topStats, String statName, String subStatEntryName) {
+ String subStat = subStatEntryName != null ?
+ chatColors.get("sub-stat-names-ranked") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
+ String topCount = chatColors.get("list-numbers") + " " + topStats.size();
+ String title = "\n" + pluginPrefix + chatColors.get("list-title") + "Top" + topCount + chatColors.get("list-title") + " " +
+ statName.toLowerCase().replace("_", " ") + subStat;
- System.out.println("OutputFormatter 45: " + (System.currentTimeMillis() - time));
- return msg;
+ boolean useDots = config.getUseDots();
+ int count = 0;
+ Set playerNames = topStats.keySet();
+ MinecraftFont font = new MinecraftFont();
+
+ StringBuilder rankList = new StringBuilder();
+ for (String playerName : playerNames) {
+ count = count+1;
+
+ rankList.append("\n")
+ .append(chatColors.get("list-numbers")).append(count).append(". ")
+ .append(chatColors.get("player-names-ranked")).append(playerName)
+ .append(chatColors.get("dots"));
+
+ if (useDots) {
+ rankList.append(" ");
+ int dots = (int) Math.round((125.0 - font.getWidth(count + ". " + playerName))/2);
+ if (dots >= 1) {
+ rankList.append(".".repeat(dots));
+ }
+ }
+ else {
+ rankList.append(":");
+ }
+
+ rankList.append(" ").append(chatColors.get("stat-numbers-ranked")).append(topStats.get(playerName).toString());
+ }
+ return title + rankList;
}
public void updateOutputColors() {
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index e1a083c..2fc8f81 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,15 +1,23 @@
# PlayerStats Configuration
-# --- Color Options ---
-# supports: all default Minecraft colors
+# --- General Options ---
+
+
+# --- Format & Color Options ---
individual-statistics:
player-names: gold
stat-names: yellow
sub-stat-names: yellow
- numbers: white
+ stat-numbers: white
ranked-list:
- player-names: gold
- stat-names: yellow
+ player-names: green
+ list-title: yellow
sub-stat-names: yellow
- numbers: white
\ No newline at end of file
+ stat-numbers: white
+ list-numbers: gold
+
+# If true, the statistics will be aligned so that they are all underneath each other
+ use-dots: true
+ dots: dark_gray
+