Experimented with Interfaces to create an API

This commit is contained in:
Artemis-the-gr8 2022-07-22 19:28:40 +02:00
parent ca1a080e6b
commit a775def8f8
19 changed files with 257 additions and 89 deletions

View File

@ -26,6 +26,11 @@
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="placeholderapi" />
<option name="name" value="placeholderapi" />
<option name="url" value="https://repo.extendedclip.com/content/repositories/placeholderapi/" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />

View File

@ -85,6 +85,10 @@
<id>maven-central</id>
<url>https://oss.sonatype.org/content/groups/public</url>
</repository>
<repository>
<id>placeholderapi</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
<dependency>
@ -93,6 +97,12 @@
<version>1.19-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>

12
pom.xml
View File

@ -30,6 +30,11 @@
<id>maven-central</id> <!-- Config-Updater -->
<url>https://oss.sonatype.org/content/groups/public</url>
</repository>
<repository>
<id>placeholderapi</id> <!-- Placeholder API -->
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
@ -58,6 +63,13 @@
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tchristofferson</groupId>
<artifactId>ConfigUpdater</artifactId>

View File

@ -51,7 +51,7 @@ public class Main extends JavaPlugin {
//register the listener
Bukkit.getPluginManager().registerEvents(new JoinListener(threadManager), this);
//finish up
this.getLogger().info("Enabled PlayerStats!");
}

View File

@ -49,6 +49,10 @@ public final class ShareManager {
}
}
public static boolean isEnabled() {
return isEnabled;
}
public synchronized void updateSettings(ConfigHandler config) {
isEnabled = config.allowStatSharing() && config.useHoverText();
waitingTime = config.getStatShareWaitingTime();
@ -74,10 +78,6 @@ public final class ShareManager {
}
}
public boolean isEnabled() {
return isEnabled;
}
public boolean senderHasPermission(CommandSender sender) {
return !(sender instanceof ConsoleCommandSender) && sender.hasPermission("playerstats.share");
}

View File

