mirror of
https://github.com/itHotL/PlayerStats.git
synced 2024-11-22 11:55:17 +01:00
Made ConfigHandler, LanguageKeyHandler, OfflinePlayerHandler and EnumHandler into singletons, merged RequestProcessor into RequestManager and wrote TabComplete logic (#88)
This commit is contained in:
parent
6c9e8b2b9d
commit
e158b4480d
@ -4,14 +4,13 @@ import com.artemis.the.gr8.playerstats.api.PlayerStats;
|
||||
import com.artemis.the.gr8.playerstats.api.StatFormatter;
|
||||
import com.artemis.the.gr8.playerstats.api.StatManager;
|
||||
import com.artemis.the.gr8.playerstats.commands.*;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestManager;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.listeners.JoinListener;
|
||||
import com.artemis.the.gr8.playerstats.msg.msgutils.LanguageKeyHandler;
|
||||
import com.artemis.the.gr8.playerstats.share.ShareManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestProcessor;
|
||||
import com.artemis.the.gr8.playerstats.utils.EnumHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||
@ -39,9 +38,8 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
private static ThreadManager threadManager;
|
||||
private static LanguageKeyHandler languageKeyHandler;
|
||||
private static OfflinePlayerHandler offlinePlayerHandler;
|
||||
private static EnumHandler enumHandler;
|
||||
|
||||
private static RequestManager statRequestManager;
|
||||
private static RequestManager requestManager;
|
||||
private static OutputManager outputManager;
|
||||
private static ShareManager shareManager;
|
||||
|
||||
@ -73,7 +71,7 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
languageKeyHandler.reload();
|
||||
offlinePlayerHandler.reload();
|
||||
outputManager.updateSettings();
|
||||
shareManager.updateSettings(config);
|
||||
shareManager.updateSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,19 +101,17 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
private void initializeMainClasses() {
|
||||
pluginInstance = this;
|
||||
playerStatsAPI = this;
|
||||
|
||||
adventure = BukkitAudiences.create(this);
|
||||
enumHandler = new EnumHandler();
|
||||
languageKeyHandler = new LanguageKeyHandler();
|
||||
config = new ConfigHandler();
|
||||
|
||||
offlinePlayerHandler = new OfflinePlayerHandler(config);
|
||||
shareManager = new ShareManager(config);
|
||||
outputManager = new OutputManager(adventure, config, languageKeyHandler);
|
||||
config = ConfigHandler.getInstance();
|
||||
languageKeyHandler = LanguageKeyHandler.getInstance();
|
||||
offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
|
||||
RequestProcessor requestProcessor = new RequestProcessor(offlinePlayerHandler, outputManager, shareManager);
|
||||
statRequestManager = new RequestManager(offlinePlayerHandler, requestProcessor);
|
||||
threadManager = new ThreadManager(this, config, outputManager, statRequestManager);
|
||||
outputManager = new OutputManager(adventure);
|
||||
shareManager = new ShareManager();
|
||||
|
||||
requestManager = new RequestManager(outputManager, shareManager);
|
||||
threadManager = new ThreadManager(this, outputManager);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,16 +119,16 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
* to the relevant commands.
|
||||
*/
|
||||
private void registerCommands() {
|
||||
TabCompleter tabCompleter = new TabCompleter(enumHandler, offlinePlayerHandler);
|
||||
TabCompleter tabCompleter = new TabCompleter();
|
||||
|
||||
PluginCommand statcmd = this.getCommand("statistic");
|
||||
if (statcmd != null) {
|
||||
statcmd.setExecutor(new StatCommand(outputManager, threadManager, config, offlinePlayerHandler, enumHandler));
|
||||
statcmd.setExecutor(new StatCommand(outputManager, threadManager));
|
||||
statcmd.setTabCompleter(tabCompleter);
|
||||
}
|
||||
PluginCommand excludecmd = this.getCommand("statisticexclude");
|
||||
if (excludecmd != null) {
|
||||
excludecmd.setExecutor(new ExcludeCommand(offlinePlayerHandler));
|
||||
excludecmd.setExecutor(new ExcludeCommand());
|
||||
excludecmd.setTabCompleter(tabCompleter);
|
||||
}
|
||||
|
||||
@ -177,7 +173,7 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
|
||||
@Override
|
||||
public StatManager getStatManager() {
|
||||
return statRequestManager;
|
||||
return requestManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.api;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestProcessor;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Creates an executable {@link StatRequest}. This Request holds all
|
||||
* the information PlayerStats needs to work with, and is used by the {@link RequestProcessor}
|
||||
* the information PlayerStats needs to work with, and is used
|
||||
* to get the desired statistic data.
|
||||
*/
|
||||
public interface RequestGenerator<T> {
|
||||
|
@ -11,8 +11,8 @@ public final class ExcludeCommand implements CommandExecutor {
|
||||
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
|
||||
public ExcludeCommand(OfflinePlayerHandler offlinePlayerHandler) {
|
||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||
public ExcludeCommand() {
|
||||
this.offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.commands;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.commands;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.api.RequestGenerator;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||
@ -32,16 +32,15 @@ public final class StatCommand implements CommandExecutor {
|
||||
|
||||
private static ThreadManager threadManager;
|
||||
private static OutputManager outputManager;
|
||||
private static ConfigHandler config;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final ConfigHandler config;
|
||||
private final EnumHandler enumHandler;
|
||||
|
||||
public StatCommand(OutputManager m, ThreadManager t, ConfigHandler c, OfflinePlayerHandler o, EnumHandler e) {
|
||||
threadManager = t;
|
||||
outputManager = m;
|
||||
config = c;
|
||||
offlinePlayerHandler = o;
|
||||
enumHandler = e;
|
||||
public StatCommand(OutputManager outputManager, ThreadManager threadManager) {
|
||||
StatCommand.threadManager = threadManager;
|
||||
StatCommand.outputManager = outputManager;
|
||||
|
||||
config = ConfigHandler.getInstance();
|
||||
enumHandler = EnumHandler.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,19 +134,19 @@ public final class StatCommand implements CommandExecutor {
|
||||
switch (statistic.getType()) {
|
||||
case UNTYPED -> request = requestGenerator.untyped(statistic);
|
||||
case BLOCK -> {
|
||||
Material block = EnumHandler.getBlockEnum(subStatName);
|
||||
Material block = enumHandler.getBlockEnum(subStatName);
|
||||
if (block != null) {
|
||||
request = requestGenerator.blockOrItemType(statistic, block);
|
||||
}
|
||||
}
|
||||
case ITEM -> {
|
||||
Material item = EnumHandler.getItemEnum(subStatName);
|
||||
Material item = enumHandler.getItemEnum(subStatName);
|
||||
if (item != null) {
|
||||
request = requestGenerator.blockOrItemType(statistic, item);
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
EntityType entity = EnumHandler.getEntityEnum(subStatName);
|
||||
EntityType entity = enumHandler.getEntityEnum(subStatName);
|
||||
if (entity != null) {
|
||||
request = requestGenerator.entityType(statistic, entity);
|
||||
}
|
||||
@ -202,7 +201,7 @@ public final class StatCommand implements CommandExecutor {
|
||||
}
|
||||
}
|
||||
if (statName != null) {
|
||||
statistic = EnumHandler.getStatEnum(statName);
|
||||
statistic = enumHandler.getStatEnum(statName);
|
||||
argsToProcess = removeArg(statName);
|
||||
}
|
||||
}
|
||||
@ -241,6 +240,8 @@ public final class StatCommand implements CommandExecutor {
|
||||
|
||||
@Contract(pure = true)
|
||||
private @Nullable String tryToFindPlayerName(@NotNull String[] args) {
|
||||
OfflinePlayerHandler offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
|
||||
for (String arg : args) {
|
||||
if (offlinePlayerHandler.isRelevantPlayer(arg)) {
|
||||
return arg;
|
||||
|
@ -7,6 +7,7 @@ import org.bukkit.Statistic;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -17,16 +18,18 @@ import java.util.stream.Collectors;
|
||||
|
||||
public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
|
||||
private final EnumHandler enumHandler;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final EnumHandler enumHandler;
|
||||
|
||||
private List<String> targetSuggestions;
|
||||
private List<String> itemBrokenSuggestions;
|
||||
private List<String> entitySuggestions;
|
||||
private List<String> statCommandTargets;
|
||||
private List<String> excludeCommandOptions;
|
||||
private List<String> itemsThatCanBreak;
|
||||
private List<String> entitiesThatCanDie;
|
||||
|
||||
public TabCompleter() {
|
||||
offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
enumHandler = EnumHandler.getInstance();
|
||||
|
||||
public TabCompleter(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler) {
|
||||
this.enumHandler = enumHandler;
|
||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||
prepareLists();
|
||||
}
|
||||
|
||||
@ -46,50 +49,58 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
}
|
||||
|
||||
private @Nullable List<String> getExcludeCommandSuggestions(@NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getDynamicTabSuggestions(offlinePlayerHandler.getOfflinePlayerNames(), args[0]);
|
||||
}
|
||||
if (args.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable List<String> getStatCommandSuggestions(@NotNull String[] args) {
|
||||
List<String> tabSuggestions = new ArrayList<>();
|
||||
if (args.length == 1) {
|
||||
return getFirstArgSuggestions(args[0]);
|
||||
tabSuggestions = excludeCommandOptions;
|
||||
}
|
||||
else if (args.length > 1) {
|
||||
String currentArg = args[args.length-1];
|
||||
else if (args.length == 2) {
|
||||
tabSuggestions = switch (args[0]) {
|
||||
case "add" -> offlinePlayerHandler.getOfflinePlayerNames();
|
||||
case "remove" -> removablePlayerNames();
|
||||
default -> tabSuggestions;
|
||||
};
|
||||
}
|
||||
return getDynamicTabSuggestions(tabSuggestions, args[args.length-1]);
|
||||
}
|
||||
|
||||
private @Nullable List<String> getStatCommandSuggestions(@NotNull String[] args) {
|
||||
if (args.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> tabSuggestions = new ArrayList<>();
|
||||
if (args.length == 1) {
|
||||
tabSuggestions = firstStatCommandArgSuggestions();
|
||||
}
|
||||
else {
|
||||
String previousArg = args[args.length-2];
|
||||
|
||||
//after checking if args[0] is a viable statistic, suggest sub-stat or targets
|
||||
if (enumHandler.isStatistic(previousArg)) {
|
||||
Statistic stat = EnumHandler.getStatEnum(previousArg);
|
||||
Statistic stat = enumHandler.getStatEnum(previousArg);
|
||||
if (stat != null) {
|
||||
return getDynamicTabSuggestions(getSuggestionsAfterStat(stat), currentArg);
|
||||
tabSuggestions = suggestionsAfterFirstStatCommandArg(stat);
|
||||
}
|
||||
}
|
||||
else if (previousArg.equalsIgnoreCase("player")) {
|
||||
if (args.length >= 3 && enumHandler.isEntityStatistic(args[args.length-3])) {
|
||||
return targetSuggestions; //if arg before "player" was entity-sub-stat, suggest targets
|
||||
tabSuggestions = statCommandTargets; //if arg before "player" was entity-sub-stat, suggest targets
|
||||
}
|
||||
else { //otherwise "player" is the target: suggest playerNames
|
||||
return getDynamicTabSuggestions(offlinePlayerHandler.getOfflinePlayerNames(), currentArg);
|
||||
tabSuggestions = offlinePlayerHandler.getOfflinePlayerNames();
|
||||
}
|
||||
}
|
||||
|
||||
//after a substatistic, suggest targets
|
||||
else if (enumHandler.isSubStatEntry(previousArg)) {
|
||||
return targetSuggestions;
|
||||
tabSuggestions = statCommandTargets;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getFirstArgSuggestions(String currentArg) {
|
||||
List<String> suggestions = enumHandler.getStatNames();
|
||||
suggestions.add("examples");
|
||||
suggestions.add("help");
|
||||
return getDynamicTabSuggestions(suggestions, currentArg);
|
||||
return getDynamicTabSuggestions(tabSuggestions, args[args.length-1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,52 +114,53 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> getSuggestionsAfterStat(@NotNull Statistic stat) {
|
||||
private @NotNull List<String> firstStatCommandArgSuggestions() {
|
||||
List<String> suggestions = enumHandler.getAllStatNames();
|
||||
suggestions.add("examples");
|
||||
suggestions.add("help");
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
private List<String> suggestionsAfterFirstStatCommandArg(@NotNull Statistic stat) {
|
||||
switch (stat.getType()) {
|
||||
case BLOCK -> {
|
||||
return getAllBlockNames();
|
||||
return enumHandler.getAllBlockNames();
|
||||
}
|
||||
case ITEM -> {
|
||||
if (stat == Statistic.BREAK_ITEM) {
|
||||
return getItemBrokenSuggestions();
|
||||
return itemsThatCanBreak;
|
||||
} else {
|
||||
return getAllItemNames();
|
||||
return enumHandler.getAllItemNames();
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
return getEntitySuggestions();
|
||||
return entitiesThatCanDie;
|
||||
}
|
||||
default -> {
|
||||
return targetSuggestions;
|
||||
return statCommandTargets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getAllItemNames() {
|
||||
return enumHandler.getItemNames();
|
||||
}
|
||||
|
||||
private List<String> getItemBrokenSuggestions() {
|
||||
return itemBrokenSuggestions;
|
||||
}
|
||||
|
||||
private List<String> getAllBlockNames() {
|
||||
return enumHandler.getBlockNames();
|
||||
}
|
||||
|
||||
private List<String> getEntitySuggestions() {
|
||||
return entitySuggestions;
|
||||
@Contract(pure = true)
|
||||
private @Nullable List<String> removablePlayerNames() {
|
||||
return statCommandTargets;
|
||||
}
|
||||
|
||||
private void prepareLists() {
|
||||
targetSuggestions = new ArrayList<>();
|
||||
targetSuggestions.add("top");
|
||||
targetSuggestions.add("player");
|
||||
targetSuggestions.add("server");
|
||||
targetSuggestions.add("me");
|
||||
statCommandTargets = new ArrayList<>();
|
||||
statCommandTargets.add("top");
|
||||
statCommandTargets.add("player");
|
||||
statCommandTargets.add("server");
|
||||
statCommandTargets.add("me");
|
||||
|
||||
excludeCommandOptions = new ArrayList<>();
|
||||
excludeCommandOptions.add("add");
|
||||
excludeCommandOptions.add("list");
|
||||
excludeCommandOptions.add("remove");
|
||||
|
||||
//breaking an item means running its durability negative
|
||||
itemBrokenSuggestions = Arrays.stream(Material.values())
|
||||
itemsThatCanBreak = Arrays.stream(Material.values())
|
||||
.parallel()
|
||||
.filter(Material::isItem)
|
||||
.filter(item -> item.getMaxDurability() != 0)
|
||||
@ -157,7 +169,7 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
//the only statistics dealing with entities are killed_entity and entity_killed_by
|
||||
entitySuggestions = Arrays.stream(EntityType.values())
|
||||
entitiesThatCanDie = Arrays.stream(EntityType.values())
|
||||
.parallel()
|
||||
.filter(EntityType::isAlive)
|
||||
.map(EntityType::toString)
|
||||
|
@ -13,10 +13,11 @@ import java.util.Map;
|
||||
/** Handles all PlayerStats' config-settings. */
|
||||
public final class ConfigHandler extends FileHandler {
|
||||
|
||||
private static volatile ConfigHandler instance;
|
||||
private final int configVersion;
|
||||
private FileConfiguration config;
|
||||
|
||||
public ConfigHandler() {
|
||||
private ConfigHandler() {
|
||||
super("config.yml");
|
||||
config = super.getFileConfiguration();
|
||||
|
||||
@ -25,6 +26,20 @@ public final class ConfigHandler extends FileHandler {
|
||||
MyLogger.setDebugLevel(getDebugLevel());
|
||||
}
|
||||
|
||||
public static ConfigHandler getInstance() {
|
||||
ConfigHandler localVar = instance;
|
||||
if (localVar != null) {
|
||||
return localVar;
|
||||
}
|
||||
|
||||
synchronized (ConfigHandler.class) {
|
||||
if (instance == null) {
|
||||
instance = new ConfigHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.listeners;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
@ -144,7 +144,9 @@ public final class MessageBuilder implements StatFormatter {
|
||||
return componentFactory.pluginPrefix()
|
||||
.append(space())
|
||||
.append(componentFactory.message().content(
|
||||
"Please add a valid " + EnumHandler.getSubStatTypeName(statType) + " to look up this statistic!"));
|
||||
"Please add a valid " +
|
||||
EnumHandler.getInstance().getSubStatTypeName(statType) +
|
||||
" to look up this statistic!"));
|
||||
}
|
||||
|
||||
public @NotNull TextComponent missingPlayerName() {
|
||||
@ -160,7 +162,9 @@ public final class MessageBuilder implements StatFormatter {
|
||||
.append(componentFactory.messageAccent().content("\"" + subStatName + "\""))
|
||||
.append(space())
|
||||
.append(componentFactory.message().content(
|
||||
"is not a valid " + EnumHandler.getSubStatTypeName(statType) + "!"));
|
||||
"is not a valid " +
|
||||
EnumHandler.getInstance().getSubStatTypeName(statType) +
|
||||
"!"));
|
||||
}
|
||||
|
||||
public @NotNull TextComponent requestAlreadyRunning() {
|
||||
@ -509,12 +513,14 @@ public final class MessageBuilder implements StatFormatter {
|
||||
}
|
||||
|
||||
private TextComponent getStatAndSubStatNameComponent(Statistic statistic, @Nullable String subStatName, Target target) {
|
||||
EnumHandler enumHandler = EnumHandler.getInstance();
|
||||
|
||||
String statKey = languageKeyHandler.getStatKey(statistic);
|
||||
String subStatKey = switch (statistic.getType()) {
|
||||
case UNTYPED -> null;
|
||||
case ENTITY -> languageKeyHandler.getEntityKey(EnumHandler.getEntityEnum(subStatName));
|
||||
case BLOCK -> languageKeyHandler.getBlockKey(EnumHandler.getBlockEnum(subStatName));
|
||||
case ITEM -> languageKeyHandler.getItemKey(EnumHandler.getItemEnum(subStatName));
|
||||
case ENTITY -> languageKeyHandler.getEntityKey(enumHandler.getEntityEnum(subStatName));
|
||||
case BLOCK -> languageKeyHandler.getBlockKey(enumHandler.getBlockEnum(subStatName));
|
||||
case ITEM -> languageKeyHandler.getItemKey(enumHandler.getItemEnum(subStatName));
|
||||
};
|
||||
if (subStatKey == null) {
|
||||
subStatKey = StringUtils.prettify(subStatName);
|
||||
|
@ -34,17 +34,18 @@ import static com.artemis.the.gr8.playerstats.enums.StandardMessage.*;
|
||||
public final class OutputManager {
|
||||
|
||||
private static BukkitAudiences adventure;
|
||||
private static ConfigHandler config;
|
||||
private static EnumMap<StandardMessage, Function<MessageBuilder, TextComponent>> standardMessages;
|
||||
|
||||
private final ConfigHandler config;
|
||||
private final LanguageKeyHandler languageKeyHandler;
|
||||
private MessageBuilder messageBuilder;
|
||||
private MessageBuilder consoleMessageBuilder;
|
||||
|
||||
public OutputManager(BukkitAudiences adventure, ConfigHandler config, LanguageKeyHandler language) {
|
||||
public OutputManager(BukkitAudiences adventure) {
|
||||
OutputManager.adventure = adventure;
|
||||
OutputManager.config = config;
|
||||
languageKeyHandler = language;
|
||||
languageKeyHandler = LanguageKeyHandler.getInstance();
|
||||
config = ConfigHandler.getInstance();
|
||||
|
||||
getMessageBuilders();
|
||||
prepareFunctions();
|
||||
}
|
||||
|
@ -22,15 +22,30 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public final class LanguageKeyHandler extends FileHandler {
|
||||
|
||||
private static volatile LanguageKeyHandler instance;
|
||||
private static HashMap<Statistic, String> statisticKeys;
|
||||
private final Pattern subStatKey;
|
||||
|
||||
public LanguageKeyHandler() {
|
||||
private LanguageKeyHandler() {
|
||||
super("language.yml");
|
||||
statisticKeys = generateStatisticKeys();
|
||||
subStatKey = Pattern.compile("(item|entity|block)\\.minecraft\\.");
|
||||
}
|
||||
|
||||
public static LanguageKeyHandler getInstance() {
|
||||
LanguageKeyHandler localVar = instance;
|
||||
if (localVar != null) {
|
||||
return localVar;
|
||||
}
|
||||
|
||||
synchronized (LanguageKeyHandler.class) {
|
||||
if (instance == null) {
|
||||
instance = new LanguageKeyHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public @NotNull String getKeyForBlockUnit() {
|
||||
return "soundCategory.block";
|
||||
@ -222,7 +237,7 @@ public final class LanguageKeyHandler extends FileHandler {
|
||||
if (block == null) return null;
|
||||
else if (block.toString().toLowerCase().contains("wall_banner")) { //replace wall_banner with regular banner, since there is no key for wall banners
|
||||
String blockName = block.toString().toLowerCase().replace("wall_", "");
|
||||
Material newBlock = EnumHandler.getBlockEnum(blockName);
|
||||
Material newBlock = EnumHandler.getInstance().getBlockEnum(blockName);
|
||||
return (newBlock != null) ? "block.minecraft." + newBlock.getKey().getKey() : null;
|
||||
}
|
||||
else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.reload;
|
||||
package com.artemis.the.gr8.playerstats.multithreading;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.UnixTimeHandler;
|
||||
@ -13,7 +13,7 @@ import java.util.concurrent.RecursiveAction;
|
||||
/**
|
||||
* The action that is executed when a reload-command is triggered.
|
||||
*/
|
||||
public final class PlayerLoadAction extends RecursiveAction {
|
||||
final class PlayerLoadAction extends RecursiveAction {
|
||||
|
||||
private static int threshold;
|
||||
|
||||
@ -21,7 +21,6 @@ public final class PlayerLoadAction extends RecursiveAction {
|
||||
private final int start;
|
||||
private final int end;
|
||||
|
||||
private final int lastPlayedLimit;
|
||||
private final ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
|
||||
/**
|
||||
@ -29,25 +28,19 @@ public final class PlayerLoadAction extends RecursiveAction {
|
||||
* that should be included in statistic calculations.
|
||||
*
|
||||
* @param players array of all OfflinePlayers to filter and load
|
||||
* @param lastPlayedLimit optional limit for amount of days ago players last played
|
||||
* @param offlinePlayerUUIDs the ConcurrentHashMap to put playerNames and UUIDs in
|
||||
* @see OfflinePlayerHandler
|
||||
*/
|
||||
public PlayerLoadAction(OfflinePlayer[] players,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
|
||||
this(players, 0, players.length, lastPlayedLimit, offlinePlayerUUIDs);
|
||||
public PlayerLoadAction(OfflinePlayer[] players, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
this(players, 0, players.length, offlinePlayerUUIDs);
|
||||
}
|
||||
|
||||
private PlayerLoadAction(OfflinePlayer[] players, int start, int end,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
private PlayerLoadAction(OfflinePlayer[] players, int start, int end, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
threshold = ThreadManager.getTaskThreshold();
|
||||
|
||||
this.players = players;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
this.lastPlayedLimit = lastPlayedLimit;
|
||||
this.offlinePlayerUUIDs = offlinePlayerUUIDs;
|
||||
|
||||
MyLogger.subActionCreated(Thread.currentThread().getName());
|
||||
@ -62,9 +55,9 @@ public final class PlayerLoadAction extends RecursiveAction {
|
||||
else {
|
||||
final int split = length / 2;
|
||||
final PlayerLoadAction subTask1 = new PlayerLoadAction(players, start, (start + split),
|
||||
lastPlayedLimit, offlinePlayerUUIDs);
|
||||
offlinePlayerUUIDs);
|
||||
final PlayerLoadAction subTask2 = new PlayerLoadAction(players, (start + split), end,
|
||||
lastPlayedLimit, offlinePlayerUUIDs);
|
||||
offlinePlayerUUIDs);
|
||||
|
||||
//queue and compute all subtasks in the right order
|
||||
invokeAll(subTask1, subTask2);
|
||||
@ -72,11 +65,16 @@ public final class PlayerLoadAction extends RecursiveAction {
|
||||
}
|
||||
|
||||
private void process() {
|
||||
OfflinePlayerHandler offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
int lastPlayedLimit = ConfigHandler.getInstance().getLastPlayedLimit();
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
OfflinePlayer player = players[i];
|
||||
String playerName = player.getName();
|
||||
MyLogger.actionRunning(Thread.currentThread().getName());
|
||||
if (playerName != null && UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed())) {
|
||||
if (playerName != null &&
|
||||
!offlinePlayerHandler.isExcluded(player.getUniqueId()) &&
|
||||
UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed())) {
|
||||
offlinePlayerUUIDs.put(playerName, player.getUniqueId());
|
||||
}
|
||||
}
|
@ -1,20 +1,14 @@
|
||||
package com.artemis.the.gr8.playerstats.reload;
|
||||
package com.artemis.the.gr8.playerstats.multithreading;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.Main;
|
||||
import com.artemis.the.gr8.playerstats.share.ShareManager;
|
||||
import com.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.msg.msgutils.LanguageKeyHandler;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestProcessor;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatThread;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.artemis.the.gr8.playerstats.enums.DebugLevel;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/** The Thread that is in charge of reloading PlayerStats. */
|
||||
public final class ReloadThread extends Thread {
|
||||
final class ReloadThread extends Thread {
|
||||
|
||||
private final Main main;
|
||||
private static OutputManager outputManager;
|
||||
@ -34,13 +28,8 @@ public final class ReloadThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will perform a series of tasks. If a {@link StatThread}
|
||||
* This method will call reload() from Main. If a {@link StatThread}
|
||||
* is still running, it will join the statThread and wait for it to finish.
|
||||
* Then, it will reload the config, update the {@link LanguageKeyHandler},
|
||||
* the {@link OfflinePlayerHandler}, the {@link DebugLevel}, update
|
||||
* the share-settings in {@link ShareManager} and topListSize-settings
|
||||
* in {@link RequestProcessor}, and update the MessageBuilders in the
|
||||
* {@link OutputManager}.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
@ -1,6 +1,6 @@
|
||||
package com.artemis.the.gr8.playerstats.statistic;
|
||||
package com.artemis.the.gr8.playerstats.multithreading;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@ -16,8 +16,6 @@ import java.util.concurrent.RecursiveTask;
|
||||
final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>> {
|
||||
|
||||
private static int threshold;
|
||||
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final ImmutableList<String> playerNames;
|
||||
private final StatRequest.Settings requestSettings;
|
||||
private final ConcurrentHashMap<String, Integer> allStats;
|
||||
@ -28,15 +26,13 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
|
||||
* ForkJoinPool, and returns the ConcurrentHashMap when
|
||||
* everything is done.
|
||||
*
|
||||
* @param offlinePlayerHandler the OfflinePlayerHandler to convert playerNames into Players
|
||||
* @param playerNames ImmutableList of playerNames for players that should be included in stat calculations
|
||||
* @param requestSettings a validated requestSettings object
|
||||
* @param allStats the ConcurrentHashMap to put the results on
|
||||
*/
|
||||
public StatAction(OfflinePlayerHandler offlinePlayerHandler, ImmutableList<String> playerNames, StatRequest.Settings requestSettings, ConcurrentHashMap<String, Integer> allStats) {
|
||||
public StatAction(ImmutableList<String> playerNames, StatRequest.Settings requestSettings, ConcurrentHashMap<String, Integer> allStats) {
|
||||
threshold = ThreadManager.getTaskThreshold();
|
||||
|
||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||
this.playerNames = playerNames;
|
||||
this.requestSettings = requestSettings;
|
||||
this.allStats = allStats;
|
||||
@ -50,8 +46,8 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
|
||||
return getStatsDirectly();
|
||||
}
|
||||
else {
|
||||
final StatAction subTask1 = new StatAction(offlinePlayerHandler, playerNames.subList(0, playerNames.size()/2), requestSettings, allStats);
|
||||
final StatAction subTask2 = new StatAction(offlinePlayerHandler, playerNames.subList(playerNames.size()/2, playerNames.size()), requestSettings, allStats);
|
||||
final StatAction subTask1 = new StatAction(playerNames.subList(0, playerNames.size()/2), requestSettings, allStats);
|
||||
final StatAction subTask2 = new StatAction(playerNames.subList(playerNames.size()/2, playerNames.size()), requestSettings, allStats);
|
||||
|
||||
//queue and compute all subtasks in the right order
|
||||
subTask1.fork();
|
||||
@ -61,6 +57,8 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
|
||||
}
|
||||
|
||||
private ConcurrentHashMap<String, Integer> getStatsDirectly() {
|
||||
OfflinePlayerHandler offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
|
||||
Iterator<String> iterator = playerNames.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
do {
|
@ -1,10 +1,11 @@
|
||||
package com.artemis.the.gr8.playerstats.statistic;
|
||||
package com.artemis.the.gr8.playerstats.multithreading;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatResult;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||
import com.artemis.the.gr8.playerstats.reload.ReloadThread;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -13,17 +14,15 @@ import java.util.*;
|
||||
/**
|
||||
* The Thread that is in charge of getting and calculating statistics.
|
||||
*/
|
||||
public final class StatThread extends Thread {
|
||||
final class StatThread extends Thread {
|
||||
|
||||
private static OutputManager outputManager;
|
||||
private final RequestManager statManager;
|
||||
|
||||
private final ReloadThread reloadThread;
|
||||
private final StatRequest<?> statRequest;
|
||||
|
||||
public StatThread(OutputManager m, RequestManager stat, int ID, StatRequest<?> s, @Nullable ReloadThread r) {
|
||||
public StatThread(OutputManager m, int ID, StatRequest<?> s, @Nullable ReloadThread r) {
|
||||
outputManager = m;
|
||||
statManager = stat;
|
||||
reloadThread = r;
|
||||
statRequest = s;
|
||||
|
||||
@ -54,7 +53,7 @@ public final class StatThread extends Thread {
|
||||
}
|
||||
|
||||
try {
|
||||
StatResult<?> result = statManager.execute(statRequest);
|
||||
StatResult<?> result = RequestManager.execute(statRequest);
|
||||
outputManager.sendToCommandSender(statRequester, result.formattedComponent());
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
@ -1,17 +1,20 @@
|
||||
package com.artemis.the.gr8.playerstats;
|
||||
package com.artemis.the.gr8.playerstats.multithreading;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.Main;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||
import com.artemis.the.gr8.playerstats.reload.ReloadThread;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatThread;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.artemis.the.gr8.playerstats.statistic.RequestManager;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* The ThreadManager is in charge of the Threads that PlayerStats
|
||||
@ -29,20 +32,18 @@ public final class ThreadManager {
|
||||
private int reloadThreadID;
|
||||
|
||||
private final Main main;
|
||||
private static ConfigHandler config;
|
||||
private final ConfigHandler config;
|
||||
private static OutputManager outputManager;
|
||||
private final RequestManager statManager;
|
||||
|
||||
private ReloadThread activatedReloadThread;
|
||||
private StatThread activatedStatThread;
|
||||
private final HashMap<String, Thread> statThreads;
|
||||
private static long lastRecordedCalcTime;
|
||||
|
||||
public ThreadManager(Main main, ConfigHandler config, OutputManager outputManager, RequestManager statManager) {
|
||||
public ThreadManager(Main main, OutputManager outputManager) {
|
||||
this.main = main;
|
||||
ThreadManager.config = config;
|
||||
this.config = ConfigHandler.getInstance();
|
||||
ThreadManager.outputManager = outputManager;
|
||||
this.statManager = statManager;
|
||||
|
||||
statThreads = new HashMap<>();
|
||||
statThreadID = 0;
|
||||
@ -50,10 +51,27 @@ public final class ThreadManager {
|
||||
lastRecordedCalcTime = 0;
|
||||
}
|
||||
|
||||
public static int getTaskThreshold() {
|
||||
static int getTaskThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public static @NotNull StatAction getStatAction(StatRequest.Settings requestSettings) {
|
||||
OfflinePlayerHandler offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
|
||||
ImmutableList<String> relevantPlayerNames = ImmutableList.copyOf(offlinePlayerHandler.getOfflinePlayerNames());
|
||||
ConcurrentHashMap<String, Integer> resultingStatNumbers = new ConcurrentHashMap<>(relevantPlayerNames.size());
|
||||
StatAction task = new StatAction(relevantPlayerNames, requestSettings, resultingStatNumbers);
|
||||
|
||||
MyLogger.actionCreated(relevantPlayerNames.size());
|
||||
return task;
|
||||
}
|
||||
|
||||
public static @NotNull PlayerLoadAction getPlayerLoadAction(OfflinePlayer[] playersToLoad, ConcurrentHashMap<String, UUID> mapToFill) {
|
||||
PlayerLoadAction task = new PlayerLoadAction(playersToLoad, mapToFill);
|
||||
MyLogger.actionCreated(playersToLoad != null ? playersToLoad.length : 0);
|
||||
return task;
|
||||
}
|
||||
|
||||
public void startReloadThread(CommandSender sender) {
|
||||
if (activatedReloadThread == null || !activatedReloadThread.isAlive()) {
|
||||
reloadThreadID += 1;
|
||||
@ -100,7 +118,7 @@ public final class ThreadManager {
|
||||
}
|
||||
|
||||
private void startNewStatThread(StatRequest<?> request) {
|
||||
activatedStatThread = new StatThread(outputManager, statManager, statThreadID, request, activatedReloadThread);
|
||||
activatedStatThread = new StatThread(outputManager, statThreadID, request, activatedReloadThread);
|
||||
statThreads.put(request.getSettings().getCommandSender().getName(), activatedStatThread);
|
||||
activatedStatThread.start();
|
||||
}
|
@ -33,15 +33,16 @@ public final class ShareManager {
|
||||
private ConcurrentHashMap<String, Instant> shareTimeStamp;
|
||||
private ArrayBlockingQueue<Integer> sharedResults;
|
||||
|
||||
public ShareManager(ConfigHandler config) {
|
||||
updateSettings(config);
|
||||
public ShareManager() {
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public void updateSettings(ConfigHandler config) {
|
||||
public void updateSettings() {
|
||||
ConfigHandler config = ConfigHandler.getInstance();
|
||||
isEnabled = config.allowStatSharing() && config.useHoverText();
|
||||
waitingTime = config.getStatShareWaitingTime();
|
||||
|
||||
|
@ -2,10 +2,22 @@ package com.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.api.RequestGenerator;
|
||||
import com.artemis.the.gr8.playerstats.api.StatManager;
|
||||
import com.artemis.the.gr8.playerstats.msg.FormattingFunction;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.share.ShareManager;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Turns user input into a {@link StatRequest} that can be
|
||||
@ -13,15 +25,15 @@ import java.util.LinkedHashMap;
|
||||
*/
|
||||
public final class RequestManager implements StatManager {
|
||||
|
||||
private static OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final RequestProcessor processor;
|
||||
private static RequestProcessor processor;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
|
||||
public RequestManager(OfflinePlayerHandler offlinePlayerHandler, RequestProcessor processor) {
|
||||
RequestManager.offlinePlayerHandler = offlinePlayerHandler;
|
||||
this.processor = processor;
|
||||
public RequestManager(OutputManager outputManager, ShareManager shareManager) {
|
||||
processor = new RequestProcessor(outputManager, shareManager);
|
||||
offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
}
|
||||
|
||||
public StatResult<?> execute(@NotNull StatRequest<?> request) {
|
||||
public static StatResult<?> execute(@NotNull StatRequest<?> request) {
|
||||
return switch (request.getSettings().getTarget()) {
|
||||
case PLAYER -> processor.processPlayerRequest(request.getSettings());
|
||||
case SERVER -> processor.processServerRequest(request.getSettings());
|
||||
@ -64,4 +76,107 @@ public final class RequestManager implements StatManager {
|
||||
public StatResult<LinkedHashMap<String, Integer>> executeTopRequest(StatRequest<LinkedHashMap<String, Integer>> request) {
|
||||
return processor.processTopRequest(request.getSettings());
|
||||
}
|
||||
|
||||
private final class RequestProcessor {
|
||||
|
||||
private static OutputManager outputManager;
|
||||
private static ShareManager shareManager;
|
||||
|
||||
public RequestProcessor(OutputManager outputManager, ShareManager shareManager) {
|
||||
RequestProcessor.outputManager = outputManager;
|
||||
RequestProcessor.shareManager = shareManager;
|
||||
}
|
||||
|
||||
public @NotNull StatResult<Integer> processPlayerRequest(StatRequest.Settings requestSettings) {
|
||||
int stat = getPlayerStat(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatPlayerStat(requestSettings, stat);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stat, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
public @NotNull StatResult<Long> processServerRequest(StatRequest.Settings requestSettings) {
|
||||
long stat = getServerStat(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatServerStat(requestSettings, stat);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stat, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
public @NotNull StatResult<LinkedHashMap<String, Integer>> processTopRequest(StatRequest.Settings requestSettings) {
|
||||
LinkedHashMap<String, Integer> stats = getTopStats(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatTopStats(requestSettings, stats);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stats, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
private int getPlayerStat(@NotNull StatRequest.Settings requestSettings) {
|
||||
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(requestSettings.getPlayerName());
|
||||
return switch (requestSettings.getStatistic().getType()) {
|
||||
case UNTYPED -> player.getStatistic(requestSettings.getStatistic());
|
||||
case ENTITY -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getEntity());
|
||||
case BLOCK -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getBlock());
|
||||
case ITEM -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getItem());
|
||||
};
|
||||
}
|
||||
|
||||
private long getServerStat(StatRequest.Settings requestSettings) {
|
||||
List<Integer> numbers = getAllStatsAsync(requestSettings)
|
||||
.values()
|
||||
.parallelStream()
|
||||
.toList();
|
||||
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, Integer> getTopStats(StatRequest.Settings requestSettings) {
|
||||
return getAllStatsAsync(requestSettings).entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
||||
.limit(requestSettings.getTopListSize())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private TextComponent processFunction(CommandSender sender, FormattingFunction function) {
|
||||
if (outputShouldBeStored(sender)) {
|
||||
int shareCode = shareManager.saveStatResult(sender.getName(), function.getResultWithSharerName(sender));
|
||||
return function.getResultWithShareButton(shareCode);
|
||||
}
|
||||
return function.getDefaultResult();
|
||||
}
|
||||
|
||||
private boolean outputShouldBeStored(CommandSender sender) {
|
||||
return !(sender instanceof ConsoleCommandSender) &&
|
||||
ShareManager.isEnabled() &&
|
||||
shareManager.senderHasPermission(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a bunch of worker pool threads to get the statistics for
|
||||
* all players that are stored in the {@link OfflinePlayerHandler}).
|
||||
*/
|
||||
private @NotNull ConcurrentHashMap<String, Integer> getAllStatsAsync(StatRequest.Settings requestSettings) {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
||||
ConcurrentHashMap<String, Integer> allStats;
|
||||
|
||||
try {
|
||||
allStats = commonPool.invoke(ThreadManager.getStatAction(requestSettings));
|
||||
} catch (ConcurrentModificationException e) {
|
||||
MyLogger.logWarning("The requestSettings could not be executed due to a ConcurrentModificationException. " +
|
||||
"This likely happened because Bukkit hasn't fully initialized all player-data yet. " +
|
||||
"Try again and it should be fine!");
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
}
|
||||
|
||||
MyLogger.actionFinished();
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
MyLogger.logMediumLevelTask("Calculated all stats", time);
|
||||
|
||||
return allStats;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
package com.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.msg.FormattingFunction;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.share.ShareManager;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class RequestProcessor {
|
||||
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private static OutputManager outputManager;
|
||||
private static ShareManager shareManager;
|
||||
|
||||
public RequestProcessor(OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager, ShareManager shareManager) {
|
||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||
RequestProcessor.outputManager = outputManager;
|
||||
RequestProcessor.shareManager = shareManager;
|
||||
}
|
||||
|
||||
public @NotNull StatResult<Integer> processPlayerRequest(StatRequest.Settings requestSettings) {
|
||||
int stat = getPlayerStat(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatPlayerStat(requestSettings, stat);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stat, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
public @NotNull StatResult<Long> processServerRequest(StatRequest.Settings requestSettings) {
|
||||
long stat = getServerStat(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatServerStat(requestSettings, stat);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stat, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
public @NotNull StatResult<LinkedHashMap<String, Integer>> processTopRequest(StatRequest.Settings requestSettings) {
|
||||
LinkedHashMap<String, Integer> stats = getTopStats(requestSettings);
|
||||
FormattingFunction formattingFunction = outputManager.formatTopStats(requestSettings, stats);
|
||||
TextComponent formattedResult = processFunction(requestSettings.getCommandSender(), formattingFunction);
|
||||
String resultAsString = outputManager.textComponentToString(formattedResult);
|
||||
|
||||
return new StatResult<>(stats, formattedResult, resultAsString);
|
||||
}
|
||||
|
||||
private int getPlayerStat(@NotNull StatRequest.Settings requestSettings) {
|
||||
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(requestSettings.getPlayerName());
|
||||
return switch (requestSettings.getStatistic().getType()) {
|
||||
case UNTYPED -> player.getStatistic(requestSettings.getStatistic());
|
||||
case ENTITY -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getEntity());
|
||||
case BLOCK -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getBlock());
|
||||
case ITEM -> player.getStatistic(requestSettings.getStatistic(), requestSettings.getItem());
|
||||
};
|
||||
}
|
||||
|
||||
private long getServerStat(StatRequest.Settings requestSettings) {
|
||||
List<Integer> numbers = getAllStatsAsync(requestSettings)
|
||||
.values()
|
||||
.parallelStream()
|
||||
.toList();
|
||||
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, Integer> getTopStats(StatRequest.Settings requestSettings) {
|
||||
return getAllStatsAsync(requestSettings).entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
||||
.limit(requestSettings.getTopListSize())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private TextComponent processFunction(CommandSender sender, FormattingFunction function) {
|
||||
if (outputShouldBeStored(sender)) {
|
||||
int shareCode = shareManager.saveStatResult(sender.getName(), function.getResultWithSharerName(sender));
|
||||
return function.getResultWithShareButton(shareCode);
|
||||
}
|
||||
return function.getDefaultResult();
|
||||
}
|
||||
|
||||
private boolean outputShouldBeStored(CommandSender sender) {
|
||||
return !(sender instanceof ConsoleCommandSender) &&
|
||||
ShareManager.isEnabled() &&
|
||||
shareManager.senderHasPermission(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a bunch of worker pool threads to get the statistics for
|
||||
* all players that are stored in the {@link OfflinePlayerHandler}).
|
||||
*/
|
||||
private @NotNull ConcurrentHashMap<String, Integer> getAllStatsAsync(StatRequest.Settings requestSettings) {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
||||
ConcurrentHashMap<String, Integer> allStats;
|
||||
|
||||
try {
|
||||
allStats = commonPool.invoke(getStatTask(requestSettings));
|
||||
} catch (ConcurrentModificationException e) {
|
||||
MyLogger.logWarning("The requestSettings could not be executed due to a ConcurrentModificationException. " +
|
||||
"This likely happened because Bukkit hasn't fully initialized all player-data yet. " +
|
||||
"Try again and it should be fine!");
|
||||
throw new ConcurrentModificationException(e.toString());
|
||||
}
|
||||
|
||||
MyLogger.actionFinished();
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
MyLogger.logMediumLevelTask("Calculated all stats", time);
|
||||
|
||||
return allStats;
|
||||
}
|
||||
|
||||
private @NotNull StatAction getStatTask(StatRequest.Settings requestSettings) {
|
||||
int size = offlinePlayerHandler.getOfflinePlayerCount() != 0 ? offlinePlayerHandler.getOfflinePlayerCount() : 16;
|
||||
ConcurrentHashMap<String, Integer> allStats = new ConcurrentHashMap<>(size);
|
||||
ImmutableList<String> playerNames = ImmutableList.copyOf(offlinePlayerHandler.getOfflinePlayerNames());
|
||||
|
||||
StatAction task = new StatAction(offlinePlayerHandler, playerNames, requestSettings, allStats);
|
||||
MyLogger.actionCreated(playerNames.size());
|
||||
|
||||
return task;
|
||||
}
|
||||
}
|
@ -21,21 +21,36 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
public final class EnumHandler {
|
||||
|
||||
private static volatile EnumHandler instance;
|
||||
private static List<String> blockNames;
|
||||
private static List<String> itemNames;
|
||||
private static List<String> statNames;
|
||||
private static List<String> subStatNames;
|
||||
|
||||
public EnumHandler() {
|
||||
private EnumHandler() {
|
||||
prepareLists();
|
||||
}
|
||||
|
||||
public static EnumHandler getInstance() {
|
||||
EnumHandler localVar = instance;
|
||||
if (localVar != null) {
|
||||
return localVar;
|
||||
}
|
||||
|
||||
synchronized (EnumHandler.class) {
|
||||
if (instance == null) {
|
||||
instance = new EnumHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all block-names in lowercase.
|
||||
*
|
||||
* @return the List
|
||||
*/
|
||||
public List<String> getBlockNames() {
|
||||
public List<String> getAllBlockNames() {
|
||||
return blockNames;
|
||||
}
|
||||
|
||||
@ -44,7 +59,7 @@ public final class EnumHandler {
|
||||
*
|
||||
* @return the List
|
||||
*/
|
||||
public List<String> getItemNames() {
|
||||
public List<String> getAllItemNames() {
|
||||
return itemNames;
|
||||
}
|
||||
|
||||
@ -53,7 +68,7 @@ public final class EnumHandler {
|
||||
*
|
||||
* @return the List
|
||||
*/
|
||||
public List<String> getStatNames() {
|
||||
public List<String> getAllStatNames() {
|
||||
return statNames;
|
||||
}
|
||||
|
||||
@ -64,7 +79,7 @@ public final class EnumHandler {
|
||||
* @return Material enum constant (uppercase), or null if none
|
||||
* can be found
|
||||
*/
|
||||
public static @Nullable Material getItemEnum(String itemName) {
|
||||
public @Nullable Material getItemEnum(String itemName) {
|
||||
if (itemName == null) return null;
|
||||
|
||||
Material item = Material.matchMaterial(itemName);
|
||||
@ -78,7 +93,7 @@ public final class EnumHandler {
|
||||
* @return EntityType enum constant (uppercase), or null if none
|
||||
* can be found
|
||||
*/
|
||||
public static @Nullable EntityType getEntityEnum(String entityName) {
|
||||
public @Nullable EntityType getEntityEnum(String entityName) {
|
||||
try {
|
||||
return EntityType.valueOf(entityName.toUpperCase());
|
||||
}
|
||||
@ -94,7 +109,7 @@ public final class EnumHandler {
|
||||
* @return Material enum constant (uppercase), or null if none
|
||||
* can be found
|
||||
*/
|
||||
public static @Nullable Material getBlockEnum(String materialName) {
|
||||
public @Nullable Material getBlockEnum(String materialName) {
|
||||
if (materialName == null) return null;
|
||||
|
||||
Material block = Material.matchMaterial(materialName);
|
||||
@ -107,7 +122,7 @@ public final class EnumHandler {
|
||||
* @param statName String (case-insensitive)
|
||||
* @return the Statistic enum constant, or null
|
||||
*/
|
||||
public static @Nullable Statistic getStatEnum(@NotNull String statName) {
|
||||
public @Nullable Statistic getStatEnum(@NotNull String statName) {
|
||||
try {
|
||||
return Statistic.valueOf(statName.toUpperCase());
|
||||
}
|
||||
@ -133,7 +148,7 @@ public final class EnumHandler {
|
||||
* @param statName the String to check (case-insensitive)
|
||||
* @return true if this String is a Statistic of Type.Entity
|
||||
*/
|
||||
public boolean isEntityStatistic(String statName) {
|
||||
public boolean isEntityStatistic(@NotNull String statName) {
|
||||
return statName.equalsIgnoreCase(Statistic.ENTITY_KILLED_BY.toString()) ||
|
||||
statName.equalsIgnoreCase(Statistic.KILL_ENTITY.toString());
|
||||
}
|
||||
@ -157,7 +172,7 @@ public final class EnumHandler {
|
||||
* @return "block", "entity", "item", or "sub-statistic" if the
|
||||
* provided Type is null.
|
||||
*/
|
||||
public static String getSubStatTypeName(Statistic.Type statType) {
|
||||
public String getSubStatTypeName(Statistic.Type statType) {
|
||||
String subStat = "sub-statistic";
|
||||
if (statType == null) return subStat;
|
||||
switch (statType) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.artemis.the.gr8.playerstats.utils;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.reload.PlayerLoadAction;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@ -21,31 +22,47 @@ import java.util.function.Predicate;
|
||||
*/
|
||||
public final class OfflinePlayerHandler extends FileHandler {
|
||||
|
||||
private static ConfigHandler config;
|
||||
private static volatile OfflinePlayerHandler instance;
|
||||
private final ConfigHandler config;
|
||||
private static FileConfiguration excludedPlayers;
|
||||
private ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
private ArrayList<String> playerNames;
|
||||
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
|
||||
public OfflinePlayerHandler(ConfigHandler configHandler) {
|
||||
private OfflinePlayerHandler() {
|
||||
super("excluded_players.yml");
|
||||
config = ConfigHandler.getInstance();
|
||||
|
||||
excludedPlayers = super.getFileConfiguration();
|
||||
config = configHandler;
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
public static OfflinePlayerHandler getInstance() {
|
||||
OfflinePlayerHandler localVar = instance;
|
||||
if (localVar != null) {
|
||||
return localVar;
|
||||
}
|
||||
|
||||
synchronized (OfflinePlayerHandler.class) {
|
||||
if (instance == null) {
|
||||
instance = new OfflinePlayerHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
excludedPlayers = super.getFileConfiguration();
|
||||
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given playerName is on the private HashMap of players
|
||||
* that should be included in statistic calculations.
|
||||
* Checks if a given player is currently
|
||||
* included for /statistic lookups.
|
||||
*
|
||||
* @param playerName String (case-sensitive)
|
||||
* @return true if this Player should be included in calculations
|
||||
* @return true if this player is included
|
||||
*/
|
||||
public boolean isRelevantPlayer(String playerName) {
|
||||
return offlinePlayerUUIDs.containsKey(playerName);
|
||||
@ -55,22 +72,20 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
super.addValueToListInFile("excluded", uniqueID);
|
||||
}
|
||||
|
||||
public static boolean isExcluded(UUID uniqueID) {
|
||||
public boolean isExcluded(UUID uniqueID) {
|
||||
List<?> excluded = excludedPlayers.getList("excluded");
|
||||
if (excluded == null) {
|
||||
return false;
|
||||
}
|
||||
for (Object obj : excluded) {
|
||||
if (obj.equals(uniqueID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return excluded.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(obj -> obj.equals(uniqueID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of OfflinePlayers that are included in
|
||||
* statistic calculations.
|
||||
* Gets the number of OfflinePlayers that are
|
||||
* currently included in statistic calculations.
|
||||
*
|
||||
* @return the number of included OfflinePlayers
|
||||
*/
|
||||
@ -84,8 +99,9 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
*
|
||||
* @return the ArrayList
|
||||
*/
|
||||
public ArrayList<String> getOfflinePlayerNames() {
|
||||
return playerNames;
|
||||
@Contract(" -> new")
|
||||
public @NotNull ArrayList<String> getOfflinePlayerNames() {
|
||||
return Collections.list(offlinePlayerUUIDs.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,12 +143,9 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
int size = offlinePlayerUUIDs != null ? offlinePlayerUUIDs.size() : 16;
|
||||
offlinePlayerUUIDs = new ConcurrentHashMap<>(size);
|
||||
|
||||
PlayerLoadAction task = new PlayerLoadAction(offlinePlayers, config.getLastPlayedLimit(), offlinePlayerUUIDs);
|
||||
MyLogger.actionCreated(offlinePlayers != null ? offlinePlayers.length : 0);
|
||||
ForkJoinPool.commonPool().invoke(task);
|
||||
MyLogger.actionFinished();
|
||||
ForkJoinPool.commonPool().invoke(ThreadManager.getPlayerLoadAction(offlinePlayers, offlinePlayerUUIDs));
|
||||
|
||||
playerNames = Collections.list(offlinePlayerUUIDs.keys());
|
||||
MyLogger.actionFinished();
|
||||
MyLogger.logLowLevelTask(("Loaded " + offlinePlayerUUIDs.size() + " offline players"), time);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user