Made top-list-max-size configurable (#16)

This commit is contained in:
Artemis-the-gr8 2022-05-19 13:59:53 +02:00
parent dc364a567e
commit 56eb0d8148
12 changed files with 99 additions and 88 deletions

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@ -34,6 +34,8 @@
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
</project>

View File

@ -9,12 +9,15 @@ 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.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin {
@Override
public void onEnable() {
//check if Spigot ChatColors can be used, and prepare accordingly
boolean enableHexColors = false;
try {
Class.forName("net.md_5.bungee.api.ChatColor");
@ -25,6 +28,7 @@ public class Main extends JavaPlugin {
this.getLogger().info("Hex Colors are not supported for this server type, proceeding with default Chat Colors...");
}
//get instances of the classes that should be initialized
ConfigHandler config = new ConfigHandler(this);
EnumHandler enumHandler = new EnumHandler(this);
OutputFormatter outputFormatter = new OutputFormatter(config, enableHexColors);
@ -32,15 +36,17 @@ public class Main extends JavaPlugin {
//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));
//register the commands
PluginCommand statcmd = this.getCommand("statistic");
if (statcmd != null) {
statcmd.setExecutor(new StatCommand(config, enumHandler, outputFormatter, this));
statcmd.setTabCompleter(new TabCompleter(enumHandler));
}
PluginCommand reloadcmd = this.getCommand("statisticreload");
if (reloadcmd != null) reloadcmd.setExecutor(new ReloadCommand(config, outputFormatter));
//register the listener
Bukkit.getPluginManager().registerEvents(new JoinListener(), this);
this.getLogger().info("Bukkit name: " + Bukkit.getName());
this.getLogger().info("Bukkit getServer name: " + Bukkit.getServer().getName());
this.getLogger().info("Bukkit version: " + Bukkit.getVersion());
this.getLogger().info("Bukkit getBukkitVersion: " + Bukkit.getBukkitVersion());
this.getLogger().info("Enabled PlayerStats!");
}

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats;
import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
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;
@ -19,15 +20,19 @@ import java.util.stream.Collectors;
public class StatThread extends Thread {
private final StatRequest request;
private final ConfigHandler config;
private final EnumHandler enumHandler;
private final OutputFormatter outputFormatter;
private final Main plugin;
private String className = "StatThread";
private final String className = "StatThread";
//constructor (called on thread creation)
public StatThread(StatRequest s, EnumHandler e, OutputFormatter o, Main p) {
public StatThread(StatRequest s, ConfigHandler c, EnumHandler e, OutputFormatter o, Main p) {
request = s;
config = c;
enumHandler = e;
outputFormatter = o;
plugin = p;
@ -37,8 +42,6 @@ public class StatThread extends Thread {
//what the thread will do once started
@Override
public void run() throws IllegalStateException, NullPointerException {
plugin.getLogger().info("Name: " + this.getName());
plugin.getLogger().info("ID: " + this.getId());
long time = System.currentTimeMillis();
if (outputFormatter == null || plugin == null) {
@ -64,6 +67,7 @@ public class StatThread extends Thread {
} catch (Exception e) {
sender.sendMessage(outputFormatter.formatExceptions(e.toString()));
e.printStackTrace();
}
} else if (topFlag) {
@ -73,7 +77,7 @@ public class StatThread extends Thread {
String top = outputFormatter.formatTopStats(topStats, statName, subStatEntry);
sender.sendMessage(top);
plugin.logTimeTaken(className, "run(): format output", time, 73);
plugin.logTimeTaken(className, "run(): total time", time, 73);
} catch (Exception e) {
sender.sendMessage(outputFormatter.formatExceptions(e.toString()));
@ -99,7 +103,7 @@ public class StatThread extends Thread {
Statistic stat = enumHandler.getStatEnum(statName);
if (stat != null) {
HashMap<String, Integer> playerStats = new HashMap<>((int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05));
HashMap<String, Integer> playerStats = new HashMap<>((int) (getOfflinePlayerCount() * 1.05));
OfflinePlayerHandler.getAllOfflinePlayerNames().forEach(playerName -> {
OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName);
if (player != null)
@ -113,7 +117,7 @@ public class StatThread extends Thread {
});
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));
.limit(config.getTopListMaxSize()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
throw new NullPointerException("Statistic " + statName + " could not be retrieved!");
}
@ -154,4 +158,20 @@ public class StatThread extends Thread {
throw new IllegalArgumentException("This statistic does not seem to be of type:untyped/block/entity/item, I think we should panic");
}
}
private int getOfflinePlayerCount() {
try {
return OfflinePlayerHandler.getOfflinePlayerCount();
}
catch (NullPointerException e) {
OfflinePlayerHandler.updateOfflinePlayers();
try {
return OfflinePlayerHandler.getOfflinePlayerCount();
}
catch (NullPointerException ex) {
plugin.getLogger().warning(e.toString());
throw new RuntimeException();
}
}
}
}

View File

@ -1,7 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
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;
@ -14,27 +13,21 @@ public class ReloadCommand implements CommandExecutor {
private final ConfigHandler config;
private final OutputFormatter outputFormatter;
private final Main plugin;
public ReloadCommand(ConfigHandler c, OutputFormatter o, Main p) {
public ReloadCommand(ConfigHandler c, OutputFormatter o) {
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;

View File

@ -1,6 +1,7 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
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;
@ -15,13 +16,15 @@ import org.jetbrains.annotations.NotNull;
public class StatCommand implements CommandExecutor {
private static OutputFormatter outputFormatter;
private final ConfigHandler config;
private final EnumHandler enumHandler;
private final OutputFormatter outputFormatter;
private final Main plugin;
public StatCommand(OutputFormatter o, EnumHandler e, Main p) {
outputFormatter = o;
public StatCommand(ConfigHandler c, EnumHandler e, OutputFormatter o, Main p) {
config = c;
enumHandler = e;
outputFormatter = o;
plugin = p;
}
@ -65,7 +68,7 @@ public class StatCommand implements CommandExecutor {
//part 2: sending the information to the StatThread
if (isValidStatRequest(request)) {
StatThread statThread = new StatThread(request, enumHandler, outputFormatter, plugin);
StatThread statThread = new StatThread(request, config, enumHandler, outputFormatter, plugin);
statThread.start();
plugin.logTimeTaken("StatCommand", "onCommand", time, 71);

View File

@ -1,6 +1,5 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import org.bukkit.command.Command;
@ -14,13 +13,11 @@ import java.util.stream.Collectors;
public class TabCompleter implements org.bukkit.command.TabCompleter {
private final EnumHandler enumHandler;
private final Main plugin;
private final List<String> commandOptions;
public TabCompleter(EnumHandler e, Main p) {
public TabCompleter(EnumHandler e) {
enumHandler = e;
plugin = p;
commandOptions = new ArrayList<>();
commandOptions.add("top");

View File

@ -47,24 +47,29 @@ public class ConfigHandler {
}
}
//returns the config setting for top-list-max-size, or the default value of 10 if no value can be retrieved
public int getTopListMaxSize() {
try {
return config.getInt("top-list-max-size");
}
catch (Exception e) {
e.printStackTrace();
return 10;
}
}
//returns a HashMap with the available (Bukkit) style choices, null if no style was chosen, and ChatColor.RESET if the entry was not valid
public HashMap<String, ChatColor> getStyleOptions() {
HashMap<String, ChatColor> styling = new HashMap<>();
ConfigurationSection individual = config.getConfigurationSection("individual-statistics-style");
if (individual != null) {
plugin.getLogger().info("individual-statistics-style: " + individual.getKeys(false));
individual.getKeys(false).forEach(path -> {
styling.put(path, getStyleOption(individual, path));
});
individual.getKeys(false).forEach(path -> styling.put(path, getStyleOption(individual, path)));
}
ConfigurationSection top = config.getConfigurationSection("top-list-style");
if (top != null) {
plugin.getLogger().info("top-list-style: " + top.getKeys(false));
top.getKeys(false).forEach(path -> {
styling.put(path + "-top", getStyleOption(top, path));
});
top.getKeys(false).forEach(path -> styling.put(path + "-top", getStyleOption(top, path)));
}
return styling;
}
@ -96,18 +101,12 @@ public class ConfigHandler {
ConfigurationSection individual = config.getConfigurationSection("individual-statistics");
if (individual != null) {
plugin.getLogger().info("individual-statistics: " + individual.getKeys(false));
individual.getKeys(false).forEach(path -> {
chatColors.put(path, getChatColor(individual, path));
});
individual.getKeys(false).forEach(path -> chatColors.put(path, getChatColor(individual, path)));
}
ConfigurationSection top = config.getConfigurationSection("top-list");
if (top != null) {
plugin.getLogger().info("top-list: " + top.getKeys(false));
top.getKeys(false).forEach(path -> {
chatColors.put(path + "-top", getChatColor(top, path));
});
top.getKeys(false).forEach(path -> chatColors.put(path + "-top", getChatColor(top, path)));
}
return chatColors;
}
@ -138,18 +137,12 @@ public class ConfigHandler {
ConfigurationSection individual = config.getConfigurationSection("individual-statistics");
if (individual != null) {
plugin.getLogger().info("individual-statistics: " + individual.getKeys(false));
individual.getKeys(false).forEach(path -> {
chatColors.put(path, getHexChatColor(individual, path));
});
individual.getKeys(false).forEach(path -> chatColors.put(path, getHexChatColor(individual, path)));
}
ConfigurationSection top = config.getConfigurationSection("top-list");
if (top != null) {
plugin.getLogger().info("top-list: " + top.getKeys(false));
top.getKeys(false).forEach(path -> {
chatColors.put(path + "-top", getHexChatColor(top, path));
});
top.getKeys(false).forEach(path -> chatColors.put(path + "-top", getHexChatColor(top, path)));
}
return chatColors;
}

View File

@ -155,11 +155,6 @@ public class EnumHandler {
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);

View File

@ -22,8 +22,9 @@ public class OfflinePlayerHandler {
return offlinePlayerMap.get(playerName);
}
public static int getOfflinePlayerCount() {
return totalOfflinePlayers > 0 ? totalOfflinePlayers : 1;
public static int getOfflinePlayerCount() throws NullPointerException {
if (totalOfflinePlayers > 0) return totalOfflinePlayers;
else throw new NullPointerException("No players found!");
}
public static List<String> getAllOfflinePlayerNames() {
@ -32,8 +33,6 @@ public class OfflinePlayerHandler {
//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();
@ -49,15 +48,7 @@ public class OfflinePlayerHandler {
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));
}
}

View File

@ -28,30 +28,34 @@ public class OutputFormatter {
updateOutPutColors(useHex);
}
public String getPluginPrefix() {
return pluginPrefix;
}
public String formatExceptions(String exception) {
return pluginPrefix + exception;
}
public String formatPlayerStat(String playerName, String statName, String subStatEntryName, int stat) {
StringBuilder msg = new StringBuilder();
StringBuilder singleStat = new StringBuilder();
String subStat = subStatEntryName != null ?
" (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
msg.append(getPlayerColor(false)).append(getPlayerStyle(false)).append(playerName).append(": ")
singleStat.append(getPlayerFormatting(false)).append(playerName).append(": ")
.append(getStatNumberColor(false)).append(getStatNumberStyle(false)).append(stat).append(" ")
.append(getStatNameColor(false)).append(getStatNameStyle(false))
.append(statName.toLowerCase().replace("_", " "))
.append(getSubStatNameColor(false)).append(getSubStatNameStyle(false)).append(subStat);
return msg.toString();
return singleStat.toString();
}
public String formatTopStats(LinkedHashMap<String, Integer> topStats, String statName, String subStatEntryName) {
StringBuilder msg = new StringBuilder();
StringBuilder topList = new StringBuilder();
String subStat = subStatEntryName != null ?
" (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
msg.append("\n").append(pluginPrefix)
topList.append("\n").append(pluginPrefix)
.append(getStatNameColor(true)).append(getStatNameStyle(true)).append("Top ")
.append(getListNumberColor()).append(getListNumberStyle()).append(topStats.size())
.append(getStatNameColor(true)).append(getStatNameStyle(true)).append(" ")
@ -67,27 +71,31 @@ public class OutputFormatter {
for (String playerName : playerNames) {
count = count+1;
msg.append("\n")
topList.append("\n")
.append(getListNumberColor()).append(getListNumberStyle()).append(count).append(". ")
.append(getPlayerColor(true)).append(getPlayerStyle(true)).append(playerName);
if (useDots) {
msg.append(getDotColor()).append(" ");
topList.append(getDotColor()).append(" ");
int dots = (int) Math.round((130.0 - font.getWidth(count + ". " + playerName))/2);
if (getPlayerStyle(true).equals(ChatColor.BOLD)) {
dots = (int) Math.round((130.0 - font.getWidth(count + ". ") - (font.getWidth(playerName) * 1.19))/2);
}
if (dots >= 1) {
msg.append(".".repeat(dots));
topList.append(".".repeat(dots));
}
}
else {
msg.append(":");
topList.append(":");
}
msg.append(" ").append(getStatNumberColor(true)).append(getStatNumberStyle(true)).append(topStats.get(playerName).toString());
topList.append(" ").append(getStatNumberColor(true)).append(getStatNumberStyle(true)).append(topStats.get(playerName).toString());
}
return msg.toString();
return topList.toString();
}
private String getPlayerFormatting(boolean isTopStat) {
return getPlayerColor(isTopStat) + "" + getPlayerStyle(isTopStat);
}
private Object getPlayerColor(boolean isTopStat) {return getColor("player-names", false, isTopStat);}

View File

@ -1,12 +1,13 @@
# PlayerStats Configuration
# --- General Options ---
# ------ General Options -------
# The maximum number of entries displayed in the top list
top-list-max-size: 10
# --- Format & Color Options ---
# --------- format -------------
# If true, the top list of statistics will be aligned so that they are all underneath each other
# If true, the top list will be aligned with lines of dots so that the stat numbers are all underneath each other
use-dots: true
# ---------- color -------------
@ -26,7 +27,7 @@ top-list:
list-numbers: gold
dots: dark_gray
# This provides additional styling options such as italic/underline/bold
# This provides additional styling options (italic/underline/bold, and yes, even magic)
individual-statistics-style:
player-names: none
stat-names: none