@ -21,7 +21,7 @@ public final class ThreadManager {
private int reloadThreadID;
private static ConfigHandler config;
private static OutputManager messageSender;
private static OutputManager outputManager;
private final OfflinePlayerHandler offlinePlayerHandler;
private ReloadThread lastActiveReloadThread;
@ -31,7 +31,7 @@ public final class ThreadManager {
private ThreadManager(ConfigHandler c, OutputManager m, OfflinePlayerHandler o) {
config = c;
messageSender = m;
outputManager = m;
offlinePlayerHandler = o;
statThreads = new HashMap<>();
@ -63,7 +63,7 @@ public final class ThreadManager {
if (lastActiveReloadThread == null || !lastActiveReloadThread.isAlive()) {
reloadThreadID += 1;
lastActiveReloadThread = new ReloadThread(config, messageSender, offlinePlayerHandler, reloadThreadID, lastActiveStatThread, sender);
lastActiveReloadThread = new ReloadThread(config, outputManager, offlinePlayerHandler, reloadThreadID, lastActiveStatThread, sender);
lastActiveReloadThread.start();
}
else {
@ -78,7 +78,7 @@ public final class ThreadManager {
if (config.limitStatRequests() && statThreads.containsKey(cmdSender)) {
Thread runningThread = statThreads.get(cmdSender);
if (runningThread.isAlive()) {
messageSender.sendFeedbackMsg(request.getCommandSender(), StandardMessage.REQUEST_ALREADY_RUNNING);
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.REQUEST_ALREADY_RUNNING);
} else {
startNewStatThread(request);
}
@ -100,7 +100,7 @@ public final class ThreadManager {
}
private void startNewStatThread(StatRequest request) {
lastActiveStatThread = new StatThread(config, messageSender, offlinePlayerHandler, statThreadID, request, lastActiveReloadThread);
lastActiveStatThread = new StatThread(config, outputManager, offlinePlayerHandler, statThreadID, request, lastActiveReloadThread);
statThreads.put(request.getCommandSender().getName(), lastActiveStatThread);
lastActiveStatThread.start();
}

View File

@ -0,0 +1,13 @@
package com.gmail.artemis.the.gr8.playerstats.api;
public interface PlayerStats {
/** The RequestManager will help you turn a String (such as "stat animals_bred") into a specific StatRequest
with all the information PlayerStats needs to work with. You'll need this StatRequest Object to get the Statistic
data that you want, and to format it into a fancy Component or String, so you can output it somewhere.*/
RequestManager getRequestGenerator();
StatGetter getStatGetter();
StatFormatter getStatFormatter();
}

View File

@ -0,0 +1,15 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import org.bukkit.command.CommandSender;
public interface RequestManager {
/** This will create a 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.
@param args an Array of args corresponding to a Statistic, a potential Sub-Statistic, and a Target
(exactly as one would type them in Minecraft chat when using PlayerStats' /stat command)*/
StatRequest generateRequest(CommandSender sender, String[] args);
boolean requestIsValid(StatRequest request);
}

View File

@ -0,0 +1,25 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import net.kyori.adventure.text.TextComponent;
import java.util.LinkedHashMap;
/** Interface that defines the output functionality PlayerStats should have.
This is meant for an outgoing API - for internal use, more output functionality may exist. */
public interface StatFormatter {
/** Returns the setting for whether TextComponents should be saved internally for later stat-sharing by players.
Make this method return "false" if you only want to get a fancy stat-result, and don't want to send it
to players in chat with a clickable "share"-button. */
boolean saveOutputForSharing();
String toString(TextComponent component);
TextComponent formatPlayerStat(StatRequest request, int playerStat);
TextComponent formatServerStat(StatRequest request, long serverStat);
TextComponent formatTopStat(StatRequest request, LinkedHashMap<String, Integer> topStats);
}

View File

@ -0,0 +1,16 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import java.util.LinkedHashMap;
public interface StatGetter extends RequestManager {
//use ThreadManager.startStatThread
LinkedHashMap<String, Integer> getTopStats(StatRequest request);
long getServerStat(StatRequest request);
int getPlayerStat(StatRequest request);
}

View File

@ -24,7 +24,7 @@ public class ShareCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
if (args.length == 1 && shareManager.isEnabled()) {
if (args.length == 1 && ShareManager.isEnabled()) {
UUID shareCode;
try {
shareCode = UUID.fromString(args[0]);
@ -43,7 +43,7 @@ public class ShareCommand implements CommandExecutor {
if (result == null) { //at this point the only possible cause of statResult being null is the request being older than 25 player-requests ago
outputManager.sendFeedbackMsg(sender, StandardMessage.STAT_RESULTS_TOO_OLD);
} else {
outputManager.shareStatResults(result.statResult());
outputManager.sendToAllPlayers(result.statResult());
}
}
}

View File

@ -1,6 +1,7 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.api.RequestManager;
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.msg.OutputManager;
@ -18,7 +19,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class StatCommand implements CommandExecutor {
public class StatCommand implements CommandExecutor, RequestManager {
private static ThreadManager threadManager;
private static OutputManager outputManager;
@ -51,7 +52,8 @@ public class StatCommand implements CommandExecutor {
}
/** Create a StatRequest Object with all the relevant information from the args[]. */
private StatRequest generateRequest(CommandSender sender, String[] args) {
@Override
public StatRequest generateRequest(CommandSender sender, String[] args) {
StatRequest request = new StatRequest(sender);
for (String arg : args) {
//check for statName
@ -134,8 +136,9 @@ public class StatCommand implements CommandExecutor {
<p>1. Is a Statistic set?</p>
<p>2. Is a subStat needed, and is a subStat Enum Constant present? (block/entity/item)</p>
<p>3. If the target is PLAYER, is a valid PlayerName provided? </p>
@return true if the Request is valid, and false + an explanation message otherwise. */
private boolean requestIsValid(StatRequest request) {
@return true if the RequestManager is valid, and false + an explanation message otherwise. */
@Override
public boolean requestIsValid(StatRequest request) {
if (request.getStatistic() == null) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.MISSING_STAT_NAME);
return false;

View File

@ -105,4 +105,24 @@ public final class StatRequest {
public Material getItem() {
return item;
}
/** Returns true if this StatRequest has all the information needed for a Statistic lookup to succeed.*/
public boolean isValid() {
if (statistic == null) return false;
switch (statistic.getType()) {
case BLOCK -> {
if (block == null) return false;
}
case ENTITY -> {
if (entity == null) return false;
}
case ITEM -> {
if (item == null) return false;
}
case UNTYPED -> {
if (subStatEntry != null) return false;
}
} //if target = PLAYER and playerName = null, return false, otherwise return true
return selection != Target.PLAYER || playerName != null;
}
}

View File

@ -29,7 +29,7 @@ import static net.kyori.adventure.text.Component.*;
The component parts (with appropriate formatting) are supplied by a ComponentFactory.
By default, this class works with the default ComponentFactory, but you can
give it a different ComponentFactory upon creation.*/
public class MessageWriter {
public class MessageBuilder {
private static ConfigHandler config;
@ -37,25 +37,25 @@ public class MessageWriter {
private final LanguageKeyHandler languageKeyHandler;
private final NumberFormatter formatter;
private MessageWriter(ConfigHandler config) {
private MessageBuilder(ConfigHandler config) {
this (config, new ComponentFactory(config));
}
private MessageWriter(ConfigHandler configHandler, ComponentFactory factory) {
private MessageBuilder(ConfigHandler configHandler, ComponentFactory factory) {
config = configHandler;
componentFactory = factory;
formatter = new NumberFormatter();
languageKeyHandler = new LanguageKeyHandler();
MyLogger.logMsg("MessageWriter created with factory: " + componentFactory.getClass().getSimpleName(), DebugLevel.MEDIUM);
MyLogger.logMsg("MessageBuilder created with factory: " + componentFactory.getClass().getSimpleName(), DebugLevel.MEDIUM);
}
public static MessageWriter defaultWriter(ConfigHandler config) {
return new MessageWriter(config);
public static MessageBuilder defaultBuilder(ConfigHandler config) {
return new MessageBuilder(config);
}
public static MessageWriter fromComponentFactory(ConfigHandler config, ComponentFactory factory) {
return new MessageWriter(config, factory);
public static MessageBuilder fromComponentFactory(ConfigHandler config, ComponentFactory factory) {
return new MessageBuilder(config, factory);
}
public TextComponent reloadedConfig() {

View File

@ -2,6 +2,7 @@ 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.api.StatFormatter;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
@ -14,6 +15,7 @@ import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.LocalDate;
import java.time.Month;
@ -25,16 +27,16 @@ import java.util.function.Function;
import static com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage.*;
public final class OutputManager {
public final class OutputManager implements StatFormatter {
private static volatile OutputManager instance;
private static BukkitAudiences adventure;
private static ShareManager shareManager;
private static MessageWriter writer;
private static MessageWriter consoleWriter;
private static MessageBuilder writer;
private static MessageBuilder consoleWriter;
private static EnumMap<StandardMessage, Function<MessageWriter, TextComponent>> standardMessages;
private static EnumMap<StandardMessage, Function<MessageBuilder, TextComponent>> standardMessages;
private OutputManager(ConfigHandler config) {
adventure = Main.adventure();
@ -61,6 +63,43 @@ public final class OutputManager {
getMessageWriters(config);
}
@Override
public boolean saveOutputForSharing() {
return true;
}
@Override
public String toString(@NotNull TextComponent component) {
return component.content();
}
@Override
public TextComponent formatPlayerStat(@NotNull StatRequest request, int playerStat) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> playerStatFunction =
getWriter(sender).formattedPlayerStatFunction(playerStat, request);
return processBuildFunction(sender, playerStatFunction);
}
@Override
public TextComponent formatServerStat(@NotNull StatRequest request, long serverStat) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> serverStatFunction =
getWriter(sender).formattedServerStatFunction(serverStat, request);
return processBuildFunction(sender, serverStatFunction);
}
@Override
public TextComponent formatTopStat(@NotNull StatRequest request, LinkedHashMap<String, Integer> topStats) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> topStatFunction =
getWriter(sender).formattedTopStatFunction(topStats, request);
return processBuildFunction(sender, topStatFunction);
}
public void sendFeedbackMsg(CommandSender sender, StandardMessage message) {
if (message != null) {
adventure.sender(sender).sendMessage(standardMessages.get(message)
@ -97,48 +136,31 @@ public final class OutputManager {
.helpMsg(sender instanceof ConsoleCommandSender));
}
public void shareStatResults(@NotNull TextComponent statResult) {
adventure.players().sendMessage(statResult);
public void sendToAllPlayers(@NotNull TextComponent component) {
adventure.players().sendMessage(component);
}
public void sendPlayerStat(@NotNull StatRequest request, int playerStat) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> buildFunction =
getWriter(sender).formattedPlayerStatFunction(playerStat, request);
processAndSend(sender, buildFunction);
public void sendToCommandSender(CommandSender sender, TextComponent component) {
adventure.sender(sender).sendMessage(component);
}
public void sendServerStat(@NotNull StatRequest request, long serverStat) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> buildFunction =
getWriter(sender).formattedServerStatFunction(serverStat, request);
private TextComponent processBuildFunction(@Nullable CommandSender sender, BiFunction<UUID, CommandSender, TextComponent> buildFunction) {
boolean saveOutput = saveOutputForSharing() &&
sender != null &&
ShareManager.isEnabled() &&
shareManager.senderHasPermission(sender);
processAndSend(sender, buildFunction);
}
public void sendTopStat(@NotNull StatRequest request, LinkedHashMap<String, Integer> topStats) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> buildFunction =
getWriter(sender).formattedTopStatFunction(topStats, request);
processAndSend(sender, buildFunction);
}
private void processAndSend(CommandSender sender, BiFunction<UUID, CommandSender, TextComponent> buildFunction) {
if (shareManager.isEnabled() && shareManager.senderHasPermission(sender)) {
UUID shareCode = shareManager.saveStatResult(sender.getName(), buildFunction.apply(null, sender));
adventure.sender(sender).sendMessage(
buildFunction.apply(shareCode, null));
if (saveOutput) {
UUID shareCode =
shareManager.saveStatResult(sender.getName(), buildFunction.apply(null, sender));
return buildFunction.apply(shareCode, null);
}
else {
adventure.sender(sender).sendMessage(
buildFunction.apply(null, null));
return buildFunction.apply(null, null);
}
}
private MessageWriter getWriter(CommandSender sender) {
private MessageBuilder getWriter(CommandSender sender) {
return sender instanceof ConsoleCommandSender ? consoleWriter : writer;
}
@ -146,30 +168,30 @@ public final class OutputManager {
boolean isBukkit = Bukkit.getName().equalsIgnoreCase("CraftBukkit");
if (config.useRainbowMode() ||
(config.useFestiveFormatting() && LocalDate.now().getMonth().equals(Month.JUNE))) {
writer = MessageWriter.fromComponentFactory(config, new PrideComponentFactory(config));
writer = MessageBuilder.fromComponentFactory(config, new PrideComponentFactory(config));
}
else {
writer = MessageWriter.defaultWriter(config);
writer = MessageBuilder.defaultBuilder(config);
}
if (!isBukkit) {
consoleWriter = writer;
} else {
consoleWriter = MessageWriter.fromComponentFactory(config, new BukkitConsoleComponentFactory(config));
consoleWriter = MessageBuilder.fromComponentFactory(config, new BukkitConsoleComponentFactory(config));
}
}
private void prepareFunctions() {
standardMessages = new EnumMap<>(StandardMessage.class);
standardMessages.put(RELOADED_CONFIG, (MessageWriter::reloadedConfig));
standardMessages.put(STILL_RELOADING, (MessageWriter::stillReloading));
standardMessages.put(MISSING_STAT_NAME, (MessageWriter::missingStatName));
standardMessages.put(MISSING_PLAYER_NAME, (MessageWriter::missingPlayerName));
standardMessages.put(REQUEST_ALREADY_RUNNING, (MessageWriter::requestAlreadyRunning));
standardMessages.put(STILL_ON_SHARE_COOLDOWN, (MessageWriter::stillOnShareCoolDown));
standardMessages.put(RESULTS_ALREADY_SHARED, (MessageWriter::resultsAlreadyShared));
standardMessages.put(STAT_RESULTS_TOO_OLD, (MessageWriter::statResultsTooOld));
standardMessages.put(UNKNOWN_ERROR, (MessageWriter::unknownError));
standardMessages.put(RELOADED_CONFIG, (MessageBuilder::reloadedConfig));
standardMessages.put(STILL_RELOADING, (MessageBuilder::stillReloading));
standardMessages.put(MISSING_STAT_NAME, (MessageBuilder::missingStatName));
standardMessages.put(MISSING_PLAYER_NAME, (MessageBuilder::missingPlayerName));
standardMessages.put(REQUEST_ALREADY_RUNNING, (MessageBuilder::requestAlreadyRunning));
standardMessages.put(STILL_ON_SHARE_COOLDOWN, (MessageBuilder::stillOnShareCoolDown));
standardMessages.put(RESULTS_ALREADY_SHARED, (MessageBuilder::resultsAlreadyShared));
standardMessages.put(STAT_RESULTS_TOO_OLD, (MessageBuilder::statResultsTooOld));
standardMessages.put(UNKNOWN_ERROR, (MessageBuilder::unknownError));
}
}

View File

@ -1,8 +1,14 @@
package com.gmail.artemis.the.gr8.playerstats.msg.msgutils;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
@ -45,7 +51,7 @@ public final class EasterEggProvider {
}
case "46dd0c5a-2b51-4ee6-80e8-29deca6dedc1" -> {
if (sillyNumberIsBetween(sillyNumber, 0, 20)) {
playerName = "<gradient:#f74040:#FF6600:#f74040>fire demon</gradient>";
playerName = "<papi:luckperms_prefix><gradient:#f74040:#FF6600:#f74040>fire demon</gradient>";
}
else if (sillyNumberIsBetween(sillyNumber, 69, 69)) {
playerName = "<gradient:blue:#b01bd1:blue>best admin</gradient>";
@ -85,7 +91,7 @@ public final class EasterEggProvider {
if (playerName == null) {
return null;
} else {
return MiniMessage.miniMessage().deserialize(playerName);
return MiniMessage.miniMessage().deserialize(playerName, papiTag(player));
}
}
@ -96,4 +102,16 @@ public final class EasterEggProvider {
private static boolean sillyNumberIsBetween(int sillyNumber, int lowerBound, int upperBound) {
return sillyNumber >= lowerBound && sillyNumber <= upperBound;
}
private static TagResolver papiTag(final @NotNull Player player) {
return TagResolver.resolver("papi", (argumentQueue, context) -> {
final String papiPlaceholder = argumentQueue.popOr("papi tag requires an argument").value();
final String parsedPlaceholder = PlaceholderAPI.setPlaceholders(player, '%' + papiPlaceholder + '%');
TextComponent componentPlaceholder = LegacyComponentSerializer.legacyAmpersand().deserialize(parsedPlaceholder);
if (!componentPlaceholder.content().isEmpty()) {
componentPlaceholder = componentPlaceholder.toBuilder().append(Component.space()).build();
}
return Tag.selfClosingInserting(componentPlaceholder);
});
}
}

View File

@ -10,6 +10,7 @@ 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.google.common.collect.ImmutableList;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -66,12 +67,14 @@ public class StatThread extends Thread {
Target selection = request.getSelection();
try {
switch (selection) {
case PLAYER -> outputManager.sendPlayerStat(request, getIndividualStat());
case TOP -> outputManager.sendTopStat(request, getTopStats());
case SERVER -> outputManager.sendServerStat(request, getServerTotal());
}
} catch (ConcurrentModificationException e) {
TextComponent statResult = switch (selection) {
case PLAYER -> outputManager.formatPlayerStat(request, getIndividualStat());
case TOP -> outputManager.formatTopStat(request, getTopStats());
case SERVER -> outputManager.formatServerStat(request, getServerStat());
};
outputManager.sendToCommandSender(request.getCommandSender(), statResult);
}
catch (ConcurrentModificationException e) {
if (!request.isConsoleSender()) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.UNKNOWN_ERROR);
}
@ -84,7 +87,7 @@ public class StatThread extends Thread {
.limit(config.getTopListMaxSize()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
private long getServerTotal() {
private long getServerStat() {
List<Integer> numbers = getAllStats().values().parallelStream().toList();
return numbers.parallelStream().mapToLong(Integer::longValue).sum();
}

View File

@ -80,6 +80,10 @@ public final class MyLogger {
}
}
public static void logException(@NotNull Exception exception, String caughtBy) {
logException(exception, caughtBy, null);
}
/** Log the encountered exception as a warning to console,
with some information about which class/method caught it
and with a printStackTrace if DebugLevel is HIGH.
@ -96,33 +100,33 @@ public final class MyLogger {
}
}
/** If DebugLevel is MEDIUM or HIGH, logs when the while loop in MessageWriter, getLanguageKey is being run. */
/** If DebugLevel is MEDIUM or HIGH, logs when the while loop in MessageBuilder, getLanguageKey is being run. */
public static void replacingUnderscores() {
if (debugLevel != DebugLevel.LOW) {
logger.info("Replacing underscores and capitalizing names...");
}
}
/** Output to console that the given thread has been created (but not started yet).*/
/** StatFormatter 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. */
/** StatFormatter 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. */
/** StatFormatter 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. */
/** StatFormatter 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...");
}
@ -171,7 +175,7 @@ public final class MyLogger {
}
}
/** Output to console that an action has finished.
/** StatFormatter 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 */
@ -190,7 +194,7 @@ public final class MyLogger {
}
}
/** Output to console how long a certain task has taken (regardless of DebugLevel).
/** StatFormatter 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 */
@ -198,7 +202,7 @@ public final class MyLogger {
logTimeTaken(className, methodName, startTime, DebugLevel.LOW);
}
/** Output to console how long a certain task has taken if DebugLevel is equal to or higher than the specified threshold.
/** StatFormatter to console how long a certain task has taken if DebugLevel is equal to or higher than the specified threshold.
@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

View File

@ -4,6 +4,8 @@ version: 1.6
api-version: 1.13
description: adds commands to view player statistics in chat
author: Artemis_the_gr8
softdepend:
- PlaceholderAPI
commands:
statistic:
aliases: