Made EnumHandler not static, made update-settings-methods static to remove unnecessary classes in constructors

This commit is contained in:
Artemis-the-gr8 2022-07-26 16:13:11 +02:00
parent b361918ca3
commit 9bf4e25750
16 changed files with 187 additions and 170 deletions

View File

@ -11,6 +11,7 @@ import com.gmail.artemis.the.gr8.playerstats.listeners.JoinListener;
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager; import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
import com.gmail.artemis.the.gr8.playerstats.statistic.RequestManager; import com.gmail.artemis.the.gr8.playerstats.statistic.RequestManager;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager; import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
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.OfflinePlayerHandler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
@ -33,20 +34,21 @@ public final class Main extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
//TODO fix (move these two into initializeMainClasses also, and remove all the Main.get... methods) //TODO fix (move these two into initializeMainClasses also, and remove all the Main.get... methods)
Metrics metrics = new Metrics(this, 15923); new Metrics(this, 15923);
//first get an instance of all the classes that need to be passed along to different classes //first get an instance of all the classes that need to be passed along to different classes
ConfigHandler config = new ConfigHandler(this); ConfigHandler config = new ConfigHandler(this);
EnumHandler enumHandler = new EnumHandler();
OfflinePlayerHandler offlinePlayerHandler = new OfflinePlayerHandler(); OfflinePlayerHandler offlinePlayerHandler = new OfflinePlayerHandler();
//initialize all the Managers and the API //initialize all the Managers and the API
initializeMainClasses(config, offlinePlayerHandler); initializeMainClasses(config, enumHandler, offlinePlayerHandler);
//register all commands and the tabCompleter //register all commands and the tabCompleter
PluginCommand statcmd = this.getCommand("statistic"); PluginCommand statcmd = this.getCommand("statistic");
if (statcmd != null) { if (statcmd != null) {
statcmd.setExecutor(new StatCommand(outputManager, threadManager, requestManager)); statcmd.setExecutor(new StatCommand(outputManager, threadManager, requestManager));
statcmd.setTabCompleter(new TabCompleter(offlinePlayerHandler)); statcmd.setTabCompleter(new TabCompleter(enumHandler, offlinePlayerHandler));
} }
PluginCommand reloadcmd = this.getCommand("statisticreload"); PluginCommand reloadcmd = this.getCommand("statisticreload");
if (reloadcmd != null) reloadcmd.setExecutor(new ReloadCommand(threadManager)); if (reloadcmd != null) reloadcmd.setExecutor(new ReloadCommand(threadManager));
@ -83,42 +85,14 @@ public final class Main extends JavaPlugin {
return playerStatsAPI; return playerStatsAPI;
} }
public static @NotNull OutputManager getOutputManager() throws IllegalStateException { private void initializeMainClasses(ConfigHandler config, EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler) {
if (outputManager == null) {
throw new IllegalStateException("The OutputManager is not loaded! Is PlayerStats enabled?");
}
return outputManager;
}
public static @NotNull ShareManager getShareManager() throws IllegalStateException {
if (shareManager == null) {
throw new IllegalStateException("The ShareManager is not loaded! Is PlayerStats enabled?");
}
return shareManager;
}
public static @NotNull StatManager getStatManager() throws IllegalStateException {
if (statManager == null) {
throw new IllegalStateException("The StatManager is not loaded! Is PlayerStats enabled?");
}
return statManager;
}
public static @NotNull ThreadManager getThreadManager() throws IllegalStateException {
if (threadManager == null) {
throw new IllegalStateException("The ThreadManager is not loaded! Is PlayerStats enabled?");
}
return threadManager;
}
private void initializeMainClasses(ConfigHandler config, OfflinePlayerHandler offlinePlayerHandler) {
adventure = BukkitAudiences.create(this); adventure = BukkitAudiences.create(this);
shareManager = new ShareManager(config); shareManager = new ShareManager(config);
statManager = new StatManager(offlinePlayerHandler, config.getTopListMaxSize()); statManager = new StatManager(offlinePlayerHandler, config.getTopListMaxSize());
outputManager = new OutputManager(getAdventure(), config, shareManager); outputManager = new OutputManager(getAdventure(), config, shareManager);
requestManager = new RequestManager(offlinePlayerHandler, outputManager); requestManager = new RequestManager(enumHandler, offlinePlayerHandler, outputManager);
threadManager = new ThreadManager(config, statManager, outputManager, offlinePlayerHandler); threadManager = new ThreadManager(config, statManager, outputManager);
playerStatsAPI = new PlayerStatsAPI(requestManager, statManager, outputManager); playerStatsAPI = new PlayerStatsAPI(requestManager, statManager, outputManager);
} }

View File

