mirror of
https://github.com/itHotL/PlayerStats.git
synced 2025-01-07 19:27:47 +01:00
Separated initial plugin set-up from reloading and organized responsibilities better for the OfflinePlayerHandler, ThreadManager and the classes implementing FileHandler
This commit is contained in:
parent
3417233dec
commit
9ac77a365b
@ -168,7 +168,7 @@ public final class Main extends JavaPlugin {
|
||||
config = new ConfigHandler();
|
||||
enumHandler = new EnumHandler();
|
||||
languageKeyHandler = new LanguageKeyHandler();
|
||||
offlinePlayerHandler = new OfflinePlayerHandler();
|
||||
offlinePlayerHandler = new OfflinePlayerHandler(config);
|
||||
|
||||
shareManager = new ShareManager(config);
|
||||
statCalculator = new StatCalculator(offlinePlayerHandler);
|
||||
|
@ -45,8 +45,6 @@ public final class ThreadManager {
|
||||
statThreadID = 0;
|
||||
reloadThreadID = 0;
|
||||
lastRecordedCalcTime = 0;
|
||||
|
||||
startReloadThread(null);
|
||||
}
|
||||
|
||||
public static int getTaskThreshold() {
|
||||
|
@ -512,6 +512,7 @@ public final class MessageBuilder implements ApiFormatter {
|
||||
return componentFactory.statAndSubStatNameTranslatable(statKey, subStatKey, target);
|
||||
}
|
||||
|
||||
//TODO turn key into custom input from file
|
||||
String prettyStatName = StringUtils.prettify(statistic.toString());
|
||||
String prettySubStatName = StringUtils.prettify(subStatName);
|
||||
return componentFactory.statAndSubStatName(prettyStatName, prettySubStatName, target);
|
||||
|
@ -13,7 +13,7 @@ import java.util.concurrent.RecursiveAction;
|
||||
/**
|
||||
* The action that is executed when a reload-command is triggered.
|
||||
*/
|
||||
final class ReloadAction extends RecursiveAction {
|
||||
public final class PlayerLoadAction extends RecursiveAction {
|
||||
|
||||
private static int threshold;
|
||||
|
||||
@ -33,14 +33,14 @@ final class ReloadAction extends RecursiveAction {
|
||||
* @param offlinePlayerUUIDs the ConcurrentHashMap to put playerNames and UUIDs in
|
||||
* @see OfflinePlayerHandler
|
||||
*/
|
||||
public ReloadAction(OfflinePlayer[] players,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
public PlayerLoadAction(OfflinePlayer[] players,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
|
||||
this(players, 0, players.length, lastPlayedLimit, offlinePlayerUUIDs);
|
||||
}
|
||||
|
||||
private ReloadAction(OfflinePlayer[] players, int start, int end,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
private PlayerLoadAction(OfflinePlayer[] players, int start, int end,
|
||||
int lastPlayedLimit, ConcurrentHashMap<String, UUID> offlinePlayerUUIDs) {
|
||||
threshold = ThreadManager.getTaskThreshold();
|
||||
|
||||
this.players = players;
|
||||
@ -61,9 +61,9 @@ final class ReloadAction extends RecursiveAction {
|
||||
}
|
||||
else {
|
||||
final int split = length / 2;
|
||||
final ReloadAction subTask1 = new ReloadAction(players, start, (start + split),
|
||||
final PlayerLoadAction subTask1 = new PlayerLoadAction(players, start, (start + split),
|
||||
lastPlayedLimit, offlinePlayerUUIDs);
|
||||
final ReloadAction subTask2 = new ReloadAction(players, (start + split), end,
|
||||
final PlayerLoadAction subTask2 = new PlayerLoadAction(players, (start + split), end,
|
||||
lastPlayedLimit, offlinePlayerUUIDs);
|
||||
|
||||
//queue and compute all subtasks in the right order
|
@ -2,25 +2,17 @@ package com.artemis.the.gr8.playerstats.reload;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.Main;
|
||||
import com.artemis.the.gr8.playerstats.ShareManager;
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
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.StatCalculator;
|
||||
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.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.enums.DebugLevel;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** The Thread that is in charge of reloading PlayerStats. */
|
||||
public final class ReloadThread extends Thread {
|
||||
@ -28,35 +20,31 @@ public final class ReloadThread extends Thread {
|
||||
private static ConfigHandler config;
|
||||
private static OutputManager outputManager;
|
||||
|
||||
private final int reloadThreadID;
|
||||
private final StatThread statThread;
|
||||
|
||||
private final CommandSender sender;
|
||||
|
||||
public ReloadThread(ConfigHandler c, OutputManager m, int ID, @Nullable StatThread s, @Nullable CommandSender se) {
|
||||
config = c;
|
||||
outputManager = m;
|
||||
|
||||
reloadThreadID = ID;
|
||||
statThread = s;
|
||||
sender = se;
|
||||
|
||||
this.setName("ReloadThread-" + reloadThreadID);
|
||||
this.setName("ReloadThread-" + ID);
|
||||
MyLogger.logHighLevelMsg(this.getName() + " created!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will perform a series of tasks. 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 offlinePlayerList in the
|
||||
* {@link OfflinePlayerHandler}, update the {@link DebugLevel}, update
|
||||
* 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 StatCalculator}, and update the MessageBuilders in the
|
||||
* {@link OutputManager}.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
long time = System.currentTimeMillis();
|
||||
MyLogger.logHighLevelMsg(this.getName() + " started!");
|
||||
|
||||
if (statThread != null && statThread.isAlive()) {
|
||||
@ -69,18 +57,11 @@ public final class ReloadThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
if (reloadThreadID != 1) { //during a reload
|
||||
MyLogger.logLowLevelMsg("Reloading!");
|
||||
reloadEverything();
|
||||
MyLogger.logLowLevelMsg("Reloading!");
|
||||
reloadEverything();
|
||||
|
||||
if (sender != null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.RELOADED_CONFIG);
|
||||
}
|
||||
}
|
||||
else { //during first start-up
|
||||
MyLogger.setDebugLevel(config.getDebugLevel());
|
||||
OfflinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
if (sender != null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.RELOADED_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,51 +70,8 @@ public final class ReloadThread extends Thread {
|
||||
MyLogger.setDebugLevel(config.getDebugLevel());
|
||||
Main.getLanguageKeyHandler().reload();
|
||||
Main.getOfflinePlayerHandler().reload();
|
||||
|
||||
OutputManager.updateMessageBuilders();
|
||||
OfflinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
|
||||
ShareManager.updateSettings(config);
|
||||
}
|
||||
|
||||
private ConcurrentHashMap<String, UUID> loadOfflinePlayers() {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
OfflinePlayer[] offlinePlayers;
|
||||
if (config.whitelistOnly()) {
|
||||
offlinePlayers = Bukkit.getWhitelistedPlayers().toArray(OfflinePlayer[]::new);
|
||||
MyLogger.logMediumLevelTask("ReloadThread",
|
||||
"retrieved whitelist", time);
|
||||
}
|
||||
else if (config.excludeBanned()) {
|
||||
if (Bukkit.getPluginManager().getPlugin("LiteBans") != null) {
|
||||
offlinePlayers = Arrays.stream(Bukkit.getOfflinePlayers())
|
||||
.parallel()
|
||||
.filter(Predicate.not(OfflinePlayer::isBanned))
|
||||
.toArray(OfflinePlayer[]::new);
|
||||
} else {
|
||||
Set<OfflinePlayer> bannedPlayers = Bukkit.getBannedPlayers();
|
||||
offlinePlayers = Arrays.stream(Bukkit.getOfflinePlayers())
|
||||
.parallel()
|
||||
.filter(offlinePlayer -> !bannedPlayers.contains(offlinePlayer)).toArray(OfflinePlayer[]::new);
|
||||
}
|
||||
MyLogger.logMediumLevelTask("ReloadThread",
|
||||
"retrieved banlist", time);
|
||||
}
|
||||
else {
|
||||
offlinePlayers = Bukkit.getOfflinePlayers();
|
||||
MyLogger.logMediumLevelTask("ReloadThread",
|
||||
"retrieved list of Offline Players", time);
|
||||
}
|
||||
|
||||
int size = offlinePlayers != null ? offlinePlayers.length : 16;
|
||||
ConcurrentHashMap<String, UUID> playerMap = new ConcurrentHashMap<>(size);
|
||||
|
||||
ReloadAction task = new ReloadAction(offlinePlayers, config.getLastPlayedLimit(), playerMap);
|
||||
MyLogger.actionCreated((offlinePlayers != null) ? offlinePlayers.length : 0);
|
||||
ForkJoinPool.commonPool().invoke(task);
|
||||
MyLogger.actionFinished();
|
||||
|
||||
MyLogger.logLowLevelTask("ReloadThread",
|
||||
("loaded " + playerMap.size() + " offline players"), time);
|
||||
return playerMap;
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ public final class StatCalculator {
|
||||
|
||||
MyLogger.actionFinished();
|
||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||
MyLogger.logMediumLevelTask("StatThread", "calculated all stats", time);
|
||||
MyLogger.logMediumLevelTask("Calculated all stats", time);
|
||||
|
||||
return allStats;
|
||||
}
|
||||
|
@ -53,12 +53,22 @@ public final class MyLogger {
|
||||
logger.info(content);
|
||||
}
|
||||
|
||||
public static void logLowLevelTask(String taskName, long startTime) {
|
||||
printTime(taskName, startTime);
|
||||
}
|
||||
|
||||
public static void logMediumLevelMsg(String content) {
|
||||
if (debugLevel != DebugLevel.LOW) {
|
||||
logger.info(content);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logMediumLevelTask(String taskName, long startTime) {
|
||||
if (debugLevel != DebugLevel.LOW) {
|
||||
printTime(taskName, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logHighLevelMsg(String content) {
|
||||
if (debugLevel == DebugLevel.HIGH) {
|
||||
logger.info(content);
|
||||
@ -146,24 +156,13 @@ public final class MyLogger {
|
||||
}
|
||||
}
|
||||
|
||||
public static void logMediumLevelTask(String className, String methodName, long startTime) {
|
||||
if (debugLevel != DebugLevel.LOW) {
|
||||
printTime(className, methodName, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logLowLevelTask(String className, String methodName, long startTime) {
|
||||
printTime(className, methodName, startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output to console how long a certain task has taken.
|
||||
*
|
||||
* @param className Name of the class executing the task
|
||||
* @param methodName Name or description of the task
|
||||
* @param taskName name of the task that has been executed
|
||||
* @param startTime Timestamp marking the beginning of the task
|
||||
*/
|
||||
private static void printTime(String className, String methodName, long startTime) {
|
||||
logger.info(className + " " + methodName + ": " + (System.currentTimeMillis() - startTime) + "ms");
|
||||
private static void printTime(String taskName, long startTime) {
|
||||
logger.info(taskName + " (" + (System.currentTimeMillis() - startTime) + "ms)");
|
||||
}
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
package com.artemis.the.gr8.playerstats.utils;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.reload.PlayerLoadAction;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A utility class that deals with OfflinePlayers. It stores a list
|
||||
@ -14,30 +19,20 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public final class OfflinePlayerHandler extends FileHandler {
|
||||
|
||||
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
private static ArrayList<String> playerNames;
|
||||
private static ConfigHandler config;
|
||||
private ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
private ArrayList<String> playerNames;
|
||||
|
||||
public OfflinePlayerHandler() {
|
||||
public OfflinePlayerHandler(ConfigHandler configHandler) {
|
||||
super("excluded_players.yml");
|
||||
offlinePlayerUUIDs = new ConcurrentHashMap<>();
|
||||
playerNames = new ArrayList<>();
|
||||
config = configHandler;
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,4 +86,51 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
throw new IllegalArgumentException("Cannot convert this player-name into a valid Player to calculate statistics for");
|
||||
}
|
||||
}
|
||||
|
||||
private void loadOfflinePlayers() {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
OfflinePlayer[] offlinePlayers;
|
||||
if (config.whitelistOnly()) {
|
||||
offlinePlayers = getWhitelistedPlayers();
|
||||
}
|
||||
else if (config.excludeBanned()) {
|
||||
offlinePlayers = getNonBannedPlayers();
|
||||
}
|
||||
else {
|
||||
offlinePlayers = Bukkit.getOfflinePlayers();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
playerNames = Collections.list(offlinePlayerUUIDs.keys());
|
||||
MyLogger.logLowLevelTask(("Loaded " + offlinePlayerUUIDs.size() + " offline players"), time);
|
||||
});
|
||||
}
|
||||
|
||||
private OfflinePlayer[] getWhitelistedPlayers() {
|
||||
return Bukkit.getWhitelistedPlayers().toArray(OfflinePlayer[]::new);
|
||||
}
|
||||
|
||||
private OfflinePlayer[] getNonBannedPlayers() {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LiteBans")) {
|
||||
return Arrays.stream(Bukkit.getOfflinePlayers())
|
||||
.parallel()
|
||||
.filter(Predicate.not(OfflinePlayer::isBanned))
|
||||
.toArray(OfflinePlayer[]::new);
|
||||
}
|
||||
|
||||
Set<OfflinePlayer> banList = Bukkit.getBannedPlayers();
|
||||
return Arrays.stream(Bukkit.getOfflinePlayers())
|
||||
.parallel()
|
||||
.filter(Predicate.not(banList::contains))
|
||||
.toArray(OfflinePlayer[]::new);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
# Players whose UUIDs are stored in this file, will not be included in /statistic results.
|
||||
# This can be used for more fine-grained filtering, for example to exclude alt accounts.
|
||||
# For more general filtering settings, see the config.yml
|
||||
# For more general filtering settings, see the config.yml (section 'General')
|
||||
|
||||
excluded:
|
||||
-
|
@ -2,6 +2,9 @@
|
||||
# PlayerStats Language File #
|
||||
# ------------------------------------------------------------------------------------------------------ #
|
||||
|
||||
# If "translate-to-client-language" in the config.yml is set to false (section 'Format & Display'),
|
||||
# values from this file will be used instead
|
||||
|
||||
stat_type.minecraft.mined: "Times Mined"
|
||||
stat_type.minecraft.crafted: "Times Crafted"
|
||||
stat_type.minecraft.used: "Times Used"
|
||||
|
Loading…
Reference in New Issue
Block a user