Improved loading-speed for loading offlinePlayers (#63), fixed ban-list-filtering taking a long time (#61), started implementing MyLogger for more advanced debugging (#62)

This commit is contained in:
Artemis-the-gr8 2022-06-23 12:14:57 +02:00
parent 523fd589fb
commit 3e968232c6
14 changed files with 293 additions and 58 deletions

View File

@ -68,8 +68,4 @@ public class Main extends JavaPlugin {
}
this.getLogger().info("Disabled PlayerStats!");
}
public void logTimeTaken(String className, String methodName, long previousTime) {
getLogger().info(className + ", " + methodName + ": " + (System.currentTimeMillis() - previousTime) + "ms");
}
}

View File

@ -5,13 +5,16 @@ import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.command.CommandSender;
public class ThreadManager {
private static final int threshold = 10;
private final int threshold = 10;
private int statThreadID;
private int reloadThreadID;
private final Main plugin;
private final BukkitAudiences adventure;
@ -28,16 +31,27 @@ public class ThreadManager {
messageFactory = m;
plugin = p;
startReloadThread(null, true);
statThreadID = 0;
reloadThreadID = 0;
startReloadThread(null);
}
public void startReloadThread(CommandSender sender, boolean firstTimeLoading) {
reloadThread = new ReloadThread(adventure, config, messageFactory, plugin, threshold, firstTimeLoading, statThread, sender);
public void startReloadThread(CommandSender sender) {
if (reloadThread == null || !reloadThread.isAlive()) {
reloadThreadID += 1;
reloadThread = new ReloadThread(adventure, config, messageFactory, plugin, threshold, reloadThreadID, statThread, sender);
reloadThread.start();
}
else {
MyLogger.threadAlreadyRunning(reloadThread.getName());
}
}
public void startStatThread(StatRequest request) {
statThread = new StatThread(adventure, config, messageFactory, plugin, threshold, request, reloadThread);
statThreadID += 1;
statThread = new StatThread(adventure, config, messageFactory, plugin, statThreadID, threshold, request, reloadThread);
statThread.start();
}

View File

@ -17,7 +17,7 @@ public class ReloadCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
threadManager.startReloadThread(sender, false);
threadManager.startReloadThread(sender);
return true;
}
}

View File

