Messing with API structure some more

This commit is contained in:
Artemis-the-gr8 2022-07-24 13:44:34 +02:00
parent 7b796c15dc
commit 096bb89607
13 changed files with 318 additions and 251 deletions

View File

@ -9,6 +9,7 @@ import com.gmail.artemis.the.gr8.playerstats.commands.TabCompleter;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.listeners.JoinListener;
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
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.OfflinePlayerHandler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
@ -22,6 +23,7 @@ public class Main extends JavaPlugin {
private static BukkitAudiences adventure;
private static PlayerStats playerStatsAPI;
private static OutputManager outputManager;
private static RequestManager requestManager;
private static ShareManager shareManager;
private static StatManager statManager;
private static ThreadManager threadManager;
@ -39,7 +41,7 @@ public class Main extends JavaPlugin {
//register all commands and the tabCompleter
PluginCommand statcmd = this.getCommand("statistic");
if (statcmd != null) {
statcmd.setExecutor(new StatCommand(outputManager, threadManager, statManager));
statcmd.setExecutor(new StatCommand(outputManager, threadManager, requestManager));
statcmd.setTabCompleter(new TabCompleter(offlinePlayerHandler));
}
PluginCommand reloadcmd = this.getCommand("statisticreload");
@ -109,10 +111,11 @@ public class Main extends JavaPlugin {
adventure = BukkitAudiences.create(this);
shareManager = new ShareManager(config);
statManager = new StatManager(offlinePlayerHandler, config.getTopListMaxSize());
outputManager = new OutputManager(getAdventure(), config, shareManager);
statManager = new StatManager(outputManager, offlinePlayerHandler, config.getTopListMaxSize());
requestManager = new RequestManager(offlinePlayerHandler, outputManager);
threadManager = new ThreadManager(config, statManager, outputManager, offlinePlayerHandler);
playerStatsAPI = PlayerStatsAPI.load(statManager, outputManager);
playerStatsAPI = new PlayerStatsAPI(requestManager, statManager, outputManager);
}
}

View File

@ -12,10 +12,11 @@ import org.jetbrains.annotations.NotNull;
/** This Interface is the outgoing API that provides access to the core functionality of PlayerStats.
To work with it, you can call PlayerStats.{@link #getAPI()} to get an instance of {@link PlayerStatsAPI}.
You can then use this object to call any of the below methods. Since calculating a
top or server statistics can take some time, it is recommended to call any of the
You can then use this object to get formatted statistics.
<p>Since calculating a top or server statistics can take some time, it is recommended to call any of the
getServerStat() or getTopStats() methods asynchronously. Otherwise, the main Thread will have
to wait until all calculations are done, and this might cause lag spikes on the server.
to wait until all calculations are done, and this might cause lag spikes on the server.</p>
<p>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 with the Adventure library,
@ -29,20 +30,6 @@ public interface PlayerStats {
return Main.getPlayerStatsAPI();
}
/** Returns a stat-result as if the caller ran the /stat command in Minecraft chat. Since calculating the
top or server statistics can take some time, it is recommended to call this method asynchronously
(otherwise the main Thread will have to wait until the calculations are done).
@param args an Array of args very similar to the input 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
@throws IllegalArgumentException if the args do not result in a valid statistic look-up*/
TextComponent getFancyStat(CommandSender sender, String[] args) throws IllegalArgumentException;
/** Get a formatted player-statistic of Statistic.Type UNTYPED.*/
TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull OfflinePlayer player);

View File

