Finished overhaul of MessageFactory and ConfigHandler, and added custom enum for CommandOptions

This commit is contained in:
Artemis-the-gr8 2022-06-07 01:06:55 +02:00
parent 8233fde53f
commit 6f43c03b8c
5 changed files with 150 additions and 163 deletions

View File

@ -0,0 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.enums;
public enum CommandOption {
PLAYER, SERVER, TOP;
}

View File

@ -1,6 +1,7 @@
package com.gmail.artemis.the.gr8.playerstats.filehandlers;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.enums.CommandOption;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
@ -67,13 +68,19 @@ public class ConfigHandler {
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "green" or "gold" for Color (for top or individual color). */
public String getPlayerNameFormatting(boolean topStat, boolean isStyle) {
String def = topStat ? "green" : "gold";
return getStringFromConfig(topStat, false, isStyle, def, "player-names");
public String getPlayerNameFormatting(CommandOption selection, boolean isStyle) {
String def;
if (selection == CommandOption.TOP) {
def = "green";
}
else {
def = "gold";
}
return getStringFromConfig(selection, isStyle, def, "player-names");
}
public boolean playerNameIsBold() {
ConfigurationSection style = getRelevantSection(true, true);
ConfigurationSection style = getRelevantSection(CommandOption.PLAYER);
if (style != null) {
String styleString = style.getString("player-names");
@ -84,72 +91,83 @@ public class ConfigHandler {
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "yellow" for Color. */
public String getStatNameFormatting(boolean topStat, boolean serverStat, boolean isStyle) {
return getStringFromConfig(topStat, serverStat, isStyle, "yellow", "stat-names");
public String getStatNameFormatting(CommandOption selection, boolean isStyle) {
return getStringFromConfig(selection, isStyle, "yellow", "stat-names");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "#FFD52B" for Color. */
public String getSubStatNameFormatting(boolean topStat, boolean serverStat, boolean isStyle) {
return getStringFromConfig(topStat, serverStat, isStyle, "#FFD52B", "sub-stat-names");
public String getSubStatNameFormatting(CommandOption selection, boolean isStyle) {
return getStringFromConfig(selection, isStyle, "#FFD52B", "sub-stat-names");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "#55AAFF" or "#ADE7FF" for Color (for the top or individual color). */
public String getStatNumberFormatting(boolean topStat, boolean serverStat, boolean isStyle) {
String def = topStat ? "#55AAFF" : "#ADE7FF";
return getStringFromConfig(topStat, serverStat, isStyle, def,"stat-numbers");
and "#55AAFF" or "#ADE7FF" for Color (for the top or individual/server color). */
public String getStatNumberFormatting(CommandOption selection, boolean isStyle) {
String def;
if (selection == CommandOption.TOP) {
def = "#55AAFF";
}
else {
def = "#ADE7FF";
}
return getStringFromConfig(selection, isStyle, def,"stat-numbers");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "yellow" for Color. */
public String getTitleFormatting(boolean topStat, boolean isStyle) {
return getStringFromConfig(topStat, (!topStat), isStyle, "yellow", "title");
public String getTitleFormatting(CommandOption selection, boolean isStyle) {
return getStringFromConfig(selection, isStyle, "yellow", "title");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "gold" for Color. */
public String getTitleNumberFormatting(boolean isStyle) {
return getStringFromConfig(true, false, isStyle, "gold", "title-number");
return getStringFromConfig(CommandOption.TOP, isStyle, "gold", "title-number");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "#FFB80E" for Color. */
public String getServerNameFormatting(boolean isStyle) {
return getStringFromConfig(false, true, isStyle, "#FFB80E", "server-name");
return getStringFromConfig(CommandOption.SERVER, isStyle, "#FFB80E", "server-name");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "gold" for Color. */
public String getRankNumberFormatting(boolean isStyle) {
return getStringFromConfig(true, false, isStyle, "gold", "rank-numbers");
return getStringFromConfig(CommandOption.TOP, isStyle, "gold", "rank-numbers");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are "none" for Style,
and "dark_gray" for Color. */
public String getDotsFormatting(boolean isStyle) {
return getStringFromConfig(true, false, isStyle, "dark_gray", "dots");
return getStringFromConfig(CommandOption.TOP, isStyle, "dark_gray", "dots");
}
/** Returns the config value for a color or style option in string-format, the supplied default value, or null if no configSection was found. */
private @Nullable String getStringFromConfig(boolean topStat, boolean serverStat, boolean isStyle, String def, String pathName){
private @Nullable String getStringFromConfig(CommandOption selection, boolean isStyle, String def, String pathName){
String path = isStyle ? pathName + "-style" : pathName;
String defaultValue = isStyle ? "none" : def;
ConfigurationSection section = getRelevantSection(topStat, serverStat);
ConfigurationSection section = getRelevantSection(selection);
return section != null ? section.getString(path, defaultValue) : null;
}
/** Returns the config section that contains the relevant color or style option. */
private @Nullable ConfigurationSection getRelevantSection(boolean topStat, boolean serverStat) {
if (topStat) {
return config.getConfigurationSection("top-list");
}
else if (serverStat) {
return config.getConfigurationSection("total-server");
}
else {
return config.getConfigurationSection("individual-statistics");
private @Nullable ConfigurationSection getRelevantSection(CommandOption selection) {
switch (selection) {
case TOP -> {
return config.getConfigurationSection("top-list");
}
case PLAYER -> {
return config.getConfigurationSection("individual-statistics");
}
case SERVER -> {
return config.getConfigurationSection("total-server");
}
default -> {
return null;
}
}
}

View File

@ -11,6 +11,7 @@ import com.google.common.collect.ImmutableList;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@ -93,7 +94,7 @@ public class StatThread extends Thread {
testFile.logRunCount(true);
adventure.sender(sender).sendMessage(messageFactory.unknownError());
} catch (Exception e) {
sender.sendMessage(messageFactory.formatExceptions(e.toString()));
adventure.sender(sender).sendMessage(messageFactory.formatExceptions(e.toString()));
}
}
@ -106,7 +107,7 @@ public class StatThread extends Thread {
plugin.logTimeTaken("StatThread", "calculating individual stat", time);
} catch (UnsupportedOperationException | NullPointerException e) {
sender.sendMessage(messageFactory.formatExceptions(e.getMessage()));
adventure.sender(sender).sendMessage(messageFactory.formatExceptions(e.getMessage()));
}
}
}
@ -123,7 +124,7 @@ public class StatThread extends Thread {
}
//invokes a bunch of worker pool threads to divide and conquer (get the statistics for all players in the list)
private ConcurrentHashMap<String, Integer> getAllStats() throws ConcurrentModificationException, NullPointerException {
private @NotNull ConcurrentHashMap<String, Integer> getAllStats() throws ConcurrentModificationException, NullPointerException {
long time = System.currentTimeMillis();
ConcurrentHashMap<String, Integer> playerStats = new ConcurrentHashMap<>((int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05));
@ -151,28 +152,30 @@ public class StatThread extends Thread {
//gets the actual statistic data for an individual player
private int getIndividualStat() throws UnsupportedOperationException, NullPointerException {
OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(request.getPlayerName());
switch (request.getStatType()) {
case UNTYPED -> {
return player.getStatistic(request.getStatEnum());
}
case ENTITY -> {
return player.getStatistic(request.getStatEnum(), request.getEntity());
}
case BLOCK -> {
return player.getStatistic(request.getStatEnum(), request.getBlock());
}
case ITEM -> {
return player.getStatistic(request.getStatEnum(), request.getItem());
}
default -> {
if (request.getStatType() != null) {
throw new UnsupportedOperationException("PlayerStats is not familiar with this statistic type - please check if you are using the latest version of the plugin!");
if (player != null) {
switch (request.getStatType()) {
case UNTYPED -> {
return player.getStatistic(request.getStatEnum());
}
else {
throw new NullPointerException("Trying to calculate a statistic of which the type is null - is this a valid statistic?");
case ENTITY -> {
return player.getStatistic(request.getStatEnum(), request.getEntity());
}
case BLOCK -> {
return player.getStatistic(request.getStatEnum(), request.getBlock());
}
case ITEM -> {
return player.getStatistic(request.getStatEnum(), request.getItem());
}
default -> {
if (request.getStatType() != null) {
throw new UnsupportedOperationException("PlayerStats is not familiar with this statistic type - please check if you are using the latest version of the plugin!");
}
else {
throw new NullPointerException("Trying to calculate a statistic of which the type is null - is this a valid statistic?");
}
}
}
}
throw new NullPointerException("The player you are trying to request either does not exist, or is not on the list for statistic lookups!");
}
}

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.utils;
import com.gmail.artemis.the.gr8.playerstats.enums.CommandOption;
import com.gmail.artemis.the.gr8.playerstats.filehandlers.ConfigHandler;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
@ -57,8 +58,8 @@ public class MessageFactory {
: getPluginPrefix().append(text("Calculating statistics, this may take a few moments...").color(msgColor));
}
public String formatExceptions(String exception) {
return getPluginPrefix() + exception;
public TextComponent formatExceptions(String exception) {
return getPluginPrefix().append(text(exception).color(msgColor));
}
public TextComponent missingStatName() {
@ -141,7 +142,7 @@ public class MessageFactory {
.append(text(" | ").color(arguments))
.append(text("server").color(arguments)
.hoverEvent(HoverEvent.showText(
text("See the combined total for everyone on the server").color(hoverBaseColor))))
text("See the combined total for everyone on your server").color(hoverBaseColor))))
.append(text(" | ").color(arguments))
.append(text("top").color(arguments)
.hoverEvent(HoverEvent.showText(
@ -159,10 +160,10 @@ public class MessageFactory {
public TextComponent formatPlayerStat(String playerName, String statName, String subStatEntryName, int stat) {
TextComponent.Builder singleStat = Component.text();
singleStat.append(playerNameComponent(playerName + ": ", false))
.append(statNumberComponent(stat, false)).append(space())
.append(statNameComponent(statName, false))
.append(subStatNameComponent(subStatEntryName, false));
singleStat.append(playerNameComponent(CommandOption.PLAYER, playerName + ": "))
.append(statNumberComponent(CommandOption.PLAYER, stat)).append(space())
.append(statNameComponent(CommandOption.PLAYER, statName))
.append(subStatNameComponent(CommandOption.PLAYER, subStatEntryName));
return singleStat.build();
}
@ -171,10 +172,10 @@ public class MessageFactory {
TextComponent.Builder topList = Component.text();
topList.append(newline()).append(getPluginPrefix())
.append(titleComponent(true, "Top")).append(space())
.append(titleComponent(CommandOption.TOP, "Top")).append(space())
.append(titleNumberComponent(topStats.size())).append(space())
.append(statNameComponent(statName, true)).append(space())
.append(subStatNameComponent(subStatEntryName, true));
.append(statNameComponent(CommandOption.TOP, statName)).append(space())
.append(subStatNameComponent(CommandOption.TOP, subStatEntryName));
boolean useDots = config.useDots();
Set<String> playerNames = topStats.keySet();
@ -186,7 +187,7 @@ public class MessageFactory {
topList.append(newline())
.append(rankingNumberComponent(count + ". "))
.append(playerNameComponent(playerName, true));
.append(playerNameComponent(CommandOption.TOP, playerName));
if (useDots) {
topList.append(space());
@ -200,23 +201,24 @@ public class MessageFactory {
}
}
else {
topList.append(playerNameComponent(":", true));
topList.append(playerNameComponent(CommandOption.TOP, ":"));
}
topList.append(space()).append(statNumberComponent(topStats.get(playerName), true));
topList.append(space()).append(statNumberComponent(CommandOption.TOP, topStats.get(playerName)));
}
return topList.build();
}
public TextComponent formatServerStat(String statName, String subStatEntry, int stat) {
TextComponent.Builder serverStat = Component.text();
serverStat.append(titleComponent(false, "All"))
serverStat.append(titleComponent(CommandOption.SERVER, "Total for"))
.append(space())
.append(statNameComponent(statName, true))
.append(serverNameComponent())
.append(space())
.append(subStatNameComponent(subStatEntry, true))
.append(titleComponent(false, "on this server:"))
.append(statNumberComponent(CommandOption.SERVER, stat))
.append(space())
.append(statNumberComponent(stat, true));
.append(statNameComponent(CommandOption.SERVER, statName))
.append(space())
.append(subStatNameComponent(CommandOption.SERVER, subStatEntry));
return serverStat.build();
}
@ -239,62 +241,67 @@ public class MessageFactory {
return subStat;
}
private TextComponent playerNameComponent(String playerName, boolean topStat) {
NamedTextColor defaultColor = topStat ? NamedTextColor.GREEN : NamedTextColor.GOLD;
TextComponent.Builder player = applyColor(
config.getPlayerNameFormatting(topStat, false), playerName, defaultColor);
return applyStyle(config.getPlayerNameFormatting(topStat, true), player).build();
private TextComponent playerNameComponent(CommandOption selection, String playerName) {
return getComponent(playerName,
getColorFromString(config.getPlayerNameFormatting(selection, false)),
getStyleFromString(config.getPlayerNameFormatting(selection, true)));
}
private TextComponent statNameComponent(String statName, boolean topStat) {
TextComponent.Builder stat = applyColor(
config.getStatNameFormatting(topStat, false, false), statName.toLowerCase().replace("_", " "), NamedTextColor.YELLOW);
return applyStyle(config.getStatNameFormatting(topStat, false, true), stat).build();
private TextComponent statNameComponent(CommandOption selection, String statName) {
return getComponent(statName.toLowerCase().replace("_", " "),
getColorFromString(config.getStatNameFormatting(selection, false)),
getStyleFromString(config.getStatNameFormatting(selection, true)));
}
private TextComponent subStatNameComponent(String subStatName, boolean topStat) {
String subStatString = subStatName != null ?
"(" + subStatName.toLowerCase().replace("_", " ") + ") " : "";
TextComponent.Builder subStat = applyColor(
config.getSubStatNameFormatting(topStat, false, false), subStatString, NamedTextColor.YELLOW);
return applyStyle(config.getSubStatNameFormatting(topStat, false,true), subStat).build();
private TextComponent subStatNameComponent(CommandOption selection, String subStatName) {
if (subStatName == null) {
return empty();
}
else {
return getComponent("(" + subStatName.toLowerCase().replace("_", " ") + ")",
getColorFromString(config.getSubStatNameFormatting(selection, false)),
getStyleFromString(config.getSubStatNameFormatting(selection, true)))
.append(space());
}
}
private TextComponent statNumberComponent(int statNumber, boolean topStat) {
TextComponent.Builder number = applyColor(
config.getStatNumberFormatting(topStat, false, false), statNumber + "", NamedTextColor.LIGHT_PURPLE);
return applyStyle(config.getStatNumberFormatting(topStat, false, true), number).build();
private TextComponent statNumberComponent(CommandOption selection, int number) {
return getComponent(number + "",
getColorFromString(config.getStatNumberFormatting(selection, false)),
getStyleFromString(config.getStatNumberFormatting(selection, true)));
}
private TextComponent titleComponent(boolean topStat, String content) {
TextComponent.Builder server = applyColor(config.getTitleFormatting(topStat, false), content, NamedTextColor.YELLOW);
return applyStyle(config.getTitleFormatting(topStat, true), server).build();
private TextComponent titleComponent(CommandOption selection, String content) {
return getComponent(content,
getColorFromString(config.getTitleFormatting(selection, false)),
getStyleFromString(config.getTitleFormatting(selection, true)));
}
private TextComponent titleNumberComponent(int number) {
return getComponent(
number + "",
return getComponent(number + "",
getColorFromString(config.getTitleNumberFormatting(false)),
getStyleFromString(config.getTitleNumberFormatting(true)));
}
private TextComponent serverNameComponent() {
return getComponent(config.getServerName() + ":",
getColorFromString(config.getServerNameFormatting(false)),
getStyleFromString(config.getServerNameFormatting(true)));
}
private TextComponent rankingNumberComponent(String number) {
return getComponent(
number,
return getComponent(number,
getColorFromString(config.getRankNumberFormatting(false)),
getStyleFromString(config.getRankNumberFormatting(true)));
}
private TextComponent dotsComponent(String dots) {
return getComponent(
dots,
return getComponent(dots,
getColorFromString(config.getDotsFormatting(false)),
getStyleFromString(config.getDotsFormatting(true)));
}
private TextComponent getComponent(String content, TextColor color, @Nullable TextDecoration style) {
Bukkit.getLogger().info("Style = " + style);
return style == null ? text(content).color(color) : text(content).color(color).decoration(style, TextDecoration.State.TRUE);
}
@ -321,69 +328,15 @@ public class MessageFactory {
}
private @Nullable TextDecoration getStyleFromString(String configString) {
if (configString != null) {
if (configString.equalsIgnoreCase("none")) {
return null;
}
else if (configString.equalsIgnoreCase("bold")) {
return TextDecoration.BOLD;
}
else if (configString.equalsIgnoreCase("italic")) {
return TextDecoration.ITALIC;
}
else if (configString.equalsIgnoreCase("magic")) {
return TextDecoration.OBFUSCATED;
}
else if (configString.equalsIgnoreCase("strikethrough")) {
return TextDecoration.STRIKETHROUGH;
}
else if (configString.equalsIgnoreCase("underlined")) {
return TextDecoration.UNDERLINED;
}
if (configString.equalsIgnoreCase("none")) {
return null;
}
return null;
}
private TextComponent.Builder applyColor(String configString, String content, NamedTextColor defaultColor) {
TextComponent.Builder component = Component.text();
if (configString != null) {
try {
if (configString.contains("#")) {
return component.content(content).color(TextColor.fromHexString(configString));
}
else {
return component.content(content).color(getTextColorByName(configString));
}
}
catch (IllegalArgumentException | NullPointerException exception) {
Bukkit.getLogger().warning(exception.toString());
}
else if (configString.equalsIgnoreCase("magic")) {
return TextDecoration.OBFUSCATED;
}
return component.content(content).colorIfAbsent(defaultColor);
}
private TextComponent.Builder applyStyle(String configString, TextComponent.Builder component) {
if (configString != null) {
if (configString.equalsIgnoreCase("none")) {
return component;
}
else if (configString.equalsIgnoreCase("bold")) {
return component.decoration(TextDecoration.BOLD, TextDecoration.State.TRUE);
}
else if (configString.equalsIgnoreCase("italic")) {
return component.decoration(TextDecoration.ITALIC, TextDecoration.State.TRUE);
}
else if (configString.equalsIgnoreCase("magic")) {
return component.decoration(TextDecoration.OBFUSCATED, TextDecoration.State.TRUE);
}
else if (configString.equalsIgnoreCase("strikethrough")) {
return component.decoration(TextDecoration.STRIKETHROUGH, TextDecoration.State.TRUE);
}
else if (configString.equalsIgnoreCase("underlined")) {
return component.decoration(TextDecoration.UNDERLINED, TextDecoration.State.TRUE);
}
else {
Index<String, TextDecoration> styles = TextDecoration.NAMES;
return styles.value(configString);
}
return component;
}
}

View File

@ -2,6 +2,8 @@ package com.gmail.artemis.the.gr8.playerstats.utils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -39,9 +41,14 @@ public class OfflinePlayerHandler {
/**
* Uses the playerName to get the player's UUID from a private HashMap, and uses the UUID to get the corresponding OfflinePlayer Object.
* @param playerName name of the target player
* @return OfflinePlayer (if this player is on the list)
* @return OfflinePlayer (if this player is on the list, otherwise null)
*/
public static OfflinePlayer getOfflinePlayer(String playerName) {
return Bukkit.getOfflinePlayer(offlinePlayerUUIDs.get(playerName));
public static @Nullable OfflinePlayer getOfflinePlayer(String playerName) {
if (offlinePlayerUUIDs.get(playerName) != null) {
return Bukkit.getOfflinePlayer(offlinePlayerUUIDs.get(playerName));
}
else {
return null;
}
}
}