mirror of
https://github.com/itHotL/PlayerStats.git
synced 2025-02-14 01:21:28 +01:00
Moved all arg-analyzing to StatCommand and got rid of InternalStatRequest (#114)
This commit is contained in:
parent
b1c015e156
commit
03efe136b0
@ -56,7 +56,7 @@ public final class Main extends JavaPlugin {
|
||||
//register all commands and the tabCompleter
|
||||
PluginCommand statcmd = this.getCommand("statistic");
|
||||
if (statcmd != null) {
|
||||
statcmd.setExecutor(new StatCommand(outputManager, threadManager));
|
||||
statcmd.setExecutor(new StatCommand(outputManager, threadManager, config, offlinePlayerHandler, enumHandler));
|
||||
statcmd.setTabCompleter(new TabCompleter(enumHandler, offlinePlayerHandler));
|
||||
}
|
||||
PluginCommand reloadcmd = this.getCommand("statisticreload");
|
||||
@ -80,17 +80,6 @@ public final class Main extends JavaPlugin {
|
||||
this.getLogger().info("Disabled PlayerStats!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Adventure's BukkitAudiences object
|
||||
* @throws IllegalStateException if PlayerStats is not enabled
|
||||
*/
|
||||
public static @NotNull BukkitAudiences getAdventure() throws IllegalStateException {
|
||||
if (adventure == null) {
|
||||
throw new IllegalStateException("Tried to access Adventure without PlayerStats being enabled!");
|
||||
}
|
||||
return adventure;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the JavaPlugin instance associated with PlayerStats
|
||||
@ -117,19 +106,9 @@ public final class Main extends JavaPlugin {
|
||||
return requestProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PlayerStats' ConfigHandler
|
||||
*/
|
||||
public static @NotNull ConfigHandler getConfigHandler() {
|
||||
if (config == null) {
|
||||
config = new ConfigHandler();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
public static @NotNull OfflinePlayerHandler getOfflinePlayerHandler() {
|
||||
public static @NotNull OfflinePlayerHandler getOfflinePlayerHandler() throws IllegalStateException {
|
||||
if (offlinePlayerHandler == null) {
|
||||
offlinePlayerHandler = new OfflinePlayerHandler(getConfigHandler());
|
||||
throw new IllegalStateException("PlayerStats does not seem to be loaded!");
|
||||
}
|
||||
return offlinePlayerHandler;
|
||||
}
|
||||
@ -141,17 +120,6 @@ public final class Main extends JavaPlugin {
|
||||
return languageKeyHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EnumHandler. If there is no EnumHandler, one will be created.
|
||||
* @return PlayerStat's EnumHandler
|
||||
*/
|
||||
public static @NotNull EnumHandler getEnumHandler() {
|
||||
if (enumHandler == null) {
|
||||
enumHandler = new EnumHandler();
|
||||
}
|
||||
return enumHandler;
|
||||
}
|
||||
|
||||
private void initializeMainClasses() {
|
||||
pluginInstance = this;
|
||||
adventure = BukkitAudiences.create(this);
|
||||
|
@ -1,38 +1,47 @@
|
||||
package com.artemis.the.gr8.playerstats.commands;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.ThreadManager;
|
||||
import com.artemis.the.gr8.playerstats.api.RequestGenerator;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.enums.StandardMessage;
|
||||
import com.artemis.the.gr8.playerstats.enums.Target;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.statistic.InternalStatRequest;
|
||||
import com.artemis.the.gr8.playerstats.statistic.PlayerStatRequest;
|
||||
import com.artemis.the.gr8.playerstats.statistic.StatRequest;
|
||||
import com.artemis.the.gr8.playerstats.statistic.*;
|
||||
import com.artemis.the.gr8.playerstats.utils.EnumHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class StatCommand implements CommandExecutor {
|
||||
|
||||
private static final Pattern pattern = Pattern.compile("top|server|me|player");
|
||||
|
||||
private static ThreadManager threadManager;
|
||||
private static OutputManager outputManager;
|
||||
private OfflinePlayerHandler offlinePlayerHandler;
|
||||
private EnumHandler enumHandler;
|
||||
private static ConfigHandler config;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final EnumHandler enumHandler;
|
||||
|
||||
public StatCommand(OutputManager m, ThreadManager t) {
|
||||
public StatCommand(OutputManager m, ThreadManager t, ConfigHandler c, OfflinePlayerHandler o, EnumHandler e) {
|
||||
threadManager = t;
|
||||
outputManager = m;
|
||||
config = c;
|
||||
offlinePlayerHandler = o;
|
||||
enumHandler = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -45,44 +54,138 @@ public class StatCommand implements CommandExecutor {
|
||||
outputManager.sendExamples(sender);
|
||||
}
|
||||
else {
|
||||
StatRequest<TextComponent> request = new InternalStatRequest(sender, args);
|
||||
if (request.isValid()) {
|
||||
threadManager.startStatThread(request);
|
||||
ArgProcessor processor = new ArgProcessor(sender, args);
|
||||
if (processor.request != null) {
|
||||
threadManager.startStatThread(processor.request);
|
||||
} else {
|
||||
sendFeedback(sender, request);
|
||||
sendFeedback(sender, processor);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the provided args and sends an appropriate
|
||||
* feedback message to the CommandSender that called the
|
||||
* stat command. 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 sender the CommandSender to send feedback to
|
||||
* @param processor the ArgProcessor object that holds
|
||||
* the analyzed args
|
||||
*/
|
||||
private void sendFeedback(CommandSender sender, @NotNull ArgProcessor processor) {
|
||||
if (processor.statistic == null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_STAT_NAME);
|
||||
}
|
||||
else if (processor.target == Target.PLAYER && processor.playerName == null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_PLAYER_NAME);
|
||||
}
|
||||
else {
|
||||
Statistic.Type type = processor.statistic.getType();
|
||||
if (type != Statistic.Type.UNTYPED && processor.subStatName == null) {
|
||||
outputManager.sendFeedbackMsgMissingSubStat(sender, type);
|
||||
} else {
|
||||
outputManager.sendFeedbackMsgWrongSubStat(sender, type, processor.subStatName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ArgProcessor {
|
||||
|
||||
private String[] argsToProcess;
|
||||
private Statistic statistic;
|
||||
private String subStatistic;
|
||||
private String subStatName;
|
||||
private Target target;
|
||||
private String playerName;
|
||||
private StatRequest<?> request;
|
||||
|
||||
private ArgProcessor(CommandSender sender, String[] args) {
|
||||
argsToProcess = args;
|
||||
process(sender);
|
||||
|
||||
extractStatistic();
|
||||
extractSubStatistic();
|
||||
extractTarget(sender);
|
||||
combineProcessedArgsIntoRequest();
|
||||
}
|
||||
|
||||
private StatRequest<?> process(CommandSender sender) {
|
||||
Pattern pattern = Pattern.compile("top|server|me|player");
|
||||
extractStatistic();
|
||||
private void combineProcessedArgsIntoRequest() {
|
||||
if (statistic == null ||
|
||||
target == Target.PLAYER && playerName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = tryToFindPlayerName(argsToProcess);
|
||||
RequestGenerator<?> requestGenerator =
|
||||
switch (target) {
|
||||
case PLAYER -> new PlayerStatRequest(playerName);
|
||||
case SERVER -> new ServerStatRequest();
|
||||
case TOP -> new TopStatRequest(config.getTopListMaxSize());
|
||||
};
|
||||
|
||||
switch (statistic.getType()) {
|
||||
case UNTYPED -> request = requestGenerator.untyped(statistic);
|
||||
case BLOCK -> {
|
||||
Material block = EnumHandler.getBlockEnum(subStatName);
|
||||
if (block != null) {
|
||||
request = requestGenerator.blockOrItemType(statistic, block);
|
||||
}
|
||||
}
|
||||
case ITEM -> {
|
||||
Material item = EnumHandler.getItemEnum(subStatName);
|
||||
if (item != null) {
|
||||
request = requestGenerator.blockOrItemType(statistic, item);
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
EntityType entity = EnumHandler.getEntityEnum(subStatName);
|
||||
if (entity != null) {
|
||||
request = requestGenerator.entityType(statistic, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTarget(CommandSender sender) {
|
||||
String targetArg = null;
|
||||
for (String arg : argsToProcess) {
|
||||
Matcher matcher = pattern.matcher(arg);
|
||||
if (matcher.find()) {
|
||||
switch (matcher.group()) {
|
||||
case "player" -> {
|
||||
if (playerName != null || containsPlayerTwice(argsToProcess)) {
|
||||
new PlayerStatRequest(playerName);
|
||||
targetArg = matcher.group();
|
||||
switch (targetArg) {
|
||||
case "me" -> {
|
||||
if (sender instanceof Player) {
|
||||
target = Target.PLAYER;
|
||||
playerName = sender.getName();
|
||||
} else {
|
||||
target = Target.SERVER;
|
||||
}
|
||||
}
|
||||
case "player" -> {
|
||||
target = Target.PLAYER;
|
||||
playerName = tryToFindPlayerName(argsToProcess);
|
||||
}
|
||||
case "server" -> target = Target.SERVER;
|
||||
case "top" -> target = Target.TOP;
|
||||
}
|
||||
argsToProcess = removeArg(targetArg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetArg == null) {
|
||||
String playerName = tryToFindPlayerName(argsToProcess);
|
||||
if (playerName != null) {
|
||||
target = Target.PLAYER;
|
||||
this.playerName = playerName;
|
||||
} else {
|
||||
target = Target.TOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,7 +200,7 @@ public class StatCommand implements CommandExecutor {
|
||||
}
|
||||
if (statName != null) {
|
||||
statistic = EnumHandler.getStatEnum(statName);
|
||||
argsToProcess = removeArg(argsToProcess, statName);
|
||||
argsToProcess = removeArg(statName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,9 +211,29 @@ public class StatCommand implements CommandExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String arg : argsToProcess) {
|
||||
|
||||
String subStatName = null;
|
||||
List<String> subStats = Arrays.stream(argsToProcess)
|
||||
.filter(enumHandler::isSubStatEntry)
|
||||
.toList();
|
||||
if (subStats.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
else if (subStats.size() == 1) {
|
||||
subStatName = subStats.get(0);
|
||||
}
|
||||
else {
|
||||
for (String arg : subStats) {
|
||||
if (!arg.equalsIgnoreCase("player")) {
|
||||
subStatName = arg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (subStatName == null) {
|
||||
subStatName = "player";
|
||||
}
|
||||
}
|
||||
this.subStatName = subStatName;
|
||||
argsToProcess = removeArg(subStatName);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@ -123,50 +246,10 @@ public class StatCommand implements CommandExecutor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean containsPlayerTwice(String[] args) {
|
||||
return Arrays.stream(args)
|
||||
.filter(arg -> arg.equalsIgnoreCase("player"))
|
||||
.toList()
|
||||
.size() >= 2;
|
||||
}
|
||||
|
||||
private String[] removeArg(@NotNull String[] args, String argToRemove) {
|
||||
ArrayList<String> currentArgs = new ArrayList<>(Arrays.asList(args));
|
||||
private String[] removeArg(String argToRemove) {
|
||||
ArrayList<String> currentArgs = new ArrayList<>(Arrays.asList(argsToProcess));
|
||||
currentArgs.remove(argToRemove);
|
||||
return currentArgs.toArray(String[]::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If a given {@link StatRequest} object does not result in a valid
|
||||
* statistic look-up, this will send a feedback message to the CommandSender
|
||||
* that made the request. 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 sender the CommandSender to send feedback to
|
||||
* @param request the StatRequest to give feedback on
|
||||
*/
|
||||
private void sendFeedback(CommandSender sender, StatRequest<?> request) {
|
||||
StatRequest.Settings settings = request.getSettings();
|
||||
|
||||
if (settings.getStatistic() == null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_STAT_NAME);
|
||||
}
|
||||
else if (settings.getTarget() == Target.PLAYER && settings.getPlayerName() == null) {
|
||||
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_PLAYER_NAME);
|
||||
}
|
||||
else {
|
||||
Statistic.Type type = settings.getStatistic().getType();
|
||||
if (type != Statistic.Type.UNTYPED && settings.getSubStatEntryName() == null) {
|
||||
outputManager.sendFeedbackMsgMissingSubStat(sender, type);
|
||||
} else {
|
||||
outputManager.sendFeedbackMsgWrongSubStat(sender, type, settings.getSubStatEntryName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
package com.artemis.the.gr8.playerstats.statistic;
|
||||
|
||||
import com.artemis.the.gr8.playerstats.Main;
|
||||
import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.EnumHandler;
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class InternalStatRequest extends StatRequest<TextComponent> {
|
||||
|
||||
private final ConfigHandler config;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
private final EnumHandler enumHandler;
|
||||
private final Pattern targetPattern;
|
||||
|
||||
public InternalStatRequest(CommandSender sender, String[] args) {
|
||||
super(sender);
|
||||
config = Main.getConfigHandler();
|
||||
offlinePlayerHandler = Main.getOfflinePlayerHandler();
|
||||
enumHandler = Main.getEnumHandler();
|
||||
targetPattern = Pattern.compile("top|server|me|player");
|
||||
|
||||
processArgs(sender, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull StatResult<TextComponent> execute() {
|
||||
return Main.getRequestProcessor().getInternalResult(super.getSettings());
|
||||
}
|
||||
|
||||
private void processArgs(CommandSender sender, String[] args) {
|
||||
MyLogger.logWarning("processArgs: " + Arrays.toString(args));
|
||||
|
||||
String[] argsMinusTarget = extractAndStoreTarget(sender, args);
|
||||
MyLogger.logWarning("processArgs minus target: " + Arrays.toString(argsMinusTarget));
|
||||
|
||||
findStatAndSubStat(argsMinusTarget);
|
||||
}
|
||||
|
||||
private String[] extractAndStoreTarget(CommandSender sender, @NotNull String[] leftoverArgs) {
|
||||
String playerName = tryToFindPlayerName(leftoverArgs);
|
||||
|
||||
for (String arg : leftoverArgs) {
|
||||
Matcher targetMatcher = targetPattern.matcher(arg);
|
||||
if (targetMatcher.find()) {
|
||||
switch (targetMatcher.group()) {
|
||||
case "player" -> {
|
||||
if (playerName == null) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
super.getSettings().configureForPlayer(playerName);
|
||||
|
||||
String[] extractedPlayerName = removeArg(leftoverArgs, playerName);
|
||||
return removeArg(extractedPlayerName, arg);
|
||||
}
|
||||
}
|
||||
case "me" -> {
|
||||
if (sender instanceof Player) {
|
||||
super.getSettings().configureForPlayer(sender.getName());
|
||||
} else {
|
||||
super.getSettings().configureForServer();
|
||||
}
|
||||
}
|
||||
case "server" -> super.getSettings().configureForServer();
|
||||
case "top" -> super.getSettings().configureForTop(config.getTopListMaxSize());
|
||||
}
|
||||
return removeArg(leftoverArgs, arg);
|
||||
}
|
||||
}
|
||||
//if no target is found, but there is a playerName, assume target = Target.PLAYER
|
||||
if (playerName != null) {
|
||||
super.getSettings().configureForPlayer(playerName);
|
||||
return removeArg(leftoverArgs, playerName);
|
||||
}
|
||||
//otherwise, assume target = Target.TOP
|
||||
super.getSettings().configureForTop(config.getTopListMaxSize());
|
||||
return leftoverArgs;
|
||||
}
|
||||
|
||||
private void findStatAndSubStat(@NotNull String[] leftoverArgs) {
|
||||
MyLogger.logWarning("findStatAndSubStat: " + Arrays.toString(leftoverArgs));
|
||||
for (String arg : leftoverArgs) {
|
||||
if (enumHandler.isStatistic(arg)) {
|
||||
MyLogger.logWarning("statistic found: " + arg);
|
||||
Statistic stat = EnumHandler.getStatEnum(arg);
|
||||
String[] argsWithoutStat = removeArg(leftoverArgs, arg);
|
||||
findAndStoreSubStat(argsWithoutStat, stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findAndStoreSubStat(String[] leftoverArgs, Statistic statistic) {
|
||||
MyLogger.logWarning("findAndStoreSubStat: " + Arrays.toString(leftoverArgs));
|
||||
if (statistic == null) {
|
||||
return;
|
||||
}
|
||||
else if (leftoverArgs.length == 0) {
|
||||
super.getSettings().configureUntyped(statistic);
|
||||
return;
|
||||
}
|
||||
|
||||
for (String arg : leftoverArgs) {
|
||||
if (enumHandler.isSubStatEntry(arg)) {
|
||||
switch (statistic.getType()) {
|
||||
case UNTYPED -> super.getSettings().configureUntyped(statistic);
|
||||
case ITEM -> {
|
||||
Material item = EnumHandler.getItemEnum(arg);
|
||||
if (item != null) {
|
||||
super.getSettings().configureBlockOrItemType(statistic, item);
|
||||
}
|
||||
}
|
||||
case BLOCK -> {
|
||||
Material block = EnumHandler.getBlockEnum(arg);
|
||||
if (block != null) {
|
||||
super.getSettings().configureBlockOrItemType(statistic, block);
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
EntityType entityType = EnumHandler.getEntityEnum(arg);
|
||||
if (entityType != null) {
|
||||
super.getSettings().configureEntityType(statistic, entityType);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
private @Nullable String tryToFindPlayerName(@NotNull String[] args) {
|
||||
for (String arg : args) {
|
||||
if (offlinePlayerHandler.isRelevantPlayer(arg)) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] removeArg(@NotNull String[] args, String argToRemove) {
|
||||
ArrayList<String> currentArgs = new ArrayList<>(Arrays.asList(args));
|
||||
currentArgs.remove(argToRemove);
|
||||
return currentArgs.toArray(String[]::new);
|
||||
}
|
||||
}
|
@ -29,10 +29,8 @@ import net.kyori.adventure.text.TextComponent;
|
||||
* By default, the resulting message is a {@link 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,
|
||||
* 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 through the PlayerStatsImpl. Information
|
||||
* on how to get and use the BukkitAudiences object can be found on
|
||||
* and use that to send the desired Component. 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>.
|
||||
*
|
||||
* <p>You can also use the provided {@link #formattedString ()} method to get the
|
||||
|
Loading…
Reference in New Issue
Block a user