@ -1,13 +1,15 @@
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 net.kyori.adventure.text.TextComponent;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
@ -17,44 +19,85 @@ import static org.jetbrains.annotations.ApiStatus.Internal;
/** The implementation of the API Interface */
public final class PlayerStatsAPI implements PlayerStats {
private static RequestManager requestManager;
private static StatFormatter statFormatter;
private static StatManager statManager;
@Internal
private PlayerStatsAPI(StatManager stat, StatFormatter format) {
public PlayerStatsAPI(RequestManager request, StatManager stat, StatFormatter format) {
requestManager = request;
statFormatter = format;
statManager = stat;
}
@Internal
public static PlayerStatsAPI load(StatManager statManager, StatFormatter statFormatter) {
return new PlayerStatsAPI(statManager, statFormatter);
}
@Override
public TextComponent getFancyStat(CommandSender sender, String[] args) throws IllegalArgumentException {
StatRequest request = statManager.generateRequest(sender, args);
if (statManager.requestIsValid(request)) {
private TextComponent getFancyStat(CommandSender sender, String[] args) throws IllegalArgumentException {
StatRequest request = requestManager.generateRequest(sender, args);
if (requestManager.requestIsValid(request)) {
switch (request.getSelection()) {
case PLAYER -> {
int stat = statManager.getPlayerStat(request);
return statFormatter.formatPlayerStat(request, stat);
return statFormatter.formatPlayerStat(request, stat, true);
}
case SERVER -> {
long stat = statManager.getServerStat(request);
return statFormatter.formatServerStat(request, stat);
return statFormatter.formatServerStat(request, stat, true);
}
case TOP -> {
LinkedHashMap<String, Integer> stats = statManager.getTopStats(request);
return statFormatter.formatTopStat(request, stats);
return statFormatter.formatTopStat(request, stats, true);
}
}
}
throw new IllegalArgumentException("This is not a valid stat-request!");
}
@Override
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull OfflinePlayer player) {
return null;
}
@Override
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull Material material, @NotNull OfflinePlayer player) {
return null;
}
@Override
public TextComponent getPlayerStat(@NotNull Statistic statistic, @NotNull EntityType entity, @NotNull OfflinePlayer player) {
return null;
}
@Override
public TextComponent getServerStat(@NotNull Statistic statistic) {
return null;
}
@Override
public TextComponent getServerStat(@NotNull Statistic statistic, @NotNull Material material) {
return null;
}
@Override
public TextComponent getServerStat(@NotNull Statistic statistic, @NotNull EntityType entity) {
return null;
}
@Override
public TextComponent getTopStats(@NotNull Statistic statistic) {
return null;
}
@Override
public TextComponent getTopStats(@NotNull Statistic statistic, @NotNull Material material) {
return null;
}
@Override
public TextComponent getTopStats(@NotNull Statistic statistic, @NotNull EntityType entity) {
return null;
}
@Override
public String statResultComponentToString(TextComponent component) {
return statFormatter.toString(component);
return statFormatter.statResultToString(component);
}
}

View File

@ -1,22 +0,0 @@
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.command.CommandSender;
import org.jetbrains.annotations.Nullable;
/** 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
data that you want, and to format this data into a fancy Component or String, so you can output it somewhere.*/
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 StatRequest could not be created.
@param args an Array of args corresponding to a Statistic, a potential Sub-Statistic, and a Target
(exactly as they are typed in Minecraft chat when using PlayerStatsAPI' /stat command -
for example "/stat kill_entity bee top")
@param sender the CommandSender that requested this specific statistic*/
StatRequest generateRequest(CommandSender sender, String[] args);
StatRequest generateRequest(CommandSender sender, String statName, @Nullable String subStatName, Target selection, @Nullable String PlayerName);
}

View File

@ -0,0 +1,37 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
public interface SimpleRequest {
void setStatistic(Statistic statistic);
Statistic getStatistic();
void setSubStatEntry(String subStatEntry);
String getSubStatEntry();
void setPlayerName(String playerName);
String getPlayerName();
void setSelection(Target selection);
Target getSelection();
void setEntity(EntityType entity);
EntityType getEntity();
void setBlock(Material material);
Material getBlock();
void setItem(Material item);
Material getItem();
}

View File

