mirror of
https://github.com/itHotL/PlayerStats.git
synced 2024-11-29 13:05:32 +01:00
Got rough version of API to work!
This commit is contained in:
parent
54040c4e3d
commit
de150bfe51
@ -21,20 +21,11 @@ public class Main extends JavaPlugin {
|
|||||||
|
|
||||||
private static BukkitAudiences adventure;
|
private static BukkitAudiences adventure;
|
||||||
private static PlayerStats playerStatsAPI;
|
private static PlayerStats playerStatsAPI;
|
||||||
|
private static OutputManager outputManager;
|
||||||
|
private static ShareManager shareManager;
|
||||||
|
private static StatManager statManager;
|
||||||
|
private static ThreadManager threadManager;
|
||||||
|
|
||||||
public static @NotNull BukkitAudiences adventure() throws IllegalStateException {
|
|
||||||
if (adventure == null) {
|
|
||||||
throw new IllegalStateException("Tried to access Adventure without PlayerStats being enabled!");
|
|
||||||
}
|
|
||||||
return adventure;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull PlayerStats getPlayerStatsAPI() throws IllegalStateException {
|
|
||||||
if (playerStatsAPI == null) {
|
|
||||||
throw new IllegalStateException("PlayerStats does not seem to be loaded!");
|
|
||||||
}
|
|
||||||
return playerStatsAPI;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@ -42,14 +33,8 @@ public class Main extends JavaPlugin {
|
|||||||
ConfigHandler config = new ConfigHandler(this);
|
ConfigHandler config = new ConfigHandler(this);
|
||||||
OfflinePlayerHandler offlinePlayerHandler = new OfflinePlayerHandler();
|
OfflinePlayerHandler offlinePlayerHandler = new OfflinePlayerHandler();
|
||||||
|
|
||||||
OutputManager outputManager = OutputManager.getInstance(config);
|
//initialize all the Managers and the API
|
||||||
StatManager statManager = StatManager.getInstance(outputManager, offlinePlayerHandler);
|
initializeMainClasses(config, offlinePlayerHandler);
|
||||||
ThreadManager threadManager = ThreadManager.getInstance(config, outputManager, statManager, offlinePlayerHandler);
|
|
||||||
ShareManager shareManager = ShareManager.getInstance(config);
|
|
||||||
|
|
||||||
//initialize the Adventure library and the API
|
|
||||||
adventure = BukkitAudiences.create(this);
|
|
||||||
playerStatsAPI = PlayerStatsAPI.load(this, threadManager, outputManager, statManager);
|
|
||||||
|
|
||||||
//register all commands and the tabCompleter
|
//register all commands and the tabCompleter
|
||||||
PluginCommand statcmd = this.getCommand("statistic");
|
PluginCommand statcmd = this.getCommand("statistic");
|
||||||
@ -77,4 +62,57 @@ public class Main extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
this.getLogger().info("Disabled PlayerStats!");
|
this.getLogger().info("Disabled PlayerStats!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @NotNull BukkitAudiences getAdventure() throws IllegalStateException {
|
||||||
|
if (adventure == null) {
|
||||||
|
throw new IllegalStateException("Tried to access Adventure without PlayerStats being enabled!");
|
||||||
|
}
|
||||||
|
return adventure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull PlayerStats getPlayerStatsAPI() throws IllegalStateException {
|
||||||
|
if (playerStatsAPI == null) {
|
||||||
|
throw new IllegalStateException("PlayerStats does not seem to be loaded!");
|
||||||
|
}
|
||||||
|
return playerStatsAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull OutputManager getOutputManager() throws IllegalStateException {
|
||||||
|
if (outputManager == null) {
|
||||||
|
throw new IllegalStateException("The OutputManager is not loaded! Is PlayerStats enabled?");
|
||||||
|
}
|
||||||
|
return outputManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull ShareManager getShareManager() throws IllegalStateException {
|
||||||
|
if (shareManager == null) {
|
||||||
|
throw new IllegalStateException("The ShareManager is not loaded! Is PlayerStats enabled?");
|
||||||
|
}
|
||||||
|
return shareManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull StatManager getStatManager() throws IllegalStateException {
|
||||||
|
if (statManager == null) {
|
||||||
|
throw new IllegalStateException("The StatManager is not loaded! Is PlayerStats enabled?");
|
||||||
|
}
|
||||||
|
return statManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull ThreadManager getThreadManager() throws IllegalStateException {
|
||||||
|
if (threadManager == null) {
|
||||||
|
throw new IllegalStateException("The ThreadManager is not loaded! Is PlayerStats enabled?");
|
||||||
|
}
|
||||||
|
return threadManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMainClasses(ConfigHandler config, OfflinePlayerHandler offlinePlayerHandler) {
|
||||||
|
adventure = BukkitAudiences.create(this);
|
||||||
|
|
||||||
|
shareManager = new ShareManager(config);
|
||||||
|
outputManager = new OutputManager(getAdventure(), config, shareManager);
|
||||||
|
statManager = new StatManager(outputManager, offlinePlayerHandler, config.getTopListMaxSize());
|
||||||
|
threadManager = new ThreadManager(config, statManager, outputManager, offlinePlayerHandler);
|
||||||
|
|
||||||
|
playerStatsAPI = PlayerStatsAPI.load(statManager, outputManager);
|
||||||
|
}
|
||||||
}
|
}
|
@ -24,8 +24,6 @@ import static java.time.temporal.ChronoUnit.SECONDS;
|
|||||||
results of past stat-lookups, so the results can be retrieved and shared when a Player clicks the share-button.*/
|
results of past stat-lookups, so the results can be retrieved and shared when a Player clicks the share-button.*/
|
||||||
public final class ShareManager {
|
public final class ShareManager {
|
||||||
|
|
||||||
private static volatile ShareManager instance;
|
|
||||||
|
|
||||||
private static boolean isEnabled;
|
private static boolean isEnabled;
|
||||||
private static int waitingTime;
|
private static int waitingTime;
|
||||||
|
|
||||||
@ -34,23 +32,10 @@ public final class ShareManager {
|
|||||||
private ConcurrentHashMap<String, Instant> shareTimeStamp;
|
private ConcurrentHashMap<String, Instant> shareTimeStamp;
|
||||||
private ArrayBlockingQueue<UUID> sharedResults;
|
private ArrayBlockingQueue<UUID> sharedResults;
|
||||||
|
|
||||||
private ShareManager(ConfigHandler config) {
|
public ShareManager(ConfigHandler config) {
|
||||||
updateSettings(config);
|
updateSettings(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShareManager getInstance(ConfigHandler config) {
|
|
||||||
ShareManager shareManager = instance;
|
|
||||||
if (shareManager != null) {
|
|
||||||
return shareManager;
|
|
||||||
}
|
|
||||||
synchronized (ShareManager.class) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ShareManager(config);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isEnabled() {
|
public static boolean isEnabled() {
|
||||||
return isEnabled;
|
return isEnabled;
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ import java.util.HashMap;
|
|||||||
to ensure those will never run at the same time. */
|
to ensure those will never run at the same time. */
|
||||||
public final class ThreadManager {
|
public final class ThreadManager {
|
||||||
|
|
||||||
private static volatile ThreadManager instance;
|
|
||||||
|
|
||||||
private final static int threshold = 10;
|
private final static int threshold = 10;
|
||||||
private int statThreadID;
|
private int statThreadID;
|
||||||
private int reloadThreadID;
|
private int reloadThreadID;
|
||||||
@ -36,11 +34,11 @@ public final class ThreadManager {
|
|||||||
private final HashMap<String, Thread> statThreads;
|
private final HashMap<String, Thread> statThreads;
|
||||||
private static long lastRecordedCalcTime;
|
private static long lastRecordedCalcTime;
|
||||||
|
|
||||||
private ThreadManager(ConfigHandler c, OutputManager m, StatManager s, OfflinePlayerHandler o) {
|
public ThreadManager(ConfigHandler config, StatManager statManager, OutputManager outputManager, OfflinePlayerHandler offlinePlayerHandler) {
|
||||||
config = c;
|
ThreadManager.config = config;
|
||||||
outputManager = m;
|
ThreadManager.outputManager = outputManager;
|
||||||
statManager = s;
|
ThreadManager.statManager = statManager;
|
||||||
offlinePlayerHandler = o;
|
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||||
|
|
||||||
statThreads = new HashMap<>();
|
statThreads = new HashMap<>();
|
||||||
statThreadID = 0;
|
statThreadID = 0;
|
||||||
@ -50,19 +48,6 @@ public final class ThreadManager {
|
|||||||
startReloadThread(null);
|
startReloadThread(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ThreadManager getInstance(ConfigHandler config, OutputManager output, StatManager statManager, OfflinePlayerHandler offlinePlayerHandler) {
|
|
||||||
ThreadManager threadManager = instance;
|
|
||||||
if (threadManager != null) {
|
|
||||||
return threadManager;
|
|
||||||
}
|
|
||||||
synchronized (ThreadManager.class) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ThreadManager(config, output, statManager, offlinePlayerHandler);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getTaskThreshold() {
|
public static int getTaskThreshold() {
|
||||||
return threshold;
|
return threshold;
|
||||||
}
|
}
|
||||||
@ -108,7 +93,7 @@ public final class ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startNewStatThread(StatRequest request) {
|
private void startNewStatThread(StatRequest request) {
|
||||||
lastActiveStatThread = new StatThread(config, outputManager, statManager, offlinePlayerHandler, statThreadID, request, lastActiveReloadThread);
|
lastActiveStatThread = new StatThread(outputManager, statManager, statThreadID, request, lastActiveReloadThread);
|
||||||
statThreads.put(request.getCommandSender().getName(), lastActiveStatThread);
|
statThreads.put(request.getCommandSender().getName(), lastActiveStatThread);
|
||||||
lastActiveStatThread.start();
|
lastActiveStatThread.start();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ public interface PlayerStats {
|
|||||||
<p>- if applicable, a sub-stat-name (example: diorite)(</p>
|
<p>- if applicable, a sub-stat-name (example: diorite)(</p>
|
||||||
<p>- a target for this lookup: can be "top", "server", "player" (or "me" to indicate the current CommandSender)</p>
|
<p>- a target for this lookup: can be "top", "server", "player" (or "me" to indicate the current CommandSender)</p>
|
||||||
<p>- if "player" was chosen, include a player-name</p>
|
<p>- if "player" was chosen, include a player-name</p>
|
||||||
@param sender the CommandSender that requested this specific statistic*/
|
@param sender the CommandSender that requested this specific statistic
|
||||||
|
@throws IllegalArgumentException if the args do not result in a valid statistic look-up*/
|
||||||
TextComponent getFancyStat(CommandSender sender, String[] args) throws IllegalArgumentException;
|
TextComponent getFancyStat(CommandSender sender, String[] args) throws IllegalArgumentException;
|
||||||
|
|
||||||
/** Turns a TextComponent into its String representation. It will lose all color and style,
|
/** Turns a TextComponent into its String representation. It will lose all color and style,
|
||||||
|
@ -1,35 +1,30 @@
|
|||||||
package com.gmail.artemis.the.gr8.playerstats.api;
|
package com.gmail.artemis.the.gr8.playerstats.api;
|
||||||
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.Main;
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
|
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
|
||||||
import net.kyori.adventure.text.TextComponent;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
import static org.jetbrains.annotations.ApiStatus.Internal;
|
import static org.jetbrains.annotations.ApiStatus.Internal;
|
||||||
|
|
||||||
/** This is the implementation of the API Interface */
|
/** The implementation of the API Interface */
|
||||||
public final class PlayerStatsAPI extends JavaPlugin implements PlayerStats {
|
public final class PlayerStatsAPI implements PlayerStats {
|
||||||
|
|
||||||
private final Main plugin;
|
|
||||||
private static ThreadManager threadManager;
|
|
||||||
private static StatFormatter statFormatter;
|
private static StatFormatter statFormatter;
|
||||||
private static StatManager statManager;
|
private static StatManager statManager;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
private PlayerStatsAPI(Main plugin, ThreadManager thread, StatFormatter format, StatManager stat) {
|
private PlayerStatsAPI(StatManager stat, StatFormatter format) {
|
||||||
this.plugin = plugin;
|
|
||||||
threadManager = thread;
|
|
||||||
statFormatter = format;
|
statFormatter = format;
|
||||||
statManager = stat;
|
statManager = stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
public static PlayerStatsAPI load(Main plugin, ThreadManager threadManager, StatFormatter formatter, StatManager statManager) {
|
public static PlayerStatsAPI load(StatManager statManager, StatFormatter statFormatter) {
|
||||||
return new PlayerStatsAPI(plugin, threadManager, formatter, statManager);
|
return new PlayerStatsAPI(statManager, statFormatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -42,17 +37,17 @@ public final class PlayerStatsAPI extends JavaPlugin implements PlayerStats {
|
|||||||
return statFormatter.formatPlayerStat(request, stat);
|
return statFormatter.formatPlayerStat(request, stat);
|
||||||
}
|
}
|
||||||
case SERVER -> {
|
case SERVER -> {
|
||||||
//do something async
|
long stat = statManager.getServerStat(request);
|
||||||
|
return statFormatter.formatServerStat(request, stat);
|
||||||
}
|
}
|
||||||
case TOP -> {
|
case TOP -> {
|
||||||
//also do something async
|
LinkedHashMap<String, Integer> stats = statManager.getTopStats(request);
|
||||||
|
return statFormatter.formatTopStat(request, stats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("This is not a valid stat-request!");
|
throw new IllegalArgumentException("This is not a valid stat-request!");
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String componentToString(TextComponent component) {
|
public String componentToString(TextComponent component) {
|
||||||
return statFormatter.toString(component);
|
return statFormatter.toString(component);
|
||||||
|
@ -3,10 +3,10 @@ package com.gmail.artemis.the.gr8.playerstats.api;
|
|||||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
/** The {@link RequestHandler} will help you turn a String (such as "stat animals_bred") into a specific {@link StatRequest}
|
/** The {@link RequestGenerator} will help you turn a String (such as "stat animals_bred") into a specific {@link StatRequest}
|
||||||
with all the information {@link PlayerStatsAPI} needs to work with. You'll need this StatRequest Object to get the statistic
|
with all the information {@link PlayerStatsAPI} needs to work with. You'll need this StatRequest Object to get the statistic
|
||||||
data that you want, and to format this data into a fancy Component or String, so you can output it somewhere.*/
|
data that you want, and to format this data into a fancy Component or String, so you can output it somewhere.*/
|
||||||
public interface RequestHandler {
|
public interface RequestGenerator {
|
||||||
|
|
||||||
/** This will create a {@link StatRequest} from the provided args, with the requesting Player (or Console)
|
/** This will create a {@link StatRequest} from the provided args, with the requesting Player (or Console)
|
||||||
as CommandSender. This CommandSender will receive feedback messages if the StatRequest could not be created.
|
as CommandSender. This CommandSender will receive feedback messages if the StatRequest could not be created.
|
@ -1,6 +1,5 @@
|
|||||||
package com.gmail.artemis.the.gr8.playerstats.msg;
|
package com.gmail.artemis.the.gr8.playerstats.msg;
|
||||||
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.Main;
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.ShareManager;
|
import com.gmail.artemis.the.gr8.playerstats.ShareManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
|
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||||
@ -33,8 +32,6 @@ import static com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage.*;
|
|||||||
(mainly to deal with the lack of hover-text, and for Bukkit consoles to make up for the lack of hex-colors).*/
|
(mainly to deal with the lack of hover-text, and for Bukkit consoles to make up for the lack of hex-colors).*/
|
||||||
public final class OutputManager implements StatFormatter {
|
public final class OutputManager implements StatFormatter {
|
||||||
|
|
||||||
private static volatile OutputManager instance;
|
|
||||||
|
|
||||||
private static BukkitAudiences adventure;
|
private static BukkitAudiences adventure;
|
||||||
private static ShareManager shareManager;
|
private static ShareManager shareManager;
|
||||||
private static MessageBuilder writer;
|
private static MessageBuilder writer;
|
||||||
@ -42,27 +39,14 @@ public final class OutputManager implements StatFormatter {
|
|||||||
|
|
||||||
private static EnumMap<StandardMessage, Function<MessageBuilder, TextComponent>> standardMessages;
|
private static EnumMap<StandardMessage, Function<MessageBuilder, TextComponent>> standardMessages;
|
||||||
|
|
||||||
private OutputManager(ConfigHandler config) {
|
public OutputManager(BukkitAudiences adventure, ConfigHandler config, ShareManager shareManager) {
|
||||||
adventure = Main.adventure();
|
OutputManager.adventure = adventure;
|
||||||
shareManager = ShareManager.getInstance(config);
|
OutputManager.shareManager = shareManager;
|
||||||
|
|
||||||
getMessageWriters(config);
|
getMessageWriters(config);
|
||||||
prepareFunctions();
|
prepareFunctions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OutputManager getInstance(ConfigHandler config) {
|
|
||||||
OutputManager outputManager = instance;
|
|
||||||
if (outputManager != null) {
|
|
||||||
return outputManager;
|
|
||||||
}
|
|
||||||
synchronized (OutputManager.class) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new OutputManager(config);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateMessageWriters(ConfigHandler config) {
|
public void updateMessageWriters(ConfigHandler config) {
|
||||||
getMessageWriters(config);
|
getMessageWriters(config);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.gmail.artemis.the.gr8.playerstats.reload;
|
package com.gmail.artemis.the.gr8.playerstats.reload;
|
||||||
|
|
||||||
|
import com.gmail.artemis.the.gr8.playerstats.Main;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.ShareManager;
|
import com.gmail.artemis.the.gr8.playerstats.ShareManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||||
@ -7,6 +8,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel;
|
|||||||
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
|
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
|
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
|
import com.gmail.artemis.the.gr8.playerstats.statistic.StatThread;
|
||||||
|
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
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.utils.OfflinePlayerHandler;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -25,10 +27,10 @@ public class ReloadThread extends Thread {
|
|||||||
|
|
||||||
private static ConfigHandler config;
|
private static ConfigHandler config;
|
||||||
private static OutputManager outputManager;
|
private static OutputManager outputManager;
|
||||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
|
||||||
|
|
||||||
private static ShareManager shareManager;
|
private static ShareManager shareManager;
|
||||||
|
|
||||||
|
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||||
|
|
||||||
private final int reloadThreadID;
|
private final int reloadThreadID;
|
||||||
private final StatThread statThread;
|
private final StatThread statThread;
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ public class ReloadThread extends Thread {
|
|||||||
outputManager = m;
|
outputManager = m;
|
||||||
offlinePlayerHandler = o;
|
offlinePlayerHandler = o;
|
||||||
|
|
||||||
shareManager = ShareManager.getInstance(c);
|
shareManager = Main.getShareManager();
|
||||||
|
|
||||||
reloadThreadID = ID;
|
reloadThreadID = ID;
|
||||||
statThread = s;
|
statThread = s;
|
||||||
@ -52,7 +54,8 @@ public class ReloadThread extends Thread {
|
|||||||
/** This method will perform a series of tasks. If a {@link StatThread} is still running,
|
/** 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,
|
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 the offlinePlayerList in the {@link OfflinePlayerHandler}, update the {@link DebugLevel},
|
||||||
update the share-settings in {@link ShareManager} and update the MessageBuilders in the {@link OutputManager}.*/
|
update the share-settings in {@link ShareManager} and topListSize-settings in {@link StatManager},
|
||||||
|
and update the MessageBuilders in the {@link OutputManager}.*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
@ -88,6 +91,7 @@ public class ReloadThread extends Thread {
|
|||||||
outputManager.updateMessageWriters(config);
|
outputManager.updateMessageWriters(config);
|
||||||
offlinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
|
offlinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
|
||||||
shareManager.updateSettings(config);
|
shareManager.updateSettings(config);
|
||||||
|
StatManager.updateSettings(config.getTopListMaxSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConcurrentHashMap<String, UUID> loadOfflinePlayers() {
|
private ConcurrentHashMap<String, UUID> loadOfflinePlayers() {
|
||||||
|
@ -9,17 +9,17 @@ import org.bukkit.OfflinePlayer;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.RecursiveAction;
|
import java.util.concurrent.RecursiveTask;
|
||||||
|
|
||||||
/** The action that is executed when a stat-command is triggered. */
|
/** The action that is executed when a stat-command is triggered. */
|
||||||
public final class StatAction extends RecursiveAction {
|
public final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>> {
|
||||||
|
|
||||||
private static int threshold;
|
private static int threshold;
|
||||||
|
|
||||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||||
private final ImmutableList<String> playerNames;
|
private final ImmutableList<String> playerNames;
|
||||||
private final StatRequest request;
|
private final StatRequest request;
|
||||||
private final ConcurrentHashMap<String, Integer> playerStats;
|
private final ConcurrentHashMap<String, Integer> allStats;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the statistic numbers for all players whose name is on the list, puts them in a ConcurrentHashMap
|
* Gets the statistic numbers for all players whose name is on the list, puts them in a ConcurrentHashMap
|
||||||
@ -27,34 +27,36 @@ public final class StatAction extends RecursiveAction {
|
|||||||
* @param offlinePlayerHandler the OfflinePlayerHandler to convert playerNames into Players
|
* @param offlinePlayerHandler the OfflinePlayerHandler to convert playerNames into Players
|
||||||
* @param playerNames ImmutableList of playerNames for players that should be included in stat calculations
|
* @param playerNames ImmutableList of playerNames for players that should be included in stat calculations
|
||||||
* @param statRequest a validated statRequest
|
* @param statRequest a validated statRequest
|
||||||
* @param playerStats the ConcurrentHashMap to put the results on
|
* @param allStats the ConcurrentHashMap to put the results on
|
||||||
*/
|
*/
|
||||||
public StatAction(OfflinePlayerHandler offlinePlayerHandler, ImmutableList<String> playerNames, StatRequest statRequest, ConcurrentHashMap<String, Integer> playerStats) {
|
public StatAction(OfflinePlayerHandler offlinePlayerHandler, ImmutableList<String> playerNames, StatRequest statRequest, ConcurrentHashMap<String, Integer> allStats) {
|
||||||
threshold = ThreadManager.getTaskThreshold();
|
threshold = ThreadManager.getTaskThreshold();
|
||||||
|
|
||||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||||
this.playerNames = playerNames;
|
this.playerNames = playerNames;
|
||||||
this.request = statRequest;
|
this.request = statRequest;
|
||||||
this.playerStats = playerStats;
|
this.allStats = allStats;
|
||||||
|
|
||||||
MyLogger.subActionCreated(Thread.currentThread().getName());
|
MyLogger.subActionCreated(Thread.currentThread().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void compute() {
|
protected ConcurrentHashMap<String, Integer> compute() {
|
||||||
if (playerNames.size() < threshold) {
|
if (playerNames.size() < threshold) {
|
||||||
getStatsDirectly();
|
return getStatsDirectly();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final StatAction subTask1 = new StatAction(offlinePlayerHandler, playerNames.subList(0, playerNames.size()/2), request, playerStats);
|
final StatAction subTask1 = new StatAction(offlinePlayerHandler, playerNames.subList(0, playerNames.size()/2), request, allStats);
|
||||||
final StatAction subTask2 = new StatAction(offlinePlayerHandler, playerNames.subList(playerNames.size()/2, playerNames.size()), request, playerStats);
|
final StatAction subTask2 = new StatAction(offlinePlayerHandler, playerNames.subList(playerNames.size()/2, playerNames.size()), request, allStats);
|
||||||
|
|
||||||
//queue and compute all subtasks in the right order
|
//queue and compute all subtasks in the right order
|
||||||
invokeAll(subTask1, subTask2);
|
subTask1.fork();
|
||||||
|
subTask2.compute();
|
||||||
|
return subTask1.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getStatsDirectly() {
|
private ConcurrentHashMap<String, Integer> getStatsDirectly() {
|
||||||
Iterator<String> iterator = playerNames.iterator();
|
Iterator<String> iterator = playerNames.iterator();
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
do {
|
do {
|
||||||
@ -70,10 +72,11 @@ public final class StatAction extends RecursiveAction {
|
|||||||
case ITEM -> statistic = player.getStatistic(request.getStatistic(), request.getItem());
|
case ITEM -> statistic = player.getStatistic(request.getStatistic(), request.getItem());
|
||||||
}
|
}
|
||||||
if (statistic > 0) {
|
if (statistic > 0) {
|
||||||
playerStats.put(playerName, statistic);
|
allStats.put(playerName, statistic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (iterator.hasNext());
|
} while (iterator.hasNext());
|
||||||
}
|
}
|
||||||
|
return allStats;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +1,16 @@
|
|||||||
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
package com.gmail.artemis.the.gr8.playerstats.statistic;
|
||||||
|
|
||||||
import com.gmail.artemis.the.gr8.playerstats.api.RequestHandler;
|
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
||||||
|
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
|
||||||
|
import com.gmail.artemis.the.gr8.playerstats.api.StatGetter;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
|
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
|
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
|
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
|
||||||
|
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.Statistic;
|
import org.bukkit.Statistic;
|
||||||
@ -14,30 +18,27 @@ import org.bukkit.command.CommandSender;
|
|||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public final class StatManager implements RequestHandler {
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
private static volatile StatManager instance;
|
public final class StatManager implements RequestGenerator, StatGetter {
|
||||||
|
|
||||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||||
private static OutputManager outputManager;
|
private static OutputManager outputManager;
|
||||||
|
private static int topListMaxSize;
|
||||||
|
|
||||||
private StatManager(OutputManager output, OfflinePlayerHandler offlinePlayerHandler) {
|
public StatManager(OutputManager outputManager, OfflinePlayerHandler offlinePlayerHandler, int topListMaxSize) {
|
||||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||||
outputManager = output;
|
StatManager.outputManager = outputManager;
|
||||||
|
StatManager.topListMaxSize = topListMaxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StatManager getInstance(OutputManager outputManager, OfflinePlayerHandler offlinePlayerHandler) {
|
public static void updateSettings(int topListMaxSize) {
|
||||||
StatManager statManager = instance;
|
StatManager.topListMaxSize = topListMaxSize;
|
||||||
if (statManager != null) {
|
|
||||||
return statManager;
|
|
||||||
}
|
|
||||||
synchronized (StatManager.class) {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new StatManager(outputManager, offlinePlayerHandler);
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatRequest generateRequest(CommandSender sender, String[] args) {
|
public StatRequest generateRequest(CommandSender sender, String[] args) {
|
||||||
@ -174,4 +175,54 @@ public final class StatManager implements RequestHandler {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LinkedHashMap<String, Integer> getTopStats(StatRequest request) {
|
||||||
|
return getAllStatsAsync(request).entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
||||||
|
.limit(topListMaxSize)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getServerStat(StatRequest request) {
|
||||||
|
List<Integer> numbers = getAllStatsAsync(request)
|
||||||
|
.values()
|
||||||
|
.parallelStream()
|
||||||
|
.toList();
|
||||||
|
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invokes a bunch of worker pool threads to divide and conquer (get the statistics for all players
|
||||||
|
that are stored in the {@link OfflinePlayerHandler}) */
|
||||||
|
public @NotNull ConcurrentHashMap<String, Integer> getAllStatsAsync(StatRequest request) {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
|
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
||||||
|
ConcurrentHashMap<String, Integer> allStats;
|
||||||
|
|
||||||
|
try {
|
||||||
|
allStats = commonPool.invoke(getStatTask(request));
|
||||||
|
} catch (ConcurrentModificationException e) {
|
||||||
|
MyLogger.logMsg("The request 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!", true);
|
||||||
|
throw new ConcurrentModificationException(e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
MyLogger.actionFinished(2);
|
||||||
|
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
||||||
|
MyLogger.logTimeTaken("StatThread", "calculated all stats", time);
|
||||||
|
|
||||||
|
return allStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatAction getStatTask(StatRequest request) {
|
||||||
|
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, request, allStats);
|
||||||
|
MyLogger.actionCreated(playerNames.size());
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,33 +9,23 @@ import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
|
|||||||
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
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.utils.OfflinePlayerHandler;
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import net.kyori.adventure.text.TextComponent;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/** The Thread that is in charge of getting and calculating statistics.*/
|
/** The Thread that is in charge of getting and calculating statistics.*/
|
||||||
public class StatThread extends Thread {
|
public class StatThread extends Thread {
|
||||||
|
|
||||||
private static ConfigHandler config;
|
|
||||||
private static OutputManager outputManager;
|
private static OutputManager outputManager;
|
||||||
private static StatManager statManager;
|
private static StatManager statManager;
|
||||||
|
|
||||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
|
||||||
|
|
||||||
private final ReloadThread reloadThread;
|
private final ReloadThread reloadThread;
|
||||||
private final StatRequest request;
|
private final StatRequest request;
|
||||||
|
|
||||||
public StatThread(ConfigHandler c, OutputManager m, StatManager t, OfflinePlayerHandler o, int ID, StatRequest s, @Nullable ReloadThread r) {
|
public StatThread(OutputManager m, StatManager t, int ID, StatRequest s, @Nullable ReloadThread r) {
|
||||||
config = c;
|
|
||||||
outputManager = m;
|
outputManager = m;
|
||||||
statManager = t;
|
statManager = t;
|
||||||
offlinePlayerHandler = o;
|
|
||||||
|
|
||||||
reloadThread = r;
|
reloadThread = r;
|
||||||
request = s;
|
request = s;
|
||||||
@ -72,8 +62,8 @@ public class StatThread extends Thread {
|
|||||||
try {
|
try {
|
||||||
TextComponent statResult = switch (selection) {
|
TextComponent statResult = switch (selection) {
|
||||||
case PLAYER -> outputManager.formatPlayerStat(request, statManager.getPlayerStat(request));
|
case PLAYER -> outputManager.formatPlayerStat(request, statManager.getPlayerStat(request));
|
||||||
case TOP -> outputManager.formatTopStat(request, getTopStats());
|
case TOP -> outputManager.formatTopStat(request, statManager.getTopStats(request));
|
||||||
case SERVER -> outputManager.formatServerStat(request, getServerStat());
|
case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request));
|
||||||
};
|
};
|
||||||
outputManager.sendToCommandSender(request.getCommandSender(), statResult);
|
outputManager.sendToCommandSender(request.getCommandSender(), statResult);
|
||||||
}
|
}
|
||||||
@ -83,43 +73,4 @@ public class StatThread extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedHashMap<String, Integer> getTopStats() throws ConcurrentModificationException {
|
|
||||||
return getAllStats().entrySet().stream()
|
|
||||||
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
|
|
||||||
.limit(config.getTopListMaxSize()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getServerStat() {
|
|
||||||
List<Integer> numbers = getAllStats().values().parallelStream().toList();
|
|
||||||
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
//invokes a bunch of worker pool threads to divide and conquer (get the statistics for all players in the list)
|
|
||||||
private @NotNull ConcurrentHashMap<String, Integer> getAllStats() throws ConcurrentModificationException {
|
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
|
|
||||||
int size = offlinePlayerHandler.getOfflinePlayerCount() != 0 ? offlinePlayerHandler.getOfflinePlayerCount() : 16;
|
|
||||||
ConcurrentHashMap<String, Integer> playerStats = new ConcurrentHashMap<>(size);
|
|
||||||
ImmutableList<String> playerNames = ImmutableList.copyOf(offlinePlayerHandler.getOfflinePlayerNames());
|
|
||||||
|
|
||||||
StatAction task = new StatAction(offlinePlayerHandler, playerNames, request, playerStats);
|
|
||||||
MyLogger.actionCreated(playerNames.size());
|
|
||||||
ForkJoinPool commonPool = ForkJoinPool.commonPool();
|
|
||||||
|
|
||||||
try {
|
|
||||||
commonPool.invoke(task);
|
|
||||||
} catch (ConcurrentModificationException e) {
|
|
||||||
MyLogger.logMsg("The request 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!", true);
|
|
||||||
throw new ConcurrentModificationException(e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
MyLogger.actionFinished(2);
|
|
||||||
ThreadManager.recordCalcTime(System.currentTimeMillis() - time);
|
|
||||||
MyLogger.logTimeTaken("StatThread", "calculated all stats", time);
|
|
||||||
|
|
||||||
return playerStats;
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user