@ -169,7 +169,7 @@ public class StatCommand implements CommandExecutor {
request.setPlayerName(sender.getName());
request.setSelection(Query.PLAYER);
}
else if (OfflinePlayerHandler.isOfflinePlayerName(arg) && request.getPlayerName() == null) {
else if (OfflinePlayerHandler.isRelevantPlayer(arg) && request.getPlayerName() == null) {
request.setPlayerName(arg);
request.setSelection(Query.PLAYER);
}

View File

@ -2,6 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.config;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.enums.Query;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
@ -24,15 +25,27 @@ public class ConfigHandler {
configVersion = 3.1;
checkConfigVersion();
MyLogger.setDebugLevel(debugLevel());
}
/** Reloads the config from file, or creates a new file with default values if there is none. */
/** Returns the desired debugging level.
<p>1 = low (only show unexpected errors)</p>
<p>2 = medium (show all encountered exceptions, log main tasks and show time taken)</p>
<p>3 = high (log all tasks and time taken)</p>
<p>Default: 1</p>*/
public int debugLevel() {
return config.getInt("debug-level", 1);
}
/** Reloads the config from file, or creates a new file with default values if there is none.
Also reads the value for debug-level and passes it on to MyLogger. */
public boolean reloadConfig() {
try {
if (!configFile.exists()) {
saveDefaultConfig();
}
config = YamlConfiguration.loadConfiguration(configFile);
MyLogger.setDebugLevel(debugLevel());
return true;
}
catch (Exception e) {

View File

@ -0,0 +1,5 @@
package com.gmail.artemis.the.gr8.playerstats.enums;
public enum DebugLevel {
LOW, MEDIUM, HIGH
}

View File

@ -16,7 +16,7 @@ public class JoinListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
if (!joinEvent.getPlayer().hasPlayedBefore()) {
threadManager.startReloadThread(null, false);
threadManager.startReloadThread(null);
}
}
}

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.reload;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.UnixTimeHandler;
import org.bukkit.OfflinePlayer;
@ -15,40 +16,33 @@ public class ReloadAction extends RecursiveAction {
private final int start;
private final int end;
private final boolean whitelistOnly;
private final boolean excludeBanned;
private final int lastPlayedLimit;
private final ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
/** Fills a ConcurrentHashMap with PlayerNames and UUIDs for all OfflinePlayers that should be included in statistic calculations.
* @param threshold the maximum length of OfflinePlayers to process in one task
* @param players array of all OfflinePlayers (straight from Bukkit)
* @param whitelistOnly whether to limit players based on the whitelist
* @param excludeBanned whether to exclude banned players
* @param lastPlayedLimit whether to set a limit based on last-played-date
* @param offlinePlayerUUIDs the ConcurrentHashMap to put resulting playerNames and UUIDs on
*/
public ReloadAction(int threshold, OfflinePlayer[] players,
boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit,
ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
this(threshold, players, 0, players.length,
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
this(threshold, players, 0, players.length, lastPlayedLimit, offlinePlayerUUIDs);
}
protected ReloadAction(int threshold, OfflinePlayer[] players, int start, int end,
boolean whitelistOnly, boolean excludeBanned, int lastPlayedLimit,
ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
this.threshold = threshold;
this.players = players;
this.start = start;
this.end = end;
this.whitelistOnly = whitelistOnly;
this.excludeBanned = excludeBanned;
this.lastPlayedLimit = lastPlayedLimit;
this.offlinePlayerUUIDs = offlinePlayerUUIDs;
MyLogger.subActionCreated(Thread.currentThread().getName());
}
@Override
@ -60,9 +54,9 @@ public class ReloadAction extends RecursiveAction {
else {
final int split = length / 2;
final ReloadAction subTask1 = new ReloadAction(threshold, players, start, (start + split),
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
lastPlayedLimit, offlinePlayerUUIDs);
final ReloadAction subTask2 = new ReloadAction(threshold, players, (start + split), end,
whitelistOnly, excludeBanned, lastPlayedLimit, offlinePlayerUUIDs);
lastPlayedLimit, offlinePlayerUUIDs);
//queue and compute all subtasks in the right order
invokeAll(subTask1, subTask2);
@ -72,11 +66,11 @@ public class ReloadAction extends RecursiveAction {
private void process() {
for (int i = start; i < end; i++) {
OfflinePlayer player = players[i];
if (player.getName() != null &&
(!whitelistOnly || player.isWhitelisted()) &&
(!excludeBanned || !player.isBanned()) &&
String playerName = player.getName();
MyLogger.actionRunning(Thread.currentThread().getName(), playerName, 1);
if (playerName != null &&
(lastPlayedLimit == 0 || UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed()))) {
offlinePlayerUUIDs.put(player.getName(), player.getUniqueId());
offlinePlayerUUIDs.put(playerName, player.getUniqueId());
}
}
}

View File

@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit;
@ -13,7 +14,9 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinPool;
@ -21,6 +24,7 @@ import java.util.concurrent.ForkJoinPool;
public class ReloadThread extends Thread {
private final int threshold;
private final int reloadThreadID;
private final BukkitAudiences adventure;
private static ConfigHandler config;
@ -29,10 +33,11 @@ public class ReloadThread extends Thread {
private final StatThread statThread;
private final CommandSender sender;
private final boolean firstTimeLoading;
public ReloadThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, boolean firstTime, @Nullable StatThread s, @Nullable CommandSender se) {
public ReloadThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, int ID, @Nullable StatThread s, @Nullable CommandSender se) {
this.threshold = threshold;
reloadThreadID = ID;
adventure = a;
config = c;
messageFactory = m;
@ -40,18 +45,21 @@ public class ReloadThread extends Thread {
statThread = s;
sender = se;
firstTimeLoading = firstTime;
this.setName("ReloadThread-" + reloadThreadID);
MyLogger.threadCreated(this.getName());
}
@Override
public void run() {
long time = System.currentTimeMillis();
MyLogger.threadStart(this.getName());
//if reload is triggered by /statreload...
if (!firstTimeLoading) {
//if reload is triggered by /statreload (aka this thread does not have ID number 1)...
if (reloadThreadID != 1) {
if (statThread != null && statThread.isAlive()) {
try {
plugin.getLogger().info("Waiting for statThread to finish up...");
MyLogger.waitingForOtherThread(this.getName(), statThread.getName());
statThread.join();
} catch (InterruptedException e) {
plugin.getLogger().warning(e.toString());
@ -62,7 +70,7 @@ public class ReloadThread extends Thread {
if (config.reloadConfig()) {
try {
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(false));
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap());
}
catch (ConcurrentModificationException e) {
plugin.getLogger().warning("The request could not be fully executed due to a ConcurrentModificationException");
@ -71,7 +79,7 @@ public class ReloadThread extends Thread {
}
}
plugin.logTimeTaken("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time);
MyLogger.logTimeTakenDefault("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time);
if (sender != null) {
adventure.sender(sender).sendMessage(messageFactory.reloadedConfig(sender instanceof ConsoleCommandSender));
}
@ -79,26 +87,36 @@ public class ReloadThread extends Thread {
}
//during first start-up...
else {
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap(true));
plugin.logTimeTaken("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time);
OfflinePlayerHandler.updateOfflinePlayerList(getPlayerMap());
MyLogger.logTimeTakenDefault("ReloadThread", ("loaded " + OfflinePlayerHandler.getOfflinePlayerCount() + " offline players"), time);
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
}
}
private ConcurrentHashMap<String, UUID> getPlayerMap(boolean firstTimeLoading) {
OfflinePlayer[] offlinePlayers = Bukkit.getOfflinePlayers();
int size;
if (firstTimeLoading) {
size = offlinePlayers.length;
private ConcurrentHashMap<String, UUID> getPlayerMap() {
long time = System.currentTimeMillis();
OfflinePlayer[] offlinePlayers;
if (config.whitelistOnly()) {
offlinePlayers = Bukkit.getWhitelistedPlayers().toArray(OfflinePlayer[]::new);
MyLogger.logTimeTaken("ReloadThread", "getting white-list-only list", time);
}
else if (config.excludeBanned()) {
Set<OfflinePlayer> bannedPlayers = Bukkit.getBannedPlayers();
offlinePlayers = Arrays.stream(Bukkit.getOfflinePlayers())
.parallel()
.filter(offlinePlayer -> !bannedPlayers.contains(offlinePlayer)).toArray(OfflinePlayer[]::new);
MyLogger.logTimeTaken("ReloadThread", "getting excluding-banned-players list", time);
}
else {
size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? OfflinePlayerHandler.getOfflinePlayerCount() : 16;
offlinePlayers = Bukkit.getOfflinePlayers();
MyLogger.logTimeTaken("ReloadThread", "getting regular player list", time);
}
int size = offlinePlayers != null ? offlinePlayers.length : 16;
ConcurrentHashMap<String, UUID> playerMap = new ConcurrentHashMap<>(size);
ReloadAction task = new ReloadAction(threshold, offlinePlayers, config.whitelistOnly(), config.excludeBanned(), config.lastPlayedLimit(), playerMap);
ReloadAction task = new ReloadAction(threshold, offlinePlayers, config.lastPlayedLimit(), playerMap);
MyLogger.actionCreated((offlinePlayers != null) ? offlinePlayers.length : 0);
ForkJoinPool commonPool = ForkJoinPool.commonPool();
try {
@ -106,6 +124,8 @@ public class ReloadThread extends Thread {
} catch (ConcurrentModificationException e) {
throw new ConcurrentModificationException(e.toString());
}
MyLogger.actionFinished(1);
return playerMap;
}

View File

@ -5,6 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.Query;
import com.gmail.artemis.the.gr8.playerstats.reload.ReloadThread;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.gmail.artemis.the.gr8.playerstats.msg.MessageFactory;
import com.google.common.collect.ImmutableList;
@ -23,6 +24,7 @@ import java.util.stream.Collectors;
public class StatThread extends Thread {
private final int threshold;
private final StatRequest request;
private final ReloadThread reloadThread;
@ -32,8 +34,9 @@ public class StatThread extends Thread {
private final Main plugin;
//constructor (called on thread creation)
public StatThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int threshold, StatRequest s, @Nullable ReloadThread r) {
public StatThread(BukkitAudiences a, ConfigHandler c, MessageFactory m, Main p, int ID, int threshold, StatRequest s, @Nullable ReloadThread r) {
this.threshold = threshold;
request = s;
reloadThread = r;
@ -41,11 +44,16 @@ public class StatThread extends Thread {
config = c;
messageFactory = m;
plugin = p;
this.setName("StatThread-" + ID);
MyLogger.threadCreated(this.getName());
}
//what the thread will do once started
@Override
public void run() throws IllegalStateException, NullPointerException {
MyLogger.threadStart(this.getName());
if (messageFactory == null || plugin == null) {
throw new IllegalStateException("Not all classes off the plugin are running!");
}
@ -54,8 +62,10 @@ public class StatThread extends Thread {
}
if (reloadThread != null && reloadThread.isAlive()) {
try {
plugin.getLogger().info("Waiting for reloadThread to finish up...");
adventure.sender(request.getCommandSender()).sendMessage(messageFactory.stillReloading(request.getCommandSender() instanceof ConsoleCommandSender));
MyLogger.waitingForOtherThread(this.getName(), reloadThread.getName());
adventure.sender(request.getCommandSender())
.sendMessage(messageFactory
.stillReloading(request.getCommandSender() instanceof ConsoleCommandSender));
reloadThread.join();
} catch (InterruptedException e) {
plugin.getLogger().warning(e.toString());
@ -128,10 +138,11 @@ public class StatThread extends Thread {
int size = OfflinePlayerHandler.getOfflinePlayerCount() != 0 ? (int) (OfflinePlayerHandler.getOfflinePlayerCount() * 1.05) : 16;
ConcurrentHashMap<String, Integer> playerStats = new ConcurrentHashMap<>(size);
ImmutableList<String> playerNames = ImmutableList.copyOf(OfflinePlayerHandler.getOfflinePlayerNames());
TopStatAction task = new TopStatAction(threshold, playerNames,
request, playerStats);
TopStatAction task = new TopStatAction(threshold, playerNames, request, playerStats);
MyLogger.actionCreated(playerNames.size());
ForkJoinPool commonPool = ForkJoinPool.commonPool();
try {
commonPool.invoke(task);
} catch (ConcurrentModificationException e) {
@ -140,8 +151,9 @@ public class StatThread extends Thread {
throw new ConcurrentModificationException(e.toString());
}
MyLogger.actionFinished(2);
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
plugin.logTimeTaken("StatThread", "calculated all stats", time);
MyLogger.logTimeTakenDefault("StatThread", "calculated all stats", time);
return playerStats;
}

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.google.common.collect.ImmutableList;
import org.bukkit.OfflinePlayer;
@ -31,6 +32,8 @@ public class TopStatAction extends RecursiveAction {
this.request = statRequest;
this.playerStats = playerStats;
MyLogger.subActionCreated(Thread.currentThread().getName());
}
@Override
@ -53,6 +56,7 @@ public class TopStatAction extends RecursiveAction {
if (iterator.hasNext()) {
do {
String playerName = iterator.next();
MyLogger.actionRunning(Thread.currentThread().getName(), playerName, 2);
OfflinePlayer player = OfflinePlayerHandler.getOfflinePlayer(playerName);
if (player != null) {
int statistic = 0;

View File

@ -0,0 +1,166 @@
package com.gmail.artemis.the.gr8.playerstats.utils;
import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
public class MyLogger {
private static final Logger logger;
private static DebugLevel debugLevel;
private static final String[] processedPlayers;
private static final AtomicInteger playersIndex;
private static ConcurrentHashMap<String, Integer> threadNames;
static{
Plugin plugin = Bukkit.getPluginManager().getPlugin("PlayerStats");
logger = plugin != null ? plugin.getLogger() : Bukkit.getLogger();
debugLevel = DebugLevel.LOW;
processedPlayers = new String[10];
playersIndex = new AtomicInteger(0);
threadNames = new ConcurrentHashMap<>();
}
private MyLogger() {
}
/** Accesses the playersIndex to up it by 1 and return its previous value. */
private static int nextPlayersIndex() {
return playersIndex.getAndIncrement();
}
/** Returns true if the playersIndex is 10, or any subsequent increment of 10. */
private static boolean incrementOfTen() {
return (playersIndex.get() == 10 || (playersIndex.get() > 10 && playersIndex.get() % 10 == 0));
}
/** Sets the desired debugging level.
<p>1 = low (only show unexpected errors)</p>
<p>2 = medium (show all encountered exceptions, log main tasks and show time taken)</p>
<p>3 = high (log all tasks and time taken)</p>
<p>Default: 1</p>*/
public static void setDebugLevel(int level) {
if (level == 2) {
debugLevel = DebugLevel.MEDIUM;
}
else if (level == 3) {
debugLevel = DebugLevel.HIGH;
}
else {
debugLevel = DebugLevel.LOW;
}
}
/** Output to console that the given thread has been created (but not started yet).*/
public static void threadCreated(String threadName) {
if (debugLevel != DebugLevel.LOW) {
logger.info(threadName + " created!");
}
}
/** Output to console that the given thread has been started. */
public static void threadStart(String threadName) {
if (debugLevel == DebugLevel.MEDIUM || debugLevel == DebugLevel.HIGH) {
logger.info(threadName + " started!");
}
}
/** Output to console that another reloadThread is already running. */
public static void threadAlreadyRunning(String threadName) {
logger.info("Another reloadThread is already running! (" + threadName + ")");
}
/** Output to console that the executingThread is waiting for otherThread to finish up. */
public static void waitingForOtherThread(String executingThread, String otherThread) {
logger.info(executingThread + ": Waiting for " + otherThread + " to finish up...");
}
/** If DebugLevel is MEDIUM or HIGH, output to console that an action has started.
@param taskLength Length of the action (in terms of units-to-process)*/
public static void actionCreated(int taskLength) {
if (debugLevel != DebugLevel.LOW) {
threadNames = new ConcurrentHashMap<>();
playersIndex.set(0);
logger.info("Initial Action created for " + taskLength + " Players. Start Index is " + playersIndex.get() + ". Processing...");
}
}
/** Internally save the name of the executing thread for later logging of this action.
The list of names is reset upon the start of every new action.
@param threadName Name of the executing thread*/
public static void subActionCreated(String threadName) {
if (debugLevel == DebugLevel.HIGH) {
if (!threadNames.containsKey(threadName)) {
threadNames.put(threadName, threadNames.size());
}
}
}
/** Internally save the name of the executing thread and processed player for logging,
and for the ReloadThread, if DebugLevel is HIGH, output the last 10 processed players once
there have been 10 names saved in MyLogger. This method is synchronized.
@param threadName Name of the executing thread
@param playerName Name of the player that was processed in this action
@param thread 1 for ReloadThread, 2 for StatThread */
public static synchronized void actionRunning(String threadName, String playerName, int thread) {
if (debugLevel != DebugLevel.LOW) {
if (!threadNames.containsKey(threadName)) {
threadNames.put(threadName, threadNames.size());
}
if (thread == 1 && debugLevel == DebugLevel.HIGH) {
if (incrementOfTen()) {
logger.info(Arrays.asList(processedPlayers).toString());
}
processedPlayers[nextPlayersIndex() % 10] = playerName;
}
else if (debugLevel == DebugLevel.MEDIUM) {
nextPlayersIndex();
}
}
}
/** Output to console that an action has finished.
<p>For the ReloadThread, if DebugLevel is HIGH, output the left-over processed players.
For both threads, if DebugLevel is MEDIUM or HIGH, output the names of the threads that were used.</p>
@param thread 1 for ReloadThread, 2 for StatThread */
public static void actionFinished(int thread) {
if (thread == 1 && debugLevel == DebugLevel.HIGH) {
ArrayList<String> leftOvers = new ArrayList<>(Arrays.asList(processedPlayers).subList(playersIndex.intValue() % 10, 10));
logger.info(leftOvers.toString());
}
if (debugLevel != DebugLevel.LOW) {
logger.info("Finished Recursive Action! In total " +
threadNames.size() + " Threads were used to process " +
playersIndex.get() + " Players: " +
Collections.list(threadNames.keys()));
}
}
/** Output to console how long a certain task has taken if DebugLevel is MEDIUM or HIGH.
@param className Name of the class executing the task
@param methodName Name or description of the task
@param startTime Timestamp marking the beginning of the task */
public static void logTimeTaken(String className, String methodName, long startTime) {
if (debugLevel != DebugLevel.LOW) {
logger.info(className + " " + methodName + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
}
/** Output to console how long a certain task has taken (regardless of DebugLevel).
@param className Name of the class executing the task
@param methodName Name or description of the task
@param startTime Timestamp marking the beginning of the task */
public static void logTimeTakenDefault(String className, String methodName, long startTime) {
logger.info(className + " " + methodName + ":" + (System.currentTimeMillis() - startTime) + "ms");
}
}

View File

@ -12,18 +12,23 @@ public class OfflinePlayerHandler {
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
private static ArrayList<String> playerNames;
static{
offlinePlayerUUIDs = new ConcurrentHashMap<>();
playerNames = new ArrayList<>();
}
private OfflinePlayerHandler() {
}
/** Checks if a given playerName is on the private HashMap of players that should be included in statistic calculations
@param playerName String, case-sensitive */
public static boolean isOfflinePlayerName(String playerName) {
public static boolean isRelevantPlayer(String playerName) {
return offlinePlayerUUIDs.containsKey(playerName);
}
/** Returns the number of OfflinePlayers that are included in statistic calculations */
public static int getOfflinePlayerCount() {
return offlinePlayerUUIDs != null ? offlinePlayerUUIDs.size() : 0;
return offlinePlayerUUIDs.size();
}
/** Get an ArrayList of names from all OfflinePlayers that should be included in statistic calculations */

View File

@ -8,6 +8,12 @@ config-version: 3.1
# # General # #
# # ------------------------------- # #
# How much output in console you'll get while PlayerStats is processing
# 1 = low (only show unexpected errors)
# 2 = medium (show all encountered exceptions, log main tasks and show time taken)
# 3 = high (log all tasks and time taken)
debug-level: 1
# Filtering options to control which players should be included in statistic calculations
include-whitelist-only: false
exclude-banned-players: false