@ -2,8 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import net.kyori.adventure.text.TextComponent;
import static org.jetbrains.annotations.ApiStatus.Internal;
import net.kyori.adventure.text.minimessage.MiniMessage;
import java.util.LinkedHashMap;
@ -11,19 +10,13 @@ import java.util.LinkedHashMap;
This is meant for an outgoing API - for internal use, more output functionality may exist. */
public interface StatFormatter {
default String toString(TextComponent component) {
return component.content();
default String statResultToString(TextComponent statResult) {
return MiniMessage.miniMessage().serialize(statResult);
}
/** 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. */
@Internal
boolean saveOutputForSharing();
TextComponent formatPlayerStat(StatRequest request, int playerStat, boolean isAPIRequest);
TextComponent formatPlayerStat(StatRequest request, int playerStat);
TextComponent formatServerStat(StatRequest request, long serverStat, boolean isAPIRequest);
TextComponent formatServerStat(StatRequest request, long serverStat);
TextComponent formatTopStat(StatRequest request, LinkedHashMap<String, Integer> topStats);
TextComponent formatTopStat(StatRequest request, LinkedHashMap<String, Integer> topStats, boolean isAPIRequest);
}

View File

@ -1,25 +1,30 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
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.statistic.RequestManager;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class StatCommand implements CommandExecutor {
private static ThreadManager threadManager;
private static OutputManager outputManager;
private final StatManager statManager;
private final RequestManager requestManager;
public StatCommand(OutputManager m, ThreadManager t, StatManager s) {
public StatCommand(OutputManager m, ThreadManager t, RequestManager r) {
threadManager = t;
outputManager = m;
statManager = s;
requestManager = r;
}
@Override
@ -32,8 +37,8 @@ public class StatCommand implements CommandExecutor {
outputManager.sendExamples(sender);
}
else {
StatRequest request = statManager.generateRequest(sender, args);
if (statManager.requestIsValid(request)) {
StatRequest request = requestManager.generateRequest(sender, args);
if (requestManager.requestIsValid(request)) {
threadManager.startStatThread(request);
} else {
return false;

View File

@ -1,5 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.models;
import com.gmail.artemis.the.gr8.playerstats.api.SimpleRequest;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import org.bukkit.Material;
import org.bukkit.Statistic;
@ -12,9 +13,9 @@ import org.jetbrains.annotations.NotNull;
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 {
public final class StatRequest implements SimpleRequest {
private final CommandSender sender;
private CommandSender sender;
private Statistic statistic;
private String playerName;
private Target selection;
@ -25,13 +26,19 @@ public final class StatRequest {
private Material item;
private boolean playerFlag;
//make a StatRequest for a given CommandSender with some default values
public StatRequest(@NotNull CommandSender s) {
sender = s;
//make a SimpleRequest for a given CommandSender with some default values
public StatRequest(CommandSender s) {
if (s != null) {
setCommandSender(s);
}
selection = Target.TOP;
playerFlag = false;
}
public void setCommandSender(@NotNull CommandSender sender) {
this.sender = sender;
}
public @NotNull CommandSender getCommandSender() {
return sender;
}
@ -74,7 +81,7 @@ public final class StatRequest {
/** 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". */
public boolean playerFlag() {
public boolean getPlayerFlag() {
return playerFlag;
}

View File

@ -24,7 +24,6 @@ import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Function;
import static org.jetbrains.annotations.ApiStatus.Internal;
import static com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage.*;
/** This class manages all PlayerStats output. It is the only place where messages are sent.
@ -51,14 +50,8 @@ public final class OutputManager implements StatFormatter {
getMessageWriters(config);
}
@Internal
@Override
public boolean saveOutputForSharing() {
return true;
}
@Override
public TextComponent formatPlayerStat(@NotNull StatRequest request, int playerStat) {
public TextComponent formatPlayerStat(@NotNull StatRequest request, int playerStat, boolean isAPIRequest) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> playerStatFunction =
getWriter(sender).formattedPlayerStatFunction(playerStat, request);
@ -67,7 +60,7 @@ public final class OutputManager implements StatFormatter {
}
@Override
public TextComponent formatServerStat(@NotNull StatRequest request, long serverStat) {
public TextComponent formatServerStat(@NotNull StatRequest request, long serverStat, boolean isAPIRequest) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> serverStatFunction =
getWriter(sender).formattedServerStatFunction(serverStat, request);
@ -76,7 +69,7 @@ public final class OutputManager implements StatFormatter {
}
@Override
public TextComponent formatTopStat(@NotNull StatRequest request, LinkedHashMap<String, Integer> topStats) {
public TextComponent formatTopStat(@NotNull StatRequest request, @NotNull LinkedHashMap<String, Integer> topStats, boolean isAPIRequest) {
CommandSender sender = request.getCommandSender();
BiFunction<UUID, CommandSender, TextComponent> topStatFunction =
getWriter(sender).formattedTopStatFunction(topStats, request);
@ -84,24 +77,24 @@ public final class OutputManager implements StatFormatter {
return processBuildFunction(sender, topStatFunction);
}
public void sendFeedbackMsg(CommandSender sender, StandardMessage message) {
public void sendFeedbackMsg(@NotNull CommandSender sender, StandardMessage message) {
if (message != null) {
adventure.sender(sender).sendMessage(standardMessages.get(message)
.apply(getWriter(sender)));
}
}
public void sendFeedbackMsgWaitAMoment(CommandSender sender, boolean longWait) {
public void sendFeedbackMsgWaitAMoment(@NotNull CommandSender sender, boolean longWait) {
adventure.sender(sender).sendMessage(getWriter(sender)
.waitAMoment(longWait));
}
public void sendFeedbackMsgMissingSubStat(CommandSender sender, Statistic.Type statType) {
public void sendFeedbackMsgMissingSubStat(@NotNull CommandSender sender, Statistic.Type statType) {
adventure.sender(sender).sendMessage(getWriter(sender)
.missingSubStatName(statType));
}
public void sendFeedbackMsgWrongSubStat(CommandSender sender, Statistic.Type statType, String subStatName) {
public void sendFeedbackMsgWrongSubStat(@NotNull CommandSender sender, Statistic.Type statType, @Nullable String subStatName) {
if (subStatName == null) {
sendFeedbackMsgMissingSubStat(sender, statType);
} else {
@ -110,12 +103,12 @@ public final class OutputManager implements StatFormatter {
}
}
public void sendExamples(CommandSender sender) {
public void sendExamples(@NotNull CommandSender sender) {
adventure.sender(sender).sendMessage(getWriter(sender)
.usageExamples());
}
public void sendHelp(CommandSender sender) {
public void sendHelp(@NotNull CommandSender sender) {
adventure.sender(sender).sendMessage(getWriter(sender)
.helpMsg(sender instanceof ConsoleCommandSender));
}
@ -124,13 +117,12 @@ public final class OutputManager implements StatFormatter {
adventure.players().sendMessage(component);
}
public void sendToCommandSender(CommandSender sender, TextComponent component) {
public void sendToCommandSender(@NotNull CommandSender sender, @NotNull TextComponent component) {
adventure.sender(sender).sendMessage(component);
}
private TextComponent processBuildFunction(@Nullable CommandSender sender, BiFunction<UUID, CommandSender, TextComponent> buildFunction) {
boolean saveOutput = saveOutputForSharing() &&
sender != null &&
private TextComponent processBuildFunction(@Nullable CommandSender sender, @NotNull BiFunction<UUID, CommandSender, TextComponent> buildFunction) {
boolean saveOutput = sender != null &&
ShareManager.isEnabled() &&
shareManager.senderHasPermission(sender);
@ -144,6 +136,7 @@ public final class OutputManager implements StatFormatter {
}
}
/** If sender == null, this will return the regular writer*/
private MessageBuilder getWriter(CommandSender sender) {
return sender instanceof ConsoleCommandSender ? consoleWriter : writer;
}

View File

@ -0,0 +1,165 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
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.models.StatRequest;
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.OfflinePlayerHandler;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Statistic;
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 class RequestManager {
private final OfflinePlayerHandler offlinePlayerHandler;
private static OutputManager outputManager;
public RequestManager(OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) {
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 SimpleRequest 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
@throws IllegalArgumentException if the args do not result in a valid statistic look-up*/
public StatRequest generateRequest(CommandSender sender, String[] args) {
StatRequest request = new StatRequest(sender);
for (String arg : args) {
//check for statName
if (EnumHandler.isStatistic(arg) && request.getStatistic() == null) {
request.setStatistic(EnumHandler.getStatEnum(arg));
}
//check for subStatEntry and playerFlag
else if (EnumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player") && !request.getPlayerFlag()) {
request.setPlayerFlag(true);
}
else {
if (request.getSubStatEntry() == null) request.setSubStatEntry(arg);
}
}
//check for selection
else if (arg.equalsIgnoreCase("top")) {
request.setSelection(Target.TOP);
}
else if (arg.equalsIgnoreCase("server")) {
request.setSelection(Target.SERVER);
}
else if (arg.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
request.setPlayerName(sender.getName());
request.setSelection(Target.PLAYER);
}
else if (sender instanceof ConsoleCommandSender) {
request.setSelection(Target.SERVER);
}
}
else if (offlinePlayerHandler.isRelevantPlayer(arg) && request.getPlayerName() == null) {
request.setPlayerName(arg);
request.setSelection(Target.PLAYER);
}
}
patchRequest(request);
return request;
}
public StatRequest generateRequest(@NotNull Target selection, @NotNull Statistic statistic, Material material, EntityType entity, OfflinePlayer player) {
return null;
}
/** This method validates the {@link StatRequest} and returns a feedback message if the Request is invalid.
It checks the following:
<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 SimpleRequest is valid, and false + an explanation message otherwise. */
public boolean requestIsValid(StatRequest request) {
if (request.getStatistic() == null) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.MISSING_STAT_NAME);
return false;
}
Statistic.Type type = request.getStatistic().getType();
if (request.getSubStatEntry() == null && type != Statistic.Type.UNTYPED) {
outputManager.sendFeedbackMsgMissingSubStat(request.getCommandSender(), type);
return false;
}
else if (!hasMatchingSubStat(request)) {
outputManager.sendFeedbackMsgWrongSubStat(request.getCommandSender(), type, request.getSubStatEntry());
return false;
}
else if (request.getSelection() == Target.PLAYER && request.getPlayerName() == null) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.MISSING_PLAYER_NAME);
return false;
}
else {
return true;
}
}
/** Adjust the SimpleRequest object if needed: unpack the playerFlag into a subStatEntry,
try to retrieve the corresponding Enum Constant for any relevant block/entity/item,
and remove any unnecessary subStatEntries.*/
private void patchRequest(StatRequest request) {
if (request.getStatistic() != null) {
Statistic.Type type = request.getStatistic().getType();
if (request.getPlayerFlag()) { //unpack the playerFlag
if (type == Statistic.Type.ENTITY && request.getSubStatEntry() == null) {
request.setSubStatEntry("player");
}
else {
request.setSelection(Target.PLAYER);
}
}
String subStatEntry = request.getSubStatEntry();
switch (type) { //attempt to convert relevant subStatEntries into their corresponding Enum Constant
case BLOCK -> {
Material block = EnumHandler.getBlockEnum(subStatEntry);
if (block != null) request.setBlock(block);
}
case ENTITY -> {
EntityType entity = EnumHandler.getEntityEnum(subStatEntry);
if (entity != null) request.setEntity(entity);
}
case ITEM -> {
Material item = EnumHandler.getItemEnum(subStatEntry);
if (item != null) request.setItem(item);
}
case UNTYPED -> { //remove unnecessary subStatEntries
if (subStatEntry != null) request.setSubStatEntry(null);
}
}
}
}
private boolean hasMatchingSubStat(StatRequest request) {
Statistic.Type type = request.getStatistic().getType();
switch (type) {
case BLOCK -> {
return request.getBlock() != null;
}
case ENTITY -> {
return request.getEntity() != null;
}
case ITEM -> {
return request.getItem() != null;
}
default -> {
return true;
}
}
}
}

View File

@ -1,23 +1,13 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
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.Target;
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.utils.EnumHandler;
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 org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Statistic;
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;
import java.util.*;
@ -28,12 +18,10 @@ import java.util.stream.Collectors;
public final class StatManager implements StatGetter {
private final OfflinePlayerHandler offlinePlayerHandler;
private static OutputManager outputManager;
private static int topListMaxSize;
public StatManager(OutputManager outputManager, OfflinePlayerHandler offlinePlayerHandler, int topListMaxSize) {
public StatManager(OfflinePlayerHandler offlinePlayerHandler, int topListMaxSize) {
this.offlinePlayerHandler = offlinePlayerHandler;
StatManager.outputManager = outputManager;
StatManager.topListMaxSize = topListMaxSize;
}
@ -41,132 +29,6 @@ public final class StatManager implements StatGetter {
StatManager.topListMaxSize = topListMaxSize;
}
public StatRequest generateRequest(CommandSender sender, String[] args) {
StatRequest request = new StatRequest(sender);
for (String arg : args) {
//check for statName
if (EnumHandler.isStatistic(arg) && request.getStatistic() == null) {
request.setStatistic(EnumHandler.getStatEnum(arg));
}
//check for subStatEntry and playerFlag
else if (EnumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player") && !request.playerFlag()) {
request.setPlayerFlag(true);
}
else {
if (request.getSubStatEntry() == null) request.setSubStatEntry(arg);
}
}
//check for selection
else if (arg.equalsIgnoreCase("top")) {
request.setSelection(Target.TOP);
}
else if (arg.equalsIgnoreCase("server")) {
request.setSelection(Target.SERVER);
}
else if (arg.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
request.setPlayerName(sender.getName());
request.setSelection(Target.PLAYER);
}
else if (sender instanceof ConsoleCommandSender) {
request.setSelection(Target.SERVER);
}
}
else if (offlinePlayerHandler.isRelevantPlayer(arg) && request.getPlayerName() == null) {
request.setPlayerName(arg);
request.setSelection(Target.PLAYER);
}
}
patchRequest(request);
return request;
}
/** Adjust the StatRequest object if needed: unpack the playerFlag into a subStatEntry,
try to retrieve the corresponding Enum Constant for any relevant block/entity/item,
and remove any unnecessary subStatEntries.*/
private void patchRequest(StatRequest request) {
if (request.getStatistic() != null) {
Statistic.Type type = request.getStatistic().getType();
if (request.playerFlag()) { //unpack the playerFlag
if (type == Statistic.Type.ENTITY && request.getSubStatEntry() == null) {
request.setSubStatEntry("player");
}
else {
request.setSelection(Target.PLAYER);
}
}
String subStatEntry = request.getSubStatEntry();
switch (type) { //attempt to convert relevant subStatEntries into their corresponding Enum Constant
case BLOCK -> {
Material block = EnumHandler.getBlockEnum(subStatEntry);
if (block != null) request.setBlock(block);
}
case ENTITY -> {
EntityType entity = EnumHandler.getEntityEnum(subStatEntry);
if (entity != null) request.setEntity(entity);
}
case ITEM -> {
Material item = EnumHandler.getItemEnum(subStatEntry);
if (item != null) request.setItem(item);
}
case UNTYPED -> { //remove unnecessary subStatEntries
if (subStatEntry != null) request.setSubStatEntry(null);
}
}
}
}
/** This method validates the {@link StatRequest} and returns feedback to the player if it returns false.
It checks the following:
<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 StatRequest is valid, and false + an explanation message otherwise. */
public boolean requestIsValid(StatRequest request) {
if (request.getStatistic() == null) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.MISSING_STAT_NAME);
return false;
}
Statistic.Type type = request.getStatistic().getType();
if (request.getSubStatEntry() == null && type != Statistic.Type.UNTYPED) {
outputManager.sendFeedbackMsgMissingSubStat(request.getCommandSender(), type);
return false;
}
else if (!hasMatchingSubStat(request)) {
outputManager.sendFeedbackMsgWrongSubStat(request.getCommandSender(), type, request.getSubStatEntry());
return false;
}
else if (request.getSelection() == Target.PLAYER && request.getPlayerName() == null) {
outputManager.sendFeedbackMsg(request.getCommandSender(), StandardMessage.MISSING_PLAYER_NAME);
return false;
}
else {
return true;
}
}
private boolean hasMatchingSubStat(StatRequest request) {
Statistic.Type type = request.getStatistic().getType();
switch (type) {
case BLOCK -> {
return request.getBlock() != null;
}
case ENTITY -> {
return request.getEntity() != null;
}
case ITEM -> {
return request.getItem() != null;
}
default -> {
return true;
}
}
}
/** Gets the statistic data for an individual player. If somehow the player
cannot be found, this returns 0.*/
public int getPlayerStat(StatRequest request) {

View File

@ -1,4 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
public class StatRequestGenerator {
}

View File

@ -6,9 +6,7 @@ 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.reload.ReloadThread;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
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 net.kyori.adventure.text.TextComponent;
import org.jetbrains.annotations.Nullable;
@ -61,9 +59,9 @@ public class StatThread extends Thread {
Target selection = request.getSelection();
try {
TextComponent statResult = switch (selection) {
case PLAYER -> outputManager.formatPlayerStat(request, statManager.getPlayerStat(request));
case TOP -> outputManager.formatTopStat(request, statManager.getTopStats(request));
case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request));
case PLAYER -> outputManager.formatPlayerStat(request, statManager.getPlayerStat(request), false);
case TOP -> outputManager.formatTopStat(request, statManager.getTopStats(request), false);
case SERVER -> outputManager.formatServerStat(request, statManager.getServerStat(request), false);
};
outputManager.sendToCommandSender(request.getCommandSender(), statResult);
}