mirror of
https://github.com/itHotL/PlayerStats.git
synced 2025-02-28 03:42:53 +01:00
Separated the API into 3 different interfaces: RequestGenerator, StatCalculator, and StatFormatter
This commit is contained in:
parent
81acf6b308
commit
3a542ec72a
@ -1,34 +1,19 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.api;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.Main;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.*;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
/** This is 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 {@link PlayerStatsAPI}.
|
||||
You can then use this object to access any of the further methods.
|
||||
To work with it, 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, it is recommended to call all the
|
||||
getServerStat() or getTopStats() methods asynchronously. Otherwise, the main Thread will have
|
||||
to wait until all calculations are done, and this might cause some lag spikes on the server.
|
||||
<br>
|
||||
<br>The result of the methods in PlayerStats' API are returned in the form of a TextComponent,
|
||||
which 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. Normally you would
|
||||
have to add the library as a dependency, 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>
|
||||
<br>Alternatively, you can also turn your TextComponent into a plain String with
|
||||
{@link #statResultComponentToString(TextComponent)}. Don't use Adventure's method .content()
|
||||
on your statResult to do this - because of the way the TextComponent is built by PlayerStats,
|
||||
you won't be able to get the full content that way. </p>*/
|
||||
<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 might severely impact server performance.
|
||||
*/
|
||||
public interface PlayerStats {
|
||||
|
||||
/** Returns an instance of the {@link PlayerStatsAPI}.
|
||||
@ -38,68 +23,15 @@ public interface PlayerStats {
|
||||
return Main.getPlayerStatsAPI();
|
||||
}
|
||||
|
||||
String statResultComponentToString(TextComponent component);
|
||||
/** The {@link StatCalculator} is responsible for getting, calculating and/or ordering raw numbers.
|
||||
It gets its data from the vanilla statistic files (stored by the server). It can return three kinds of data,
|
||||
depending on the chosen {@link Target}:
|
||||
<br>- int (for {@link Target#PLAYER})
|
||||
<br>- long (for {@link Target#SERVER})
|
||||
<br>- LinkedHashMap[String player-name, Integer number] (for {@link Target#TOP})*/
|
||||
StatCalculator statCalculator();
|
||||
|
||||
/** Get a formatted player-statistic of Statistic.Type Untyped.
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[player-name]: [number] [stat-name]
|
||||
@throws NullPointerException if statistic or playerName is null*/
|
||||
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull String playerName) throws NullPointerException;
|
||||
RequestGenerator requestGenerator();
|
||||
|
||||
/** Get a formatted player-statistic of Statistic.Type Block or Item.
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[player-name]: [number] [stat-name] [sub-stat-name]
|
||||
@throws NullPointerException if statistic, material or playerName is null*/
|
||||
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull Material material, @NotNull String playerName) throws NullPointerException;
|
||||
|
||||
/** Get a formatted player-statistic of Statistic.Type Entity.
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[player-name]: [number] [stat-name] [sub-stat-name]
|
||||
@throws NullPointerException if statistic, entity or playerName is null*/
|
||||
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull EntityType entity, @NotNull String playerName) throws NullPointerException;
|
||||
|
||||
/** Get a formatted server-statistic of Statistic.Type Untyped. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[Total on] [server-name]: [number] [stat-name]
|
||||
@throws NullPointerException if statistic is null*/
|
||||
TextComponent getServerStat(@NotNull Statistic statistic) throws NullPointerException;
|
||||
|
||||
/** Get a formatted server-statistic of Statistic.Type Block or Item. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]
|
||||
@throws NullPointerException if statistic or material is null*/
|
||||
TextComponent getServerStat(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException;
|
||||
|
||||
/** Get a formatted server-statistic of Statistic.Type Entity. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]
|
||||
@throws NullPointerException if statistic or entity is null*/
|
||||
TextComponent getServerStat(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException;
|
||||
|
||||
/** Get a formatted top-statistic of Statistic.Type Untyped. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[PlayerStats] [Top 10] [stat-name]
|
||||
<br> [1.] [player-name] [number]
|
||||
<br> [2.] [player-name] [number]
|
||||
<br> [3.] etc...
|
||||
@throws NullPointerException if statistic is null*/
|
||||
TextComponent getTopStats(@NotNull Statistic statistic) throws NullPointerException;
|
||||
|
||||
/** Get a formatted top-statistic of Statistic.Type Block or Item. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name]
|
||||
<br> [1.] [player-name] [number]
|
||||
<br> [2.] [player-name] [number]
|
||||
<br> [3.] etc...
|
||||
@throws NullPointerException if statistic or material is null*/
|
||||
TextComponent getTopStats(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException;
|
||||
|
||||
/** Get a formatted top-statistic of Statistic.Type Entity. Don't call this from the main Thread (see class description)!
|
||||
@return a TextComponent with the following parts:
|
||||
<br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name]
|
||||
<br> [1.] [player-name] [number]
|
||||
<br> [2.] [player-name] [number]
|
||||
<br> [3.] etc...
|
||||
@throws NullPointerException if statistic or entity is null*/
|
||||
TextComponent getTopStats(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException;
|
||||
StatFormatter statFormatter();
|
||||
}
|
@ -1,19 +1,7 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.api;
|
||||
|
||||
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.statistic.RequestManager;
|
||||
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
|
||||
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import static org.jetbrains.annotations.ApiStatus.Internal;
|
||||
|
||||
@ -32,76 +20,17 @@ public final class PlayerStatsAPI implements PlayerStats {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String statResultComponentToString(TextComponent component) {
|
||||
return statFormatter.statResultComponentToString(component);
|
||||
public StatCalculator statCalculator() {
|
||||
return statManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull String playerName) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.PLAYER, statistic, null, null, playerName);
|
||||
public RequestGenerator requestGenerator() {
|
||||
return requestManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull Material material, @NotNull String playerName) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.PLAYER, statistic, material, null, playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull EntityType entity, @NotNull String playerName) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.PLAYER, statistic, null, entity, playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getServerStat(@NotNull Statistic statistic) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.SERVER, statistic, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getServerStat(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.SERVER, statistic, material, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getServerStat(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.SERVER, statistic, null, entity, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getTopStats(@NotNull Statistic statistic) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.TOP, statistic, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getTopStats(@NotNull Statistic statistic, @NotNull Material material) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.TOP, statistic, material, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextComponent getTopStats(@NotNull Statistic statistic, @NotNull EntityType entity) throws NullPointerException {
|
||||
return getFormattedStatistic(Target.TOP, statistic, null, entity, null);
|
||||
}
|
||||
|
||||
private TextComponent getFormattedStatistic(@NotNull Target selection, @NotNull Statistic statistic,
|
||||
@Nullable Material material, @Nullable EntityType entity, @Nullable String playerName) throws NullPointerException {
|
||||
StatRequest request = requestManager.generateRequest(selection, statistic, material, entity, playerName);
|
||||
if (requestManager.validateAPIRequest(request)) {
|
||||
MyLogger.logMsg("API is being called! We are calculating a " + selection + "for " + statistic);
|
||||
switch (selection) {
|
||||
case PLAYER -> {
|
||||
int stat = statManager.getPlayerStat(request);
|
||||
return statFormatter.formatPlayerStat(request, stat);
|
||||
}
|
||||
case SERVER -> {
|
||||
long stat = statManager.getServerStat(request);
|
||||
return statFormatter.formatServerStat(request, stat);
|
||||
}
|
||||
case TOP -> {
|
||||
LinkedHashMap<String, Integer> stats = statManager.getTopStats(request);
|
||||
return statFormatter.formatTopStat(request, stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NullPointerException("Not enough parameters are present for a valid statistic look-up! " +
|
||||
"Make sure you include a block/item/entity if Statistic.Type is not Untyped, and include a playerName if you want a player-statistic");
|
||||
public StatFormatter statFormatter() {
|
||||
return statFormatter;
|
||||
}
|
||||
}
|
@ -1,29 +1,32 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.api;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/** The {@link RequestGenerator} can turn some user input, such as a String
|
||||
(for example: "stat animals_bred") into a specific {@link StatRequest} that holds
|
||||
all the information {@link PlayerStatsAPI} needs to work with.
|
||||
This StatRequest is then used by the {@link StatCalculator} to get the desired statistic data.*/
|
||||
/** Turns user input into a valid {@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 {
|
||||
|
||||
/** 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 SimpleStatRequest could not be created.
|
||||
as CommandSender. This CommandSender will receive feedback messages if the StatRequest could not be created.
|
||||
|
||||
@param args an Array of args such as a CommandSender would put in Minecraft chat:
|
||||
<p>- a stat-name (example: "mine_block")</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>- if "player" was chosen, include a player-name</p>
|
||||
@param sender the CommandSender that requested this specific statistic
|
||||
@return the generated StatRequest
|
||||
@throws IllegalArgumentException if the args do not result in a valid statistic look-up*/
|
||||
StatRequest generateRequest(CommandSender sender, String[] args);
|
||||
|
||||
StatRequest generateRequest(@NotNull Target selection, @NotNull Statistic statistic, Material material, EntityType entity, String playerName);
|
||||
StatRequest createPlayerStatRequest(String playerName, Statistic statistic, Material material, EntityType entity);
|
||||
|
||||
StatRequest createServerStatRequest(Statistic statistic, Material material, EntityType entityType);
|
||||
|
||||
StatRequest createTopStatRequest(Statistic statistic, Material material, EntityType entityType);
|
||||
}
|
||||
|
@ -5,12 +5,16 @@ import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/** The {@link StatCalculator} represents the actual statistic-getting magic that happens once a valid
|
||||
{@link StatRequest} has been obtained. It takes a valid StatRequest, and returns (a map of) numbers. */
|
||||
{@link StatRequest} is passed to it. It takes a valid StatRequest, and returns (a map of) numbers.
|
||||
For more information on how to create a valid StatRequest, see the class description for {@link StatRequest}.*/
|
||||
public interface StatCalculator {
|
||||
|
||||
/** Returns the requested Statistic*/
|
||||
int getPlayerStat(StatRequest request);
|
||||
|
||||
/** Don't call from main Thread!*/
|
||||
long getServerStat(StatRequest request);
|
||||
|
||||
/** Don't call from main Thread!*/
|
||||
LinkedHashMap<String, Integer> getTopStats(StatRequest request);
|
||||
}
|
||||
|
@ -1,25 +1,47 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.api;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.*;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/** The {@link StatFormatter} defines what the output of any given statistic look-up should be.
|
||||
<br></br>
|
||||
<p>The Formatter takes a {@link StatRequest} and the result of {@link StatCalculator} calculations, and transforms the
|
||||
request object and raw numbers into a pretty message (TextComponent) with all the relevant information in it.
|
||||
This output is ready to be sent to a Player or Console, or can be turned into a String representation if necessary.*/
|
||||
/** The {@link StatFormatter} formats raw numbers into pretty messages.
|
||||
This Formatter takes a {@link StatRequest} and combines it with the raw number(s)
|
||||
returned by the {@link StatCalculator}, and transforms those into a pretty message
|
||||
(by default a TextComponent) with all the relevant information in it.
|
||||
<br>
|
||||
<br>The output is ready to be sent to a Minecraft client or console with the Adventure library.
|
||||
To send a Component, you need to get a {@link BukkitAudiences} object. Normally you would
|
||||
have to add the library as a dependency, 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>
|
||||
<br>Alternatively, you can also turn your TextComponent into a plain String with
|
||||
{@link #statResultComponentToString(TextComponent)}. Don't use Adventure's method .content()
|
||||
on your statResult to do this - because of the way the TextComponent is built by PlayerStats,
|
||||
you won't be able to get the full content that way.*/
|
||||
public interface StatFormatter {
|
||||
|
||||
/** Turns a TextComponent into its String representation. If you don't want to work with
|
||||
Adventure's TextComponents, you can call this method to turn any stat-result into a String.
|
||||
@return a String representation of this TextComponent, without hover/click events, but with color, style and formatting */
|
||||
@return a String representation of this TextComponent, without hover/click events,
|
||||
but with color, style and formatting. TranslatableComponents will be turned into
|
||||
plain English.*/
|
||||
String statResultComponentToString(TextComponent statResult);
|
||||
|
||||
/** @return a TextComponent with the following parts:
|
||||
<br>[player-name]: [number] [stat-name] {sub-stat-name}*/
|
||||
TextComponent formatPlayerStat(StatRequest request, int playerStat);
|
||||
|
||||
/** @return a TextComponent with the following parts:
|
||||
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]*/
|
||||
TextComponent formatServerStat(StatRequest request, long serverStat);
|
||||
|
||||
/** @return a TextComponent with the following parts:
|
||||
<br>[PlayerStats] [Top 10] [stat-name] [sub-stat-name]
|
||||
<br> [1.] [player-name] [number]
|
||||
<br> [2.] [player-name] [number]
|
||||
<br> [3.] etc...*/
|
||||
TextComponent formatTopStat(StatRequest request, LinkedHashMap<String, Integer> topStats);
|
||||
}
|
@ -1,40 +1,70 @@
|
||||
package com.gmail.artemis.the.gr8.playerstats.models;
|
||||
|
||||
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
|
||||
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/** The Object PlayerStats uses to calculate the appropriate statistic.
|
||||
It is generated from the args provided by a CommandSender when /stat is called,
|
||||
and always contains this CommandSender. By default, {@link #getSelection()}
|
||||
will return {@link Target#TOP}, unless another selection is specified in the args.*/
|
||||
public final class StatRequest {
|
||||
/** A StatRequest is the object PlayerStats uses to calculate and format the requested statistic.
|
||||
This object can be generated from two different sources:
|
||||
<br>- Internally: by PlayerStats itself when /stat is called, using the args provided by the CommandSender.
|
||||
<br>- Externally: through the API methods provided by the {@link RequestGenerator} interface.
|
||||
<br>
|
||||
<br>For this StatRequest to be valid, it needs the following values:
|
||||
<ul>
|
||||
<li> a {@link Statistic} <code>statistic</code> </li>
|
||||
<li> if this Statistic is not of {@link Statistic.Type} Untyped, a <code>subStatEntryName</code> needs to be set,
|
||||
together with one of the following values:
|
||||
<br>- for Type.Block: a {@link Material} <code>blockMaterial</code>
|
||||
<br>- for Type.Item: a {@link Material} <code>itemMaterial</code>
|
||||
<br>- for Type.Entity: an {@link EntityType} <code>entityType</code>
|
||||
<li> a {@link Target} <code>target</code> (automatically set for all API-requests)
|
||||
<li> if the <code>target</code> is Target.Player, a <code>playerName</code> needs to be added
|
||||
</ul>*/
|
||||
public class StatRequest {
|
||||
|
||||
private final CommandSender sender;
|
||||
private boolean isAPIRequest;
|
||||
private Statistic statistic;
|
||||
private String playerName;
|
||||
private Target selection;
|
||||
private Target target;
|
||||
|
||||
private String subStatEntry;
|
||||
private String subStatEntryName;
|
||||
private EntityType entity;
|
||||
private Material block;
|
||||
private Material item;
|
||||
private boolean playerFlag;
|
||||
|
||||
//make a SimpleStatRequest for a given CommandSender with some default values
|
||||
/** Create a new {@link StatRequest} with default values:
|
||||
<br>- CommandSender sender (provided)
|
||||
<br>- Target <code>target</code> = {@link Target#TOP}
|
||||
<br>- boolean <code>playerFlag</code> = false
|
||||
<br>- boolean <code>isAPIRequest</code> = false
|
||||
|
||||
@param sender the CommandSender who prompted this RequestGenerator
|
||||
*/
|
||||
public StatRequest(@NotNull CommandSender sender) {
|
||||
this(sender, false);
|
||||
}
|
||||
|
||||
/** Create a new {@link StatRequest} with default values:
|
||||
<br>- CommandSender sender (provided)
|
||||
<br>- Target target = {@link Target#TOP}
|
||||
<br>- boolean playerFlag = false
|
||||
<br>- boolean isAPIRequest (provided)
|
||||
|
||||
@param sender the CommandSender who prompted this RequestGenerator
|
||||
@param isAPIRequest whether this RequestGenerator is coming through the API or the onCommand
|
||||
*/
|
||||
public StatRequest(@NotNull CommandSender sender, boolean isAPIRequest) {
|
||||
this.sender = sender;
|
||||
this.isAPIRequest = isAPIRequest;
|
||||
selection = Target.TOP;
|
||||
target = Target.TOP;
|
||||
playerFlag = false;
|
||||
}
|
||||
|
||||
@ -54,23 +84,30 @@ public final class StatRequest {
|
||||
return sender instanceof ConsoleCommandSender;
|
||||
}
|
||||
|
||||
/** Set a {@link Statistic} for this StatRequest.*/
|
||||
public void setStatistic(Statistic statistic) {
|
||||
this.statistic = statistic;
|
||||
}
|
||||
|
||||
/** Returns the set enum constant Statistic, or null if none was set. */
|
||||
/** If a {@link Statistic} was set, this will return it.
|
||||
|
||||
@return the <code>statistic</code> for this RequestGenerator*/
|
||||
public Statistic getStatistic() {
|
||||
return statistic;
|
||||
}
|
||||
|
||||
/** Sets the subStatEntry, and automatically tries to get the corresponding item/block/entity if there is a valid statType present.
|
||||
If the subStatEntry is set to null, any present item/block/entity is set to null again. */
|
||||
public void setSubStatEntry(String subStatEntry) {
|
||||
this.subStatEntry = subStatEntry;
|
||||
/** Sets the <code>subStatEntryName</code> (a block-, item- or entity-name). */
|
||||
public void setSubStatEntryName(String subStatEntry) {
|
||||
this.subStatEntryName = subStatEntry;
|
||||
}
|
||||
|
||||
public String getSubStatEntry() {
|
||||
return subStatEntry;
|
||||
/** If a {@link Statistic} is set, and this Statistic is of Type Block, Item or Entity,
|
||||
this will return the name of said block, item or entity
|
||||
(in the way .toString would for the given enum constant).
|
||||
|
||||
@return the <code>subStatEntryName</code>*/
|
||||
public @Nullable String getSubStatEntryName() {
|
||||
return subStatEntryName;
|
||||
}
|
||||
|
||||
public void setPlayerName(String playerName) {
|
||||
@ -86,18 +123,24 @@ public final class StatRequest {
|
||||
this.playerFlag = playerFlag;
|
||||
}
|
||||
|
||||
/** The "player" arg is a special case, because it could either be a valid subStatEntry, or indicate that the lookup action should target a specific player.
|
||||
This is why the playerFlag exists - if this is true, and playerName is null, subStatEntry should be set to "player". */
|
||||
/** For internal use. The "player" arg is a special case, because it could either be
|
||||
a valid <code>subStatEntry</code>, or indicate that the lookup action should target
|
||||
a specific player. This is why the <code>playerFlag</code> exists - if this flag true,
|
||||
and <code>playerName</code> is null, the <code>subStatEntry</code> should be set to "player". */
|
||||
public boolean getPlayerFlag() {
|
||||
return playerFlag;
|
||||
}
|
||||
|
||||
public void setSelection(Target selection) {
|
||||
this.selection = selection;
|
||||
public void setTarget(Target target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public @NotNull Target getSelection() {
|
||||
return selection;
|
||||
/** Returns the {@link Target} for this StatRequest.
|
||||
If no Target is explicitly set, this will return {@link Target#TOP}.
|
||||
All static factory methods that create a {@link StatRequest} set the
|
||||
appropriate Target for themselves, so there is no need to manually set the Target.*/
|
||||
public @NotNull Target getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setEntity(EntityType entity) {
|
||||
|
@ -177,7 +177,7 @@ public class MessageBuilder {
|
||||
.append(getStatNumberComponent(request.getStatistic(), stat, Target.PLAYER, request.isConsoleSender()))
|
||||
.append(space())
|
||||
.append(getStatNameComponent(request))
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getSelection(), request.isConsoleSender())) //space is provided by statUnitComponent
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getTarget(), request.isConsoleSender())) //space is provided by statUnitComponent
|
||||
.build();
|
||||
|
||||
return getFormattingFunction(playerStat, Target.PLAYER);
|
||||
@ -197,7 +197,7 @@ public class MessageBuilder {
|
||||
.append(getStatNumberComponent(request.getStatistic(), stat, Target.SERVER, request.isConsoleSender()))
|
||||
.append(space())
|
||||
.append(getStatNameComponent(request))
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getSelection(), request.isConsoleSender())) //space is provided by statUnit
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getTarget(), request.isConsoleSender())) //space is provided by statUnit
|
||||
.build();
|
||||
|
||||
return getFormattingFunction(serverStat, Target.SERVER);
|
||||
@ -308,7 +308,7 @@ public class MessageBuilder {
|
||||
.append(componentFactory.title(config.getTopStatsTitle(), Target.TOP)).append(space())
|
||||
.append(componentFactory.titleNumber(statListSize)).append(space())
|
||||
.append(getStatNameComponent(request)) //space is provided by statUnitComponent
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getSelection(), request.isConsoleSender()))
|
||||
.append(getStatUnitComponent(request.getStatistic(), request.getTarget(), request.isConsoleSender()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ public class MessageBuilder {
|
||||
private TextComponent getStatNameComponent(StatRequest request) {
|
||||
if (config.useTranslatableComponents()) {
|
||||
String statKey = languageKeyHandler.getStatKey(request.getStatistic());
|
||||
String subStatKey = request.getSubStatEntry();
|
||||
String subStatKey = request.getSubStatEntryName();
|
||||
if (subStatKey != null) {
|
||||
switch (request.getStatistic().getType()) {
|
||||
case BLOCK -> subStatKey = languageKeyHandler.getBlockKey(request.getBlock());
|
||||
@ -363,13 +363,13 @@ public class MessageBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
return componentFactory.statAndSubStatNameTranslatable(statKey, subStatKey, request.getSelection());
|
||||
return componentFactory.statAndSubStatNameTranslatable(statKey, subStatKey, request.getTarget());
|
||||
}
|
||||
else {
|
||||
return componentFactory.statAndSubStatName(
|
||||
StringUtils.prettify(request.getStatistic().toString()),
|
||||
StringUtils.prettify(request.getSubStatEntry()),
|
||||
request.getSelection());
|
||||
StringUtils.prettify(request.getSubStatEntryName()),
|
||||
request.getTarget());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.RecursiveAction;
|
||||
|
||||
/** The action that is executed when a reload-command is triggered. */
|
||||
public final class ReloadAction extends RecursiveAction {
|
||||
final class ReloadAction extends RecursiveAction {
|
||||
|
||||
private static int threshold;
|
||||
|
||||
|
@ -16,18 +16,31 @@ import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RequestManager implements RequestGenerator {
|
||||
public final class RequestManager extends StatRequest implements RequestGenerator {
|
||||
|
||||
private final EnumHandler enumHandler;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private static OutputManager outputManager;
|
||||
|
||||
public RequestManager(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) {
|
||||
super(Bukkit.getConsoleSender());
|
||||
this.enumHandler = enumHandler;
|
||||
this.offlinePlayerHandler = offlinePlayerHandler;
|
||||
RequestManager.outputManager = outputManager;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
|
||||
@param args an Array of args such as a CommandSender would put in Minecraft chat:
|
||||
<p>- a <code>statName</code> (example: "mine_block")</p>
|
||||
<p>- if applicable, a <code>subStatEntryName</code> (example: diorite)(</p>
|
||||
<p>- a <code>target</code> for this lookup: can be "top", "server", "player" (or "me" to indicate the current CommandSender)</p>
|
||||
<p>- if "player" was chosen, include a <code>playerName</code></p>
|
||||
|
||||
@param sender the CommandSender that requested this specific statistic
|
||||
@return the generated StatRequest
|
||||
*/
|
||||
public StatRequest generateRequest(CommandSender sender, String[] args) {
|
||||
StatRequest request = new StatRequest(sender);
|
||||
for (String arg : args) {
|
||||
@ -41,28 +54,28 @@ public class RequestManager implements RequestGenerator {
|
||||
request.setPlayerFlag(true);
|
||||
}
|
||||
else {
|
||||
if (request.getSubStatEntry() == null) request.setSubStatEntry(arg);
|
||||
if (request.getSubStatEntryName() == null) request.setSubStatEntryName(arg);
|
||||
}
|
||||
}
|
||||
//check for selection
|
||||
else if (arg.equalsIgnoreCase("top")) {
|
||||
request.setSelection(Target.TOP);
|
||||
request.setTarget(Target.TOP);
|
||||
}
|
||||
else if (arg.equalsIgnoreCase("server")) {
|
||||
request.setSelection(Target.SERVER);
|
||||
request.setTarget(Target.SERVER);
|
||||
}
|
||||
else if (arg.equalsIgnoreCase("me")) {
|
||||
if (sender instanceof Player) {
|
||||
request.setPlayerName(sender.getName());
|
||||
request.setSelection(Target.PLAYER);
|
||||
request.setTarget(Target.PLAYER);
|
||||
}
|
||||
else if (sender instanceof ConsoleCommandSender) {
|
||||
request.setSelection(Target.SERVER);
|
||||
request.setTarget(Target.SERVER);
|
||||
}
|
||||
}
|
||||
else if (offlinePlayerHandler.isRelevantPlayer(arg) && request.getPlayerName() == null) {
|
||||
request.setPlayerName(arg);
|
||||
request.setSelection(Target.PLAYER);
|
||||
request.setTarget(Target.PLAYER);
|
||||
}
|
||||
else if (arg.equalsIgnoreCase("api")) {
|
||||
request.setAPIRequest();
|
||||
@ -72,23 +85,38 @@ public class RequestManager implements RequestGenerator {
|
||||
return request;
|
||||
}
|
||||
|
||||
/** This method will generate a {@link StatRequest} for a stat-request arriving through the API.*/
|
||||
public StatRequest generateRequest(@NotNull Target selection, @NotNull Statistic statistic, Material material, EntityType entity, String playerName) {
|
||||
@Override
|
||||
public StatRequest createPlayerStatRequest(String playerName, Statistic statistic, Material material, EntityType entity) {
|
||||
return generateRequest(Target.PLAYER, statistic, material, entity, playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatRequest createServerStatRequest(Statistic statistic, Material material, EntityType entityType) {
|
||||
return generateRequest(Target.SERVER, statistic, material, entityType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatRequest createTopStatRequest(Statistic statistic, Material material, EntityType entityType) {
|
||||
return generateRequest(Target.TOP, statistic, material, entityType, null);
|
||||
}
|
||||
|
||||
/** This method will generate a {@link StatRequest} for a request arriving through the API.*/
|
||||
private StatRequest generateRequest(@NotNull Target selection, @NotNull Statistic statistic, Material material, EntityType entity, String playerName) {
|
||||
StatRequest request = new StatRequest(Bukkit.getConsoleSender(), true);
|
||||
request.setSelection(selection);
|
||||
request.setTarget(selection);
|
||||
request.setStatistic(statistic);
|
||||
switch (statistic.getType()) {
|
||||
case BLOCK -> {
|
||||
request.setBlock(material);
|
||||
request.setSubStatEntry(material.toString());
|
||||
request.setSubStatEntryName(material.toString());
|
||||
}
|
||||
case ITEM -> {
|
||||
request.setItem(material);
|
||||
request.setSubStatEntry(material.toString());
|
||||
request.setSubStatEntryName(material.toString());
|
||||
}
|
||||
case ENTITY -> {
|
||||
request.setEntity(entity);
|
||||
request.setSubStatEntry(entity.toString());
|
||||
request.setSubStatEntryName(entity.toString());
|
||||
}
|
||||
}
|
||||
if (selection == Target.PLAYER) request.setPlayerName(playerName);
|
||||
@ -97,22 +125,30 @@ public class RequestManager implements RequestGenerator {
|
||||
|
||||
/** Checks if a given {@link StatRequest} would result in a valid statistic look-up,
|
||||
and sends a feedback message to the CommandSender that prompted the request if it is invalid.
|
||||
<p>The following is checked:
|
||||
<br>1. Is a Statistic set?</br>
|
||||
<br>2. Is a sub-Statistic needed, and if so, is a corresponding Material/EntityType present?</br>
|
||||
<br>3. If the target is PLAYER, is a valid PlayerName provided? </br>
|
||||
@return true if the StatRequest is valid, and false otherwise. */
|
||||
<br> The following is checked:
|
||||
<ul>
|
||||
<li>Is a <code>statistic</code> set?
|
||||
<li>Is a <code>subStatEntry</code> needed, and if so, is a corresponding Material/EntityType present?
|
||||
<li>If the <code>target</code> is Player, is a valid <code>playerName</code> provided?
|
||||
</ul>
|
||||
@param request the StatRequest to check
|
||||
@return true if the StatRequest is valid, and false otherwise.
|
||||
*/
|
||||
public boolean validateRequest(StatRequest request) {
|
||||
return validateRequestAndSendMessage(request, request.getCommandSender());
|
||||
}
|
||||
|
||||
/** Checks if a given {@link StatRequest} would result in a valid statistic look-up,
|
||||
and sends a feedback message in the server console if it is invalid.
|
||||
<p>The following is checked:
|
||||
<br>1. Is a Statistic set?</br>
|
||||
<br>2. Is a sub-Statistic needed, and if so, is a corresponding Material/EntityType present?</br>
|
||||
<br>3. If the target is PLAYER, is a valid PlayerName provided? </br>
|
||||
@return true if the StatRequest is valid, and false otherwise. */
|
||||
<br> The following is checked:
|
||||
<ul>
|
||||
<li>Is a <code>statistic</code> set?
|
||||
<li>Is a <code>subStatEntry</code> needed, and if so, is a corresponding Material/EntityType present?
|
||||
<li>If the <code>target</code> is Player, is a valid <code>playerName</code> provided?
|
||||
</ul>
|
||||
@param request the StatRequest to check
|
||||
@return true if the StatRequest is valid, and false otherwise.
|
||||
*/
|
||||
public boolean validateAPIRequest(StatRequest request) {
|
||||
return validateRequestAndSendMessage(request, Bukkit.getConsoleSender());
|
||||
}
|
||||
@ -123,15 +159,15 @@ public class RequestManager implements RequestGenerator {
|
||||
return false;
|
||||
}
|
||||
Statistic.Type type = request.getStatistic().getType();
|
||||
if (request.getSubStatEntry() == null && type != Statistic.Type.UNTYPED) {
|
||||
if (request.getSubStatEntryName() == null && type != Statistic.Type.UNTYPED) {
|
||||
outputManager.sendFeedbackMsgMissingSubStat(sender, type);
|
||||
return false;
|
||||
}
|
||||
else if (!hasMatchingSubStat(request)) {
|
||||
outputManager.sendFeedbackMsgWrongSubStat(sender, type, request.getSubStatEntry());
|
||||
outputManager.sendFeedbackMsgWrongSubStat(sender, type, request.getSubStatEntryName());
|
||||
return false;
|
||||
}
|
||||
else if (request.getSelection() == Target.PLAYER && request.getPlayerName() == null) {
|
||||
else if (request.getTarget() == Target.PLAYER && request.getPlayerName() == null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_PLAYER_NAME);
|
||||
return false;
|
||||
}
|
||||
@ -148,15 +184,15 @@ public class RequestManager implements RequestGenerator {
|
||||
Statistic.Type type = request.getStatistic().getType();
|
||||
|
||||
if (request.getPlayerFlag()) { //unpack the playerFlag
|
||||
if (type == Statistic.Type.ENTITY && request.getSubStatEntry() == null) {
|
||||
request.setSubStatEntry("player");
|
||||
if (type == Statistic.Type.ENTITY && request.getSubStatEntryName() == null) {
|
||||
request.setSubStatEntryName("player");
|
||||
}
|
||||
else {
|
||||
request.setSelection(Target.PLAYER);
|
||||
request.setTarget(Target.PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
String subStatEntry = request.getSubStatEntry();
|
||||
String subStatEntry = request.getSubStatEntryName();
|
||||
switch (type) { //attempt to convert relevant subStatEntries into their corresponding Enum Constant
|
||||
case BLOCK -> {
|
||||
Material block = EnumHandler.getBlockEnum(subStatEntry);
|
||||
@ -171,7 +207,7 @@ public class RequestManager implements RequestGenerator {
|
||||
if (item != null) request.setItem(item);
|
||||
}
|
||||
case UNTYPED -> { //remove unnecessary subStatEntries
|
||||
if (subStatEntry != null) request.setSubStatEntry(null);
|
||||
if (subStatEntry != null) request.setSubStatEntryName(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
/** The action that is executed when a stat-command is triggered. */
|
||||
public final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>> {
|
||||
final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>> {
|
||||
|
||||
private static int threshold;
|
||||
|
||||
|
@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
/** The Thread that is in charge of getting and calculating statistics.*/
|
||||
public class StatThread extends Thread {
|
||||
public final class StatThread extends Thread {
|
||||
|
||||
private static OutputManager outputManager;
|
||||
private static StatManager statManager;
|
||||
@ -57,7 +57,7 @@ public class StatThread extends Thread {
|
||||
outputManager.sendFeedbackMsgWaitAMoment(request.getCommandSender(), lastCalc > 20000);
|
||||
}
|
||||
|
||||
Target selection = request.getSelection();
|
||||
Target selection = request.getTarget();
|
||||
try {
|
||||
TextComponent statResult = switch (selection) {
|
||||
case PLAYER -> outputManager.formatPlayerStat(request, statManager.getPlayerStat(request));
|
||||
@ -65,7 +65,7 @@ public class StatThread extends Thread {
|
||||
case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request));
|
||||
};
|
||||
if (request.isAPIRequest()) {
|
||||
String msg = PlayerStats.getAPI().statResultComponentToString(statResult);
|
||||
String msg = PlayerStats.getAPI().statFormatter().statResultComponentToString(statResult);
|
||||
request.getCommandSender().sendMessage(msg);
|
||||
}
|
||||
else {
|
||||
|
@ -56,6 +56,7 @@ public final class OfflinePlayerHandler {
|
||||
return Bukkit.getOfflinePlayer(offlinePlayerUUIDs.get(playerName));
|
||||
}
|
||||
else {
|
||||
MyLogger.logMsg("Cannot calculate statistics for player-name: " + playerName, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user