Added a lot more documentation, and made topListSize a parameter for API requests

This commit is contained in:
Artemis-the-gr8 2022-08-01 21:40:43 +02:00
parent f988b96adf
commit f6e37de926
8 changed files with 145 additions and 47 deletions

View File

@ -23,6 +23,7 @@ public final class Main extends JavaPlugin {
private static BukkitAudiences adventure;
private static ConfigHandler config;
private static OfflinePlayerHandler offlinePlayerHandler;
private static EnumHandler enumHandler;
@ -75,6 +76,13 @@ public final class Main extends JavaPlugin {
return adventure;
}
public static @NotNull ConfigHandler getConfigHandler() throws IllegalStateException {
if (config == null) {
throw new IllegalStateException("PlayerStats does not seem to be loaded!");
}
return config;
}
public static @NotNull EnumHandler getEnumHandler() {
if (enumHandler == null) {
enumHandler = new EnumHandler();
@ -99,13 +107,13 @@ public final class Main extends JavaPlugin {
private void initializeMainClasses() {
adventure = BukkitAudiences.create(this);
offlinePlayerHandler = new OfflinePlayerHandler();
config = new ConfigHandler(this);
enumHandler = new EnumHandler();
ConfigHandler config = new ConfigHandler(this);
offlinePlayerHandler = new OfflinePlayerHandler();
shareManager = new ShareManager(config);
outputManager = new OutputManager(getAdventure(), config, shareManager);
StatManager statManager = new StatManager(offlinePlayerHandler, config.getTopListMaxSize());
StatManager statManager = new StatManager(offlinePlayerHandler);
threadManager = new ThreadManager(config, statManager, outputManager);
playerStatsAPI = new PlayerStatsAPI(statManager, outputManager);

View File

@ -8,26 +8,49 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
/** The outgoing API that you can use to access the core functionality of PlayerStats!
To work with it, you need to call PlayerStats.{@link #getAPI()} to get an instance of
To work with the API, you need to call PlayerStats.{@link #getAPI()} to get an instance of
{@link PlayerStatsAPI}. You can then use this object to access any of the further methods.
<br>
<br>Since calculating a top or server statistics can take some time, I strongly
encourage you to call all the getServerStat() and getTopStats() methods from the
{@link StatCalculator} asynchronously. Otherwise, the main Thread will have to wait
until all calculations are done, and this can severely impact server performance.
encourage you to call all the serverStat() and topStat() methods asynchronously.
Otherwise, the main Thread will have to wait until all calculations are done,
and this can severely impact server performance.
*/
public interface PlayerStats {
/** Returns an instance of the {@link PlayerStatsAPI}.
/** Gets an instance of the {@link PlayerStatsAPI}.
@return the PlayerStats API
@throws IllegalStateException if PlayerStats is not loaded on the server when this method is called*/
@Contract(pure = true)
static @NotNull PlayerStats getAPI() throws IllegalStateException {
return Main.getPlayerStatsAPI();
}
/** Gets a StatRequest object that can be used to look up a player-statistic.
This StatRequest will have all default settings already configured,
and will be processed as soon as you call one of its methods.
@return a PlayerStatRequest that can be used to look up a statistic for the
Player whose name is provided*/
PlayerStatRequest playerStat(String playerName);
/** Gets a StatRequest object that can be used to look up a server-statistic.
This StatRequest will have all default settings already configured,
and will be processed as soon as you call one of its methods.
<br>
<br> Don't call this from the main Thread! (see class description)
@return a ServerStatRequest that can be used to look up a server total*/
ServerStatRequest serverStat();
/** Gets a StatRequest object that can be used to look up a top-x-statistic.
This StatRequest will have all default settings already configured, and will be
processed as soon as you call one of its methods.
<br>
<br> Don't call this from the main Thread! (see class description)
@param topListSize how big the top-x should be (10 by default)
@return a TopStatRequest that can be used to look up a top statistic*/
TopStatRequest topStat(int topListSize);
}

View File

@ -1,12 +1,15 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.StatResult;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequest;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull;
/** Completes a basic {@link StatRequest} provided by the {@link PlayerStatsAPI}
and performs a statistic lookup with the information that is stored inside this StatRequest.*/
public interface RequestExecutor<T> {
@Internal
@ -19,13 +22,30 @@ public interface RequestExecutor<T> {
return PlayerStatsAPI.statFormatter();
}
StatResult<T> untyped(@NotNull Statistic statistic);
/** Gets a StatResult for a Statistic of Statistic.Type {@code Untyped}.
/** @throws IllegalArgumentException if <code>statistic</code> is not of Type.Block
@param statistic a Statistic of Type.Untyped
@return a {@link StatResult}
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Untyped*/
StatResult<T> untyped(@NotNull Statistic statistic) throws IllegalArgumentException;
/** Gets a StatResult for a Statistic of Statistic.Type Block or Item.
@param statistic a Statistic of Type.Block or Type.Item
@param material a block if the <code>statistic</code> is of Type.Block,
and an item if the <code>statistic</code> is of Type.Item
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Block
(with a block as <code>material</code>), or <code>statistic</code> is not of Type.Item
(with an item as <code>material</code>)
@return a {@link StatResult} */
StatResult<T> blockOrItemType(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException;
/** Gets a StatResult for a Statistic of Statistic.Type Entity.
@param statistic a Statistic of Type.Entity
@param entityType an EntityType
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Entity,
or <code>entityType</code> is not a valid EntityType
@return a {@link StatResult} */
StatResult<T> entityType(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException;
}
}

View File

@ -1,18 +1,40 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.StatResult;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
/** Turns user input into a valid {@link StatRequest}. This StatRequest should hold all
/** Turns user input into a completed {@link StatRequest}. This StatRequest should hold all
the information PlayerStats needs to work with, and is used by the {@link StatCalculator}
to get the desired statistic data.*/
public interface RequestGenerator {
StatRequest untyped(Statistic statistic);
/** Gets a StatRequest for a Statistic of Statistic.Type {@code Untyped}.
StatRequest blockOrItemType(Statistic statistic, Material material);
@param statistic a Statistic of Type.Untyped
@return a {@link StatRequest}
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Untyped*/
StatRequest untyped(@NotNull Statistic statistic) throws IllegalArgumentException;
StatRequest entityType(Statistic statistic, EntityType entityType);
/** Gets a StatRequest for a Statistic of Statistic.Type Block or Item.
@param statistic a Statistic of Type.Block or Type.Item
@param material a block if the <code>statistic</code> is of Type.Block,
and an item if the <code>statistic</code> is of Type.Item
@return a {@link StatRequest}
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Block
(with a block as <code>material</code>), or <code>statistic</code> is not of Type.Item
(with an item as <code>material</code>) */
StatRequest blockOrItemType(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException;
/** Gets a StatRequest for a Statistic of Statistic.Type Entity.
@param statistic a Statistic of Type.Entity
@param entityType an EntityType
@return a {@link StatRequest}
@throws IllegalArgumentException if <code>statistic</code> is not of Type.Entity*/
StatRequest entityType(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException;
}

View File

@ -84,7 +84,6 @@ public final class ReloadThread extends Thread {
OutputManager.updateMessageWriters(config);
OfflinePlayerHandler.updateOfflinePlayerList(loadOfflinePlayers());
ShareManager.updateSettings(config);
StatManager.updateSettings(config.getTopListMaxSize());
}
private ConcurrentHashMap<String, UUID> loadOfflinePlayers() {

View File

@ -17,19 +17,14 @@ import java.util.stream.Collectors;
public final class StatManager implements StatCalculator {
private final OfflinePlayerHandler offlinePlayerHandler;
private static int topListMaxSize;
public StatManager(OfflinePlayerHandler offlinePlayerHandler, int topListMaxSize) {
public StatManager(OfflinePlayerHandler offlinePlayerHandler) {
this.offlinePlayerHandler = offlinePlayerHandler;
StatManager.topListMaxSize = topListMaxSize;
}
public static void updateSettings(int topListMaxSize) {
StatManager.topListMaxSize = topListMaxSize;
}
/** Gets the statistic data for an individual player. If somehow the player
cannot be found, this returns 0.*/
@Override
public int getPlayerStat(StatRequest statRequest) {
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(statRequest.getPlayerName());
if (player != null) {
@ -43,13 +38,15 @@ public final class StatManager implements StatCalculator {
return 0;
}
@Override
public LinkedHashMap<String, Integer> getTopStats(StatRequest statRequest) {
return getAllStatsAsync(statRequest).entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(topListMaxSize)
.limit(statRequest.getTopListSize())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
@Override
public long getServerStat(StatRequest statRequest) {
List<Integer> numbers = getAllStatsAsync(statRequest)
.values()

View File

@ -12,6 +12,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public record StatRequestHandler(StatRequest statRequest) implements RequestGenerator {
@ -31,7 +32,7 @@ public record StatRequestHandler(StatRequest statRequest) implements RequestGene
public static StatRequestHandler topRequestHandler(int topListSize) {
StatRequest request = new StatRequest(Bukkit.getConsoleSender(), true);
request.setTarget(Target.TOP);
request.setTopListSize(topListSize != 0 ? topListSize : 10);
request.setTopListSize(topListSize != 0 ? topListSize : Main.getConfigHandler().getTopListMaxSize());
return new StatRequestHandler(request);
}
@ -44,27 +45,38 @@ public record StatRequestHandler(StatRequest statRequest) implements RequestGene
}
@Override
public StatRequest untyped(Statistic statistic) {
statRequest.setStatistic(statistic);
return statRequest;
public StatRequest untyped(@NotNull Statistic statistic) throws IllegalArgumentException {
if (statistic.getType() == Statistic.Type.UNTYPED) {
statRequest.setStatistic(statistic);
return statRequest;
}
throw new IllegalArgumentException("This statistic is not of Type.Untyped");
}
@Override
public StatRequest blockOrItemType(Statistic statistic, Material material) {
statRequest.setSubStatEntryName(material.toString());
if (statistic.getType() == Statistic.Type.BLOCK) {
public StatRequest blockOrItemType(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException {
Statistic.Type type = statistic.getType();
if (type == Statistic.Type.BLOCK && material.isBlock()) {
statRequest.setBlock(material);
} else {
}
else if (type == Statistic.Type.ITEM && material.isItem()){
statRequest.setItem(material);
}
else {
throw new IllegalArgumentException("Either this statistic is not of Type.Block or Type.Item, or no valid block or item has been provided");
}
statRequest.setSubStatEntryName(material.toString());
return statRequest;
}
@Override
public StatRequest entityType(Statistic statistic, EntityType entityType) {
statRequest.setSubStatEntryName(entityType.toString());
statRequest.setEntity(entityType);
return statRequest;
public StatRequest entityType(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException {
if (statistic.getType() == Statistic.Type.ENTITY) {
statRequest.setSubStatEntryName(entityType.toString());
statRequest.setEntity(entityType);
return statRequest;
}
throw new IllegalArgumentException("This statistic is not of Type.Entity");
}
/**

View File

@ -3,14 +3,17 @@ package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.TextComponent;
/** Holds the result of a completed stat-lookup. From the StatResult,
you can get the raw numbers:
/** Holds the result of a completed stat-lookup. The <code>Type</code> parameter
<code>T</code> of the StatResult represents the data type of the stored number:
From the StatResult,
you can get the numbers in a formatted message, or the raw numbers by themselves:
<ul>
<li> <code>int</code> for playerStat
<li> <code>long</code> for serverStat
<li> <code>Integer</code> for playerStat
<li> <code>Long</code> for serverStat
<li> <code>LinkedHashMap(String, Integer)</code> for topStat
</ul>
Besides raw numbers, you can also get a formatted message. This can either
You can get the raw numbers with {@link #getNumericalValue()}. Additionally,
you can get a formatted message that includes formatted numbers. This can either
be a String or a {@link TextComponent}, and contains the following information:
<ul>
<li> for playerStat:
@ -23,19 +26,33 @@ import net.kyori.adventure.text.TextComponent;
<br> [2.] [player-name] [.....] [formatted-number]
<br> [3.] etc...
</ul>
If you get a TextComponent, you can send this directly to a Minecraft client or console
with the Adventure library. To send a Component, you need to get a {@link BukkitAudiences}
object, and use that to send the desired Component. Normally you would have to add Adventure
The TextComponents can be sent directly to a Minecraft client or console with the
Adventure library. To send a Component, you need to get a {@link BukkitAudiences} object,
and use that to send the desired Component. Normally you would have to add Adventure
as a dependency to your project, but since the library is included in PlayerStats, you can
access it directly. Information on how to get and use the BukkitAudiences object can be found on
<a href="https://docs.adventure.kyori.net/platform/bukkit.html">Adventure's website</a>.
<br>
access it directly. Information on how to get and use the BukkitAudiences object can be
found on <a href="https://docs.adventure.kyori.net/platform/bukkit.html">Adventure's website</a>.
*/
public interface StatResult<T> {
/** Gets the raw number for the completed stat-lookup this {@link StatResult} stores.
@return {@code Integer} for playerStat, {@code Long} for serverStat,
and {@code LinkedHashMap<String, Integer>} for topStat*/
T getNumericalValue();
/** Gets the formatted message for the completed stat-lookup this {@link StatResult} stores.
@return a {@code TextComponent} message containing the formatted number.
This message follows the same style/color/language settings that are specified in the
PlayerStats config. See class description for more information. */
TextComponent getFormattedTextComponent();
/** Gets the formatted message for the completed stat-lookup this {@link StatResult} stores.
@return a String message containing the formatted number. This message follows
the same style and color settings that are specified in the PlayerStats config,
but it is not translatable (it is always plain English). See class description
for more information.*/
String getFormattedString();
}