255 lines
9.4 KiB
Java
255 lines
9.4 KiB
Java
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.*;
|
|
import com.artemis.the.gr8.playerstats.utils.EnumHandler;
|
|
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
|
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 static ConfigHandler config;
|
|
private final OfflinePlayerHandler offlinePlayerHandler;
|
|
private final EnumHandler enumHandler;
|
|
|
|
public StatCommand(OutputManager m, ThreadManager t, ConfigHandler c, OfflinePlayerHandler o, EnumHandler e) {
|
|
threadManager = t;
|
|
outputManager = m;
|
|
config = c;
|
|
offlinePlayerHandler = o;
|
|
enumHandler = e;
|
|
}
|
|
|
|
@Override
|
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
|
if (args.length == 0 || args[0].equalsIgnoreCase("help")) { //in case of less than 1 argument or "help", display the help message
|
|
outputManager.sendHelp(sender);
|
|
}
|
|
else if (args[0].equalsIgnoreCase("examples") ||
|
|
args[0].equalsIgnoreCase("example")) { //in case of "statistic examples", show examples
|
|
outputManager.sendExamples(sender);
|
|
}
|
|
else {
|
|
ArgProcessor processor = new ArgProcessor(sender, args);
|
|
if (processor.request != null) {
|
|
threadManager.startStatThread(processor.request);
|
|
} else {
|
|
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 subStatName;
|
|
private Target target;
|
|
private String playerName;
|
|
private StatRequest<?> request;
|
|
|
|
private ArgProcessor(CommandSender sender, String[] args) {
|
|
argsToProcess = args;
|
|
|
|
extractStatistic();
|
|
extractSubStatistic();
|
|
extractTarget(sender);
|
|
combineProcessedArgsIntoRequest();
|
|
}
|
|
|
|
private void combineProcessedArgsIntoRequest() {
|
|
if (statistic == null ||
|
|
target == Target.PLAYER && playerName == null) {
|
|
return;
|
|
}
|
|
|
|
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()) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void extractStatistic() {
|
|
String statName = null;
|
|
for (String arg : argsToProcess) {
|
|
if (enumHandler.isStatistic(arg)) {
|
|
statName = arg;
|
|
break;
|
|
}
|
|
}
|
|
if (statName != null) {
|
|
statistic = EnumHandler.getStatEnum(statName);
|
|
argsToProcess = removeArg(statName);
|
|
}
|
|
}
|
|
|
|
private void extractSubStatistic() {
|
|
if (statistic == null ||
|
|
statistic.getType() == Statistic.Type.UNTYPED ||
|
|
argsToProcess.length == 0) {
|
|
return;
|
|
}
|
|
|
|
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)
|
|
private @Nullable String tryToFindPlayerName(@NotNull String[] args) {
|
|
for (String arg : args) {
|
|
if (offlinePlayerHandler.isRelevantPlayer(arg)) {
|
|
return arg;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private String[] removeArg(String argToRemove) {
|
|
ArrayList<String> currentArgs = new ArrayList<>(Arrays.asList(argsToProcess));
|
|
currentArgs.remove(argToRemove);
|
|
return currentArgs.toArray(String[]::new);
|
|
}
|
|
}
|
|
} |