@ -27,10 +27,10 @@ public final class ShareManager {
private static boolean isEnabled; private static boolean isEnabled;
private static int waitingTime; private static int waitingTime;
private volatile AtomicInteger resultID; private static volatile AtomicInteger resultID;
private ConcurrentHashMap<UUID, StatResult> statResultQueue; private static ConcurrentHashMap<UUID, StatResult> statResultQueue;
private ConcurrentHashMap<String, Instant> shareTimeStamp; private static ConcurrentHashMap<String, Instant> shareTimeStamp;
private ArrayBlockingQueue<UUID> sharedResults; private static ArrayBlockingQueue<UUID> sharedResults;
public ShareManager(ConfigHandler config) { public ShareManager(ConfigHandler config) {
updateSettings(config); updateSettings(config);
@ -40,7 +40,7 @@ public final class ShareManager {
return isEnabled; return isEnabled;
} }
public synchronized void updateSettings(ConfigHandler config) { public static synchronized void updateSettings(ConfigHandler config) {
isEnabled = config.allowStatSharing() && config.useHoverText(); isEnabled = config.allowStatSharing() && config.useHoverText();
waitingTime = config.getStatShareWaitingTime(); waitingTime = config.getStatShareWaitingTime();

View File

@ -27,18 +27,16 @@ public final class ThreadManager {
private static ConfigHandler config; private static ConfigHandler config;
private static OutputManager outputManager; private static OutputManager outputManager;
private static StatManager statManager; private static StatManager statManager;
private final OfflinePlayerHandler offlinePlayerHandler;
private ReloadThread lastActiveReloadThread; private ReloadThread lastActiveReloadThread;
private StatThread lastActiveStatThread; private StatThread lastActiveStatThread;
private final HashMap<String, Thread> statThreads; private final HashMap<String, Thread> statThreads;
private static long lastRecordedCalcTime; private static long lastRecordedCalcTime;
public ThreadManager(ConfigHandler config, StatManager statManager, OutputManager outputManager, OfflinePlayerHandler offlinePlayerHandler) { public ThreadManager(ConfigHandler config, StatManager statManager, OutputManager outputManager) {
ThreadManager.config = config; ThreadManager.config = config;
ThreadManager.outputManager = outputManager; ThreadManager.outputManager = outputManager;
ThreadManager.statManager = statManager; ThreadManager.statManager = statManager;
this.offlinePlayerHandler = offlinePlayerHandler;
statThreads = new HashMap<>(); statThreads = new HashMap<>();
statThreadID = 0; statThreadID = 0;
@ -56,7 +54,7 @@ public final class ThreadManager {
if (lastActiveReloadThread == null || !lastActiveReloadThread.isAlive()) { if (lastActiveReloadThread == null || !lastActiveReloadThread.isAlive()) {
reloadThreadID += 1; reloadThreadID += 1;
lastActiveReloadThread = new ReloadThread(config, outputManager, offlinePlayerHandler, reloadThreadID, lastActiveStatThread, sender); lastActiveReloadThread = new ReloadThread(config, outputManager, reloadThreadID, lastActiveStatThread, sender);
lastActiveReloadThread.start(); lastActiveReloadThread.start();
} }
else { else {

View File

@ -1,14 +1,16 @@
package com.gmail.artemis.the.gr8.playerstats.api; package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.Main; import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.LanguageKeyHandler;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.StringUtils;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.*;
import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Statistic; import org.bukkit.Statistic;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
@ -16,8 +18,6 @@ import org.jetbrains.annotations.NotNull;
import java.util.Locale; import java.util.Locale;
import static net.kyori.adventure.translation.GlobalTranslator.renderer;
/** This is the outgoing API that you can use to access the core functionality of PlayerStats. /** This is the outgoing API that you can use to access the core functionality of PlayerStats.
To work with it, you need to call PlayerStats.{@link #getAPI()} to get an instance of {@link PlayerStatsAPI}. To work with it, you need to call PlayerStats.{@link #getAPI()} to get an instance of {@link PlayerStatsAPI}.
You can then use this object to access any of the further methods. You can then use this object to access any of the further methods.
@ -48,48 +48,60 @@ public interface PlayerStats {
/** Turns a TextComponent into its String representation. If you don't want to work with /** Turns a TextComponent into its String representation. If you don't want to work with
Adventure's TextComponents, you can call this method to turn any stat-result into a String. Adventure's TextComponents, you can call this method to turn any stat-result into a String.
@return a String representation of this TextComponent, without color and style, but with line-breaks*/ @return a String representation of this TextComponent, without hover/click events, but with color, style and formatting */
default String statResultComponentToString(TextComponent statResult) { default String statResultComponentToString(TextComponent statResult) {
return LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().build().serialize(statResult); ComponentFlattener flattener = ComponentFlattener.basic().toBuilder()
.mapper(TranslatableComponent.class, trans ->
StringUtils.prettify(
LanguageKeyHandler.extractName(
trans.key())))
.build();
return LegacyComponentSerializer.builder()
.hexColors()
.useUnusualXRepeatedCharacterHexFormat()
.flattener(flattener)
.build()
.serialize(statResult);
} }
/** Get a formatted player-statistic of Statistic.Type UNTYPED. /** Get a formatted player-statistic of Statistic.Type Untyped.
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] <br>[player-name]: [number] [stat-name]
@throws NullPointerException if statistic or playerName is null*/ @throws NullPointerException if statistic or playerName is null*/
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull String playerName) throws NullPointerException; TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull String playerName) throws NullPointerException;
/** Get a formatted player-statistic of Statistic.Type BLOCK or ITEM. /** Get a formatted player-statistic of Statistic.Type Block or Item.
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] [sub-stat-name] <br>[player-name]: [number] [stat-name] [sub-stat-name]
@throws NullPointerException if statistic, material or playerName is null*/ @throws NullPointerException if statistic, material or playerName is null*/
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull Material material, @NotNull String playerName) throws NullPointerException; TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull Material material, @NotNull String playerName) throws NullPointerException;
/** Get a formatted player-statistic of Statistic.Type ENTITY. /** Get a formatted player-statistic of Statistic.Type Entity.
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] [sub-stat-name] <br>[player-name]: [number] [stat-name] [sub-stat-name]
@throws NullPointerException if statistic, entity or playerName is null*/ @throws NullPointerException if statistic, entity or playerName is null*/
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull EntityType entity, @NotNull String playerName) throws NullPointerException; TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull EntityType entity, @NotNull String playerName) throws NullPointerException;
/** Get a formatted server-statistic of Statistic.Type UNTYPED. Not recommended to call this from the main Thread (see class description). /** Get a formatted server-statistic of Statistic.Type Untyped. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] <br>[Total on] [server-name]: [number] [stat-name]
@throws NullPointerException if statistic is null*/ @throws NullPointerException if statistic is null*/
TextComponent getServerStat(@NotNull Statistic statistic) throws NullPointerException; TextComponent getServerStat(@NotNull Statistic statistic) throws NullPointerException;
/** Get a formatted server-statistic of Statistic.Type BLOCK or ITEM. Not recommended to call this from the main Thread (see class description). /** Get a formatted server-statistic of Statistic.Type Block or Item. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name] <br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]
@throws NullPointerException if statistic or material is null*/ @throws NullPointerException if statistic or material is null*/
TextComponent getServerStat(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException; TextComponent getServerStat(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException;
/** Get a formatted server-statistic of Statistic.Type ENTITY. Not recommended to call this from the main Thread (see class description). /** Get a formatted server-statistic of Statistic.Type Entity. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name] <br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]
@throws NullPointerException if statistic or entity is null*/ @throws NullPointerException if statistic or entity is null*/
TextComponent getServerStat(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException; TextComponent getServerStat(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException;
/** Get a formatted top-statistic of Statistic.Type UNTYPED. Not recommended to call this from the main Thread (see class description). /** Get a formatted top-statistic of Statistic.Type Untyped. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[PlayerStats] [Top 10] [stat-name] <br>[PlayerStats] [Top 10] [stat-name]
<br> [1.] [player-name] [number] <br> [1.] [player-name] [number]
@ -98,7 +110,7 @@ public interface PlayerStats {
@throws NullPointerException if statistic is null*/ @throws NullPointerException if statistic is null*/
TextComponent getTopStats(@NotNull Statistic statistic) throws NullPointerException; TextComponent getTopStats(@NotNull Statistic statistic) throws NullPointerException;
/** Get a formatted top-statistic of Statistic.Type BLOCK or ITEM. Not recommended to call this from the main Thread (see class description). /** Get a formatted top-statistic of Statistic.Type Block or Item. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name] <br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name]
<br> [1.] [player-name] [number] <br> [1.] [player-name] [number]
@ -107,7 +119,7 @@ public interface PlayerStats {
@throws NullPointerException if statistic or material is null*/ @throws NullPointerException if statistic or material is null*/
TextComponent getTopStats(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException; TextComponent getTopStats(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException;
/** Get a formatted top-statistic of Statistic.Type ENTITY. Not recommended to call this from the main Thread (see class description). /** Get a formatted top-statistic of Statistic.Type Entity. Don't call this from the main Thread (see class description)!
@return a TextComponent with the following parts: @return a TextComponent with the following parts:
<br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name] <br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name]
<br> [1.] [player-name] [number] <br> [1.] [player-name] [number]

View File

@ -1,13 +1,17 @@
package com.gmail.artemis.the.gr8.playerstats.commands; package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager; import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager; import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
import com.gmail.artemis.the.gr8.playerstats.statistic.RequestManager; import com.gmail.artemis.the.gr8.playerstats.statistic.RequestManager;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest; import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -36,16 +40,6 @@ public class StatCommand implements CommandExecutor {
outputManager.sendExamples(sender); outputManager.sendExamples(sender);
} }
else if (args[0].equalsIgnoreCase(">:(")) { else if (args[0].equalsIgnoreCase(">:(")) {
java.awt.Color color = new java.awt.Color(178, 102, 255);
// ChatColor one = ChatColor.of(color);
// TextComponent msg = new TextComponent(">:(((((");
// msg.setColor(one);
// sender.spigot().sendMessage(msg);
// sender.sendMessage("regular msg with ChatColor: " + one + ">:((((((");
// sender.sendMessage("regular msg Component.toLegacyText: " + msg.toLegacyText());
// sender.sendMessage("regular msg Component.toString: " + msg);
}
else if (args[0].equalsIgnoreCase(">:((")) {
Component msg = MiniMessage.miniMessage().deserialize("<gradient:#f74040:#FF6600:#f74040>fire demon</gradient>"); Component msg = MiniMessage.miniMessage().deserialize("<gradient:#f74040:#FF6600:#f74040>fire demon</gradient>");
String msgString = LegacyComponentSerializer.builder().hexColors().build().serialize(msg); String msgString = LegacyComponentSerializer.builder().hexColors().build().serialize(msg);
sender.sendMessage("LCS.hexColors(): " + msgString); sender.sendMessage("LCS.hexColors(): " + msgString);
@ -60,6 +54,16 @@ public class StatCommand implements CommandExecutor {
sender.sendMessage("LCS.hexColors().spigotformat...: " + msgString3); sender.sendMessage("LCS.hexColors().spigotformat...: " + msgString3);
MyLogger.logMsg(msgString3); MyLogger.logMsg(msgString3);
} }
else if (args[0].equalsIgnoreCase("test")) {
TranslatableComponent msg = Component.translatable(Statistic.ANIMALS_BRED.getKey().getNamespace() + "." + Statistic.ANIMALS_BRED.getKey().getKey());
TranslatableComponent msg2 = Component.translatable("stat." + Statistic.ANIMALS_BRED.getKey().getNamespace() + "." + Statistic.ANIMALS_BRED.getKey().getKey());
Main.getAdventure().console().sendMessage(msg);
Main.getAdventure().console().sendMessage(msg2);
MyLogger.logMsg("key to String: " + Statistic.KILL_ENTITY.getKey());
MyLogger.logMsg("key.getNamespace(): " + Statistic.KILL_ENTITY.getKey().getNamespace());
MyLogger.logMsg("key.getKey(): " + Statistic.KILL_ENTITY.getKey().getKey());
}
else { else {
StatRequest request = requestManager.generateRequest(sender, args); StatRequest request = requestManager.generateRequest(sender, args);
if (requestManager.validateRequest(request)) { if (requestManager.validateRequest(request)) {

View File

@ -14,14 +14,16 @@ import java.util.stream.Collectors;
public class TabCompleter implements org.bukkit.command.TabCompleter { public class TabCompleter implements org.bukkit.command.TabCompleter {
private final EnumHandler enumHandler;
private final OfflinePlayerHandler offlinePlayerHandler; private final OfflinePlayerHandler offlinePlayerHandler;
private final TabCompleteHelper tabCompleteHelper; private final TabCompleteHelper tabCompleteHelper;
private final List<String> commandOptions; private final List<String> commandOptions;
public TabCompleter(OfflinePlayerHandler o) { public TabCompleter(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler) {
offlinePlayerHandler = o; this.enumHandler = enumHandler;
tabCompleteHelper = new TabCompleteHelper(); this.offlinePlayerHandler = offlinePlayerHandler;
tabCompleteHelper = new TabCompleteHelper(enumHandler);
commandOptions = new ArrayList<>(); commandOptions = new ArrayList<>();
commandOptions.add("top"); commandOptions.add("top");
@ -50,7 +52,7 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
else { //after checking if args[0] is a viable statistic, suggest substatistic OR commandOptions else { //after checking if args[0] is a viable statistic, suggest substatistic OR commandOptions
String previousArg = args[args.length -2]; String previousArg = args[args.length -2];
if (EnumHandler.isStatistic(previousArg)) { if (enumHandler.isStatistic(previousArg)) {
Statistic stat = EnumHandler.getStatEnum(previousArg); Statistic stat = EnumHandler.getStatEnum(previousArg);
if (stat != null) { if (stat != null) {
tabSuggestions = getTabSuggestions(getRelevantList(stat), currentArg); tabSuggestions = getTabSuggestions(getRelevantList(stat), currentArg);
@ -60,7 +62,7 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
//if previous arg = "player" //if previous arg = "player"
else if (previousArg.equalsIgnoreCase("player")) { else if (previousArg.equalsIgnoreCase("player")) {
if (args.length >= 3 && EnumHandler.isEntityStatistic(args[args.length-3])) { if (args.length >= 3 && enumHandler.isEntityStatistic(args[args.length-3])) {
tabSuggestions = commandOptions; //if arg before "player" was entity-stat, suggest commandOptions tabSuggestions = commandOptions; //if arg before "player" was entity-stat, suggest commandOptions
} }
else { //otherwise "player" is target-flag: suggest playerNames else { //otherwise "player" is target-flag: suggest playerNames
@ -69,7 +71,7 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
} }
//after a substatistic, suggest commandOptions //after a substatistic, suggest commandOptions
else if (EnumHandler.isSubStatEntry(previousArg)) { else if (enumHandler.isSubStatEntry(previousArg)) {
tabSuggestions = commandOptions; tabSuggestions = commandOptions;
} }
} }
@ -78,7 +80,7 @@ public class TabCompleter implements org.bukkit.command.TabCompleter {
} }
private List<String> getFirstArgSuggestions(String currentArg) { private List<String> getFirstArgSuggestions(String currentArg) {
List<String> suggestions = EnumHandler.getStatNames(); List<String> suggestions = enumHandler.getStatNames();
suggestions.add("examples"); suggestions.add("examples");
suggestions.add("help"); suggestions.add("help");
return getTabSuggestions(suggestions, currentArg); return getTabSuggestions(suggestions, currentArg);

View File

@ -10,15 +10,17 @@ import java.util.stream.Collectors;
public final class TabCompleteHelper { public final class TabCompleteHelper {
private final EnumHandler enumHandler;
private static List<String> itemBrokenSuggestions; private static List<String> itemBrokenSuggestions;
private static List<String> entitySuggestions; private static List<String> entitySuggestions;
public TabCompleteHelper() { public TabCompleteHelper(EnumHandler enumHandler) {
this.enumHandler = enumHandler;
prepareLists(); prepareLists();
} }
public List<String> getAllItemNames() { public List<String> getAllItemNames() {
return EnumHandler.getItemNames(); return enumHandler.getItemNames();
} }
public List<String> getItemBrokenSuggestions() { public List<String> getItemBrokenSuggestions() {
@ -26,7 +28,7 @@ public final class TabCompleteHelper {
} }
public List<String> getAllBlockNames() { public List<String> getAllBlockNames() {
return EnumHandler.getBlockNames(); return enumHandler.getBlockNames();
} }
public List<String> getEntitySuggestions() { public List<String> getEntitySuggestions() {
@ -52,4 +54,4 @@ public final class TabCompleteHelper {
.map(String::toLowerCase) .map(String::toLowerCase)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View File

@ -10,7 +10,6 @@ import com.gmail.artemis.the.gr8.playerstats.msg.components.ExampleMessage;
import com.gmail.artemis.the.gr8.playerstats.msg.components.HelpMessage; import com.gmail.artemis.the.gr8.playerstats.msg.components.HelpMessage;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.*; import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.*;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest; import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
@ -90,7 +89,7 @@ public class MessageBuilder {
return componentFactory.pluginPrefix() return componentFactory.pluginPrefix()
.append(space()) .append(space())
.append(componentFactory.message().content( .append(componentFactory.message().content(
"Please add a valid " + EnumHandler.getSubStatTypeName(statType) + " to look up this statistic!")); "Please add a valid " + getSubStatTypeName(statType) + " to look up this statistic!"));
} }
public TextComponent missingPlayerName() { public TextComponent missingPlayerName() {
@ -106,7 +105,7 @@ public class MessageBuilder {
.append(componentFactory.messageAccent().content("\"" + subStatName + "\"")) .append(componentFactory.messageAccent().content("\"" + subStatName + "\""))
.append(space()) .append(space())
.append(componentFactory.message().content( .append(componentFactory.message().content(
"is not a valid " + EnumHandler.getSubStatTypeName(statType) + "!")); "is not a valid " + getSubStatTypeName(statType) + "!"));
} }
public TextComponent requestAlreadyRunning() { public TextComponent requestAlreadyRunning() {
@ -483,4 +482,16 @@ public class MessageBuilder {
return Component.space() return Component.space()
.append(componentFactory.statUnit(statName, null, selection)); .append(componentFactory.statUnit(statName, null, selection));
} }
/** Returns "block", "entity", "item", or "sub-statistic" if the provided Type is null. */
public static String getSubStatTypeName(Statistic.Type statType) {
String subStat = "sub-statistic";
if (statType == null) return subStat;
switch (statType) {
case BLOCK -> subStat = "block";
case ENTITY -> subStat = "entity";
case ITEM -> subStat = "item";
}
return subStat;
}
} }

View File

@ -46,7 +46,7 @@ public final class OutputManager implements StatFormatter {
prepareFunctions(); prepareFunctions();
} }
public void updateMessageWriters(ConfigHandler config) { public static void updateMessageWriters(ConfigHandler config) {
getMessageWriters(config); getMessageWriters(config);
} }
@ -145,7 +145,7 @@ public final class OutputManager implements StatFormatter {
} }
} }
private void getMessageWriters(ConfigHandler config) { private static void getMessageWriters(ConfigHandler config) {
boolean isBukkit = Bukkit.getName().equalsIgnoreCase("CraftBukkit"); boolean isBukkit = Bukkit.getName().equalsIgnoreCase("CraftBukkit");
if (config.useRainbowMode() || if (config.useRainbowMode() ||
(config.useFestiveFormatting() && LocalDate.now().getMonth().equals(Month.JUNE))) { (config.useFestiveFormatting() && LocalDate.now().getMonth().equals(Month.JUNE))) {

View File

@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.PluginColor;
import com.gmail.artemis.the.gr8.playerstats.enums.Target; import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import com.gmail.artemis.the.gr8.playerstats.enums.Unit; import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageBuilder; import com.gmail.artemis.the.gr8.playerstats.msg.MessageBuilder;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.LanguageKeyHandler;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.TranslatableComponent;
@ -206,10 +207,10 @@ public class ComponentFactory {
getStyleFromString(config.getStatNameDecoration(selection, true))); getStyleFromString(config.getStatNameDecoration(selection, true)));
TextComponent subStat = subStatNameTranslatable(subStatKey, selection); TextComponent subStat = subStatNameTranslatable(subStatKey, selection);
if (statKey.equalsIgnoreCase("stat_type.minecraft.killed")) { if (LanguageKeyHandler.isKeyForKillEntity(statKey)) {
return totalStatNameBuilder.append(killEntityBuilder(subStat)).build(); return totalStatNameBuilder.append(killEntityBuilder(subStat)).build();
} }
else if (statKey.equalsIgnoreCase("stat_type.minecraft.killed_by")) { else if (LanguageKeyHandler.isKeyForEntityKilledBy(statKey)) {
return totalStatNameBuilder.append(entityKilledByBuilder(subStat)).build(); return totalStatNameBuilder.append(entityKilledByBuilder(subStat)).build();
} }
else { else {

View File

@ -20,6 +20,36 @@ public final class LanguageKeyHandler {
statNameKeys = generateStatNameKeys(); statNameKeys = generateStatNameKeys();
} }
public static boolean isKeyForKillEntity(String statKey) {
return statKey.equalsIgnoreCase("stat_type.minecraft.killed");
}
public static boolean isKeyForEntityKilledBy(String statKey) {
return statKey.equalsIgnoreCase("stat_type.minecraft.killed_by");
}
public static String extractName(String nameSpacedKey) {
if (nameSpacedKey.equalsIgnoreCase("soundCategory.block")) {
return Unit.BLOCK.getLabel();
}
String toReplace = "";
if (nameSpacedKey.contains("stat")) {
if (nameSpacedKey.contains("type")) {
toReplace = "stat_type";
} else {
toReplace = "stat";
}
} else if (nameSpacedKey.contains("entity")) {
toReplace = "entity";
} else if (nameSpacedKey.contains("block")) {
toReplace = "block";
} else if (nameSpacedKey.contains("item")) {
toReplace = "item";
}
toReplace = toReplace + ".minecraft.";
return nameSpacedKey.replace(toReplace, "");
}
public String getStatKey(@NotNull Statistic statistic) { public String getStatKey(@NotNull Statistic statistic) {
if (statistic.getType() == Statistic.Type.UNTYPED) { if (statistic.getType() == Statistic.Type.UNTYPED) {
return "stat.minecraft." + statNameKeys.get(statistic); return "stat.minecraft." + statNameKeys.get(statistic);

View File

@ -1,6 +1,5 @@
package com.gmail.artemis.the.gr8.playerstats.reload; package com.gmail.artemis.the.gr8.playerstats.reload;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.ShareManager; import com.gmail.artemis.the.gr8.playerstats.ShareManager;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager; import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler; import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
@ -27,21 +26,15 @@ public class ReloadThread extends Thread {
private static ConfigHandler config; private static ConfigHandler config;
private static OutputManager outputManager; private static OutputManager outputManager;
private static ShareManager shareManager;
private final OfflinePlayerHandler offlinePlayerHandler;
private final int reloadThreadID; private final int reloadThreadID;
private final StatThread statThread; private final StatThread statThread;
private final CommandSender sender; private final CommandSender sender;
public ReloadThread(ConfigHandler c, OutputManager m, OfflinePlayerHandler o, int ID, @Nullable StatThread s, @Nullable CommandSender se) { public ReloadThread(ConfigHandler c, OutputManager m, int ID, @Nullable StatThread s, @Nullable CommandSender se) {
config = c; config = c;
outputManager = m; outputManager = m;
offlinePlayerHandler = o;
shareManager = Main.getShareManager();
reloadThreadID = ID; reloadThreadID = ID;
statThread = s; statThread = s;
@ -81,16 +74,16 @@ public class ReloadThread extends Thread {
} }
else { //during first start-up else { //during first start-up
MyLogger.setDebugLevel(config.getDebugLevel()); MyLogger.setDebugLevel(config.getDebugLevel());
offlinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers()); OfflinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
ThreadManager.recordCalcTime(System.currentTimeMillis() - time); ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
} }
} }
private void reloadEverything() { private void reloadEverything() {
MyLogger.setDebugLevel(config.getDebugLevel()); MyLogger.setDebugLevel(config.getDebugLevel());
outputManager.updateMessageWriters(config); OutputManager.updateMessageWriters(config);
offlinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers()); OfflinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
shareManager.updateSettings(config); ShareManager.updateSettings(config);
StatManager.updateSettings(config.getTopListMaxSize()); StatManager.updateSettings(config.getTopListMaxSize());
} }

View File

@ -18,10 +18,12 @@ import org.jetbrains.annotations.NotNull;
public class RequestManager implements RequestGenerator { public class RequestManager implements RequestGenerator {
private final EnumHandler enumHandler;
private final OfflinePlayerHandler offlinePlayerHandler; private final OfflinePlayerHandler offlinePlayerHandler;
private static OutputManager outputManager; private static OutputManager outputManager;
public RequestManager(OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) { public RequestManager(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) {
this.enumHandler = enumHandler;
this.offlinePlayerHandler = offlinePlayerHandler; this.offlinePlayerHandler = offlinePlayerHandler;
RequestManager.outputManager = outputManager; RequestManager.outputManager = outputManager;
} }
@ -30,11 +32,11 @@ public class RequestManager implements RequestGenerator {
StatRequest request = new StatRequest(sender); StatRequest request = new StatRequest(sender);
for (String arg : args) { for (String arg : args) {
//check for statName //check for statName
if (EnumHandler.isStatistic(arg) && request.getStatistic() == null) { if (enumHandler.isStatistic(arg) && request.getStatistic() == null) {
request.setStatistic(EnumHandler.getStatEnum(arg)); request.setStatistic(EnumHandler.getStatEnum(arg));
} }
//check for subStatEntry and playerFlag //check for subStatEntry and playerFlag
else if (EnumHandler.isSubStatEntry(arg)) { else if (enumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player") && !request.getPlayerFlag()) { if (arg.equalsIgnoreCase("player") && !request.getPlayerFlag()) {
request.setPlayerFlag(true); request.setPlayerFlag(true);
} }

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.statistic; package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.api.PlayerStats;
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage; import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
import com.gmail.artemis.the.gr8.playerstats.enums.Target; import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest; import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
@ -8,8 +9,6 @@ import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager; import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger; import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
@ -66,11 +65,8 @@ public class StatThread extends Thread {
case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request)); case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request));
}; };
if (request.isAPIRequest()) { if (request.isAPIRequest()) {
String msg = LegacyComponentSerializer.builder().hexColors().build().serialize(statResult); String msg = PlayerStats.getAPI().statResultComponentToString(statResult);
request.getCommandSender().sendMessage(msg); request.getCommandSender().sendMessage(msg);
String msg2 = LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().build().serialize(statResult);
request.getCommandSender().sendMessage(msg2);
} }
else { else {
outputManager.sendToCommandSender(request.getCommandSender(), statResult); outputManager.sendToCommandSender(request.getCommandSender(), statResult);

View File

@ -19,54 +19,27 @@ import java.util.stream.Stream;
and turn a name into its corresponding enum constant. */ and turn a name into its corresponding enum constant. */
public final class EnumHandler { public final class EnumHandler {
private final static List<String> blockNames; private static List<String> blockNames;
private final static List<String> entityNames; private static List<String> itemNames;
private final static List<String> itemNames; private static List<String> statNames;
private final static List<String> statNames; private static List<String> subStatNames;
private final static List<String> subStatNames;
static { public EnumHandler() {
blockNames = Arrays.stream(Material.values()) prepareLists();
.filter(Material::isBlock)
.map(Material::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
entityNames = Arrays.stream(EntityType.values())
.map(EntityType::toString)
.map(String::toLowerCase)
.filter(entityName -> !entityName.equalsIgnoreCase("unknown"))
.collect(Collectors.toList());
itemNames = Arrays.stream(Material.values())
.filter(Material::isItem)
.map(Material::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
subStatNames = Stream.of(blockNames, entityNames, itemNames)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
statNames = Arrays.stream(Statistic.values())
.map(Statistic::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
} }
/** Returns all block-names in lowercase */ /** Returns all block-names in lowercase */
public static List<String> getBlockNames() { public List<String> getBlockNames() {
return blockNames; return blockNames;
} }
/** Returns all item-names in lowercase*/ /** Returns all item-names in lowercase*/
public static List<String> getItemNames() { public List<String> getItemNames() {
return itemNames; return itemNames;
} }
/** Returns all statistic-names in lowercase */ /** Returns all statistic-names in lowercase */
public static List<String> getStatNames() { public List<String> getStatNames() {
return statNames; return statNames;
} }
@ -115,31 +88,50 @@ public final class EnumHandler {
/** Checks if string is a valid statistic /** Checks if string is a valid statistic
@param statName String, case-insensitive */ @param statName String, case-insensitive */
public static boolean isStatistic(@NotNull String statName) { public boolean isStatistic(@NotNull String statName) {
return statNames.contains(statName.toLowerCase()); return statNames.contains(statName.toLowerCase());
} }
/** Checks whether the given String equals the name of an entity-type statistic. */ /** Checks whether the given String equals the name of an entity-type statistic. */
public static boolean isEntityStatistic(String statName) { public boolean isEntityStatistic(String statName) {
return statName.equalsIgnoreCase(Statistic.ENTITY_KILLED_BY.toString()) || return statName.equalsIgnoreCase(Statistic.ENTITY_KILLED_BY.toString()) ||
statName.equalsIgnoreCase(Statistic.KILL_ENTITY.toString()); statName.equalsIgnoreCase(Statistic.KILL_ENTITY.toString());
} }
/** Checks if this statistic is a subStatEntry, meaning it is a block, item or entity /** Checks if this statistic is a subStatEntry, meaning it is a block, item or entity
@param statName String, case-insensitive*/ @param statName String, case-insensitive*/
public static boolean isSubStatEntry(@NotNull String statName) { public boolean isSubStatEntry(@NotNull String statName) {
return subStatNames.contains(statName.toLowerCase()); return subStatNames.contains(statName.toLowerCase());
} }
/** Returns "block", "entity", "item", or "sub-statistic" if the provided Type is null. */ private void prepareLists() {
public static String getSubStatTypeName(Statistic.Type statType) { List<String> entityNames = Arrays.stream(EntityType.values())
String subStat = "sub-statistic"; .map(EntityType::toString)
if (statType == null) return subStat; .map(String::toLowerCase)
switch (statType) { .filter(entityName -> !entityName.equalsIgnoreCase("unknown"))
case BLOCK -> subStat = "block"; .collect(Collectors.toList());
case ENTITY -> subStat = "entity";
case ITEM -> subStat = "item"; blockNames = Arrays.stream(Material.values())
} .filter(Material::isBlock)
return subStat; .map(Material::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
itemNames = Arrays.stream(Material.values())
.filter(Material::isItem)
.map(Material::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
subStatNames = Stream.of(blockNames, entityNames, itemNames)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
statNames = Arrays.stream(Statistic.values())
.map(Statistic::toString)
.map(String::toLowerCase)
.collect(Collectors.toList());
} }
} }

View File

@ -10,7 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
/** A utility class that deals with OfflinePlayers. It stores a list of all OfflinePlayer-names /** A utility class that deals with OfflinePlayers. It stores a list of all OfflinePlayer-names
that need to be included in statistic calculations, and can retrieve the corresponding OfflinePlayer that need to be included in statistic calculations, and can retrieve the corresponding OfflinePlayer
object for a given player-name.*/ object for a given player-name.*/
public class OfflinePlayerHandler { public final class OfflinePlayerHandler {
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs; private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
private static ArrayList<String> playerNames; private static ArrayList<String> playerNames;
@ -20,6 +20,16 @@ public class OfflinePlayerHandler {
playerNames = new ArrayList<>(); playerNames = new ArrayList<>();
} }
/**
* Get a new HashMap that stores the players to include in stat calculations.
* This HashMap is stored as a private variable in OfflinePlayerHandler.
* @param playerList ConcurrentHashMap with keys: playerNames and values: UUIDs
*/
public static void updateOfflinePlayerList(ConcurrentHashMap<String, UUID> playerList) {
offlinePlayerUUIDs = playerList;
playerNames = Collections.list(offlinePlayerUUIDs.keys());
}
/** Checks if a given playerName is on the private HashMap of players that should be included in statistic calculations /** Checks if a given playerName is on the private HashMap of players that should be included in statistic calculations
@param playerName String, case-sensitive */ @param playerName String, case-sensitive */
public boolean isRelevantPlayer(String playerName) { public boolean isRelevantPlayer(String playerName) {
@ -36,16 +46,6 @@ public class OfflinePlayerHandler {
return playerNames; return playerNames;
} }
/**
* Get a new HashMap that stores the players to include in stat calculations.
* This HashMap is stored as a private variable in OfflinePlayerHandler.
* @param playerList ConcurrentHashMap with keys: playerNames and values: UUIDs
*/
public void updateOfflinePlayerList(ConcurrentHashMap<String, UUID> playerList) {
offlinePlayerUUIDs = playerList;
playerNames = Collections.list(offlinePlayerUUIDs.keys());
}
/** /**
* Uses the playerName to get the player's UUID from a private HashMap, and uses the UUID to get the corresponding OfflinePlayer Object. * 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 * @param playerName name of the target player