More API rework

This commit is contained in:
Artemis-the-gr8 2022-07-28 22:12:50 +02:00
parent c3bf1e60fc
commit 228f1f2d73
31 changed files with 443 additions and 498 deletions

View File

@ -9,7 +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.request.InternalStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
import com.gmail.artemis.the.gr8.playerstats.utils.EnumHandler;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
@ -25,7 +25,7 @@ public final class Main extends JavaPlugin {
private static BukkitAudiences adventure;
private static PlayerStats playerStatsAPI;
private static OutputManager outputManager;
private static RequestManager requestManager;
private static InternalStatFetcher internalStatFetcher;
private static ShareManager shareManager;
private static ThreadManager threadManager;
@ -46,7 +46,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, requestManager));
statcmd.setExecutor(new StatCommand(outputManager, threadManager, internalStatFetcher));
statcmd.setTabCompleter(new TabCompleter(enumHandler, offlinePlayerHandler));
}
PluginCommand reloadcmd = this.getCommand("statisticreload");
@ -90,9 +90,9 @@ public final class Main extends JavaPlugin {
shareManager = new ShareManager(config);
StatManager statManager = new StatManager(offlinePlayerHandler, config.getTopListMaxSize());
outputManager = new OutputManager(getAdventure(), config, shareManager);
requestManager = new RequestManager(enumHandler, offlinePlayerHandler, outputManager);
internalStatFetcher = new InternalStatFetcher(enumHandler, offlinePlayerHandler, outputManager);
threadManager = new ThreadManager(config, statManager, outputManager);
playerStatsAPI = new PlayerStatsAPI(requestManager, statManager, outputManager);
playerStatsAPI = new PlayerStatsAPI(internalStatFetcher, statManager, outputManager);
}
}

View File

@ -2,7 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.DebugLevel;
import com.gmail.artemis.the.gr8.playerstats.models.InternalStatResult;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.InternalStatResult;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.command.CommandSender;

View File

@ -2,7 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
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.statistic.StatManager;
@ -61,19 +61,19 @@ public final class ThreadManager {
}
}
public void startStatThread(StatRequest statRequest) {
public void startStatThread(StatRequestCore statRequestCore) {
statThreadID += 1;
String cmdSender = statRequest.getCommandSender().getName();
String cmdSender = statRequestCore.getCommandSender().getName();
if (config.limitStatRequests() && statThreads.containsKey(cmdSender)) {
Thread runningThread = statThreads.get(cmdSender);
if (runningThread.isAlive()) {
outputManager.sendFeedbackMsg(statRequest.getCommandSender(), StandardMessage.REQUEST_ALREADY_RUNNING);
outputManager.sendFeedbackMsg(statRequestCore.getCommandSender(), StandardMessage.REQUEST_ALREADY_RUNNING);
} else {
startNewStatThread(statRequest);
startNewStatThread(statRequestCore);
}
} else {
startNewStatThread(statRequest);
startNewStatThread(statRequestCore);
}
}
@ -89,9 +89,9 @@ public final class ThreadManager {
return lastRecordedCalcTime;
}
private void startNewStatThread(StatRequest statRequest) {
lastActiveStatThread = new StatThread(outputManager, statManager, statThreadID, statRequest, lastActiveReloadThread);
statThreads.put(statRequest.getCommandSender().getName(), lastActiveStatThread);
private void startNewStatThread(StatRequestCore statRequestCore) {
lastActiveStatThread = new StatThread(outputManager, statManager, statThreadID, statRequestCore, lastActiveReloadThread);
statThreads.put(statRequestCore.getCommandSender().getName(), lastActiveStatThread);
lastActiveStatThread.start();
}
}

View File

@ -1,15 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
public interface APIRequest {
StatRequest untyped(Statistic statistic);
StatRequest blockOrItemType(Statistic statistic, Material material);
StatRequest entityType(Statistic statistic, EntityType entityType);
}

View File

@ -1,10 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.api;
public abstract class PlayerRequest implements APIRequest {
protected final String playerName;
public PlayerRequest(String playerName) {
this.playerName = playerName;
}
}

View File

@ -1,48 +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.Bukkit;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
public class PlayerStatRequest extends PlayerRequest {
public PlayerStatRequest(String playerName) {
super(playerName);
}
@Override
public StatRequest untyped(Statistic statistic) {
StatRequest request = getBasePlayerRequest();
request.setStatistic(statistic);
return request;
}
@Override
public StatRequest blockOrItemType(@NotNull Statistic statistic, Material material) {
StatRequest request = getBasePlayerRequest(statistic);
request.setSubStatEntryName(material.toString());
if (statistic.getType() == Statistic.Type.BLOCK) {
request.setBlock(material);
} else {
request.setItem(material);
}
return request;
}
@Override
public StatRequest entityType(Statistic statistic, EntityType entityType) {
return null;
}
private StatRequest getBasePlayerRequest(@NotNull Statistic statistic) {
StatRequest request = new StatRequest(Bukkit.getConsoleSender(), true);
request.setStatistic(statistic);
request.setTarget(Target.PLAYER);
request.setPlayerName(super.playerName);
return request;
}
}

View File

@ -1,10 +1,9 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.models.StatResult;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.EntityType;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.PlayerStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.ServerStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.TopStatFetcher;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@ -26,9 +25,9 @@ public interface PlayerStats {
return Main.getPlayerStatsAPI();
}
PlayerRequest getPlayerStat(String playerName);
PlayerStatFetcher playerStat(String playerName);
StatResult<?> getServerStat(Statistic statistic, Material material, EntityType entity);
ServerStatFetcher serverStat();
StatResult<?> getTopStats(Statistic statistic, Material material, EntityType entity);
TopStatFetcher topStat(int topListSize);
}

View File

@ -1,79 +1,40 @@
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.*;
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.Statistic;
import org.bukkit.entity.EntityType;
import java.util.LinkedHashMap;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.InternalStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatManager;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.PlayerStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.ServerStatFetcher;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.TopStatFetcher;
import static org.jetbrains.annotations.ApiStatus.Internal;
/** The implementation of the API Interface */
public final class PlayerStatsAPI implements PlayerStats {
private static RequestGenerator requestGenerator;
private static InternalStatFetcher requestGenerator;
private static StatCalculator statCalculator;
private static StatFormatter statFormatter;
@Internal
public PlayerStatsAPI(RequestManager request, StatManager stat, StatFormatter format) {
public PlayerStatsAPI(InternalStatFetcher request, StatManager stat, StatFormatter format) {
PlayerStatsAPI.requestGenerator = request;
statCalculator = stat;
statFormatter = format;
}
public PlayerRequest getPlayerStat(String playerName) {
return ;
@Override
public PlayerStatFetcher playerStat(String playerName) {
return new PlayerStatFetcher(playerName);
}
@Override
public StatResult<Integer> getPlayerStat(String playerName, Statistic statistic) {
return getPlayerStat(playerName, statistic, null, null);
public ServerStatFetcher serverStat() {
return new ServerStatFetcher();
}
@Override
public StatResult<?> getPlayerStat(String playerName, Statistic statistic, Material material) {
return getPlayerStat(playerName, statistic, material, null);
}
@Override
public StatResult<?> getPlayerStat(String playerName, Statistic statistic, EntityType entityType) {
return getPlayerStat(playerName, statistic, null, entityType);
}
@Override
public StatResult<?> getServerStat(Statistic statistic, Material material, EntityType entity) {
StatRequest request = getStatRequest(Target.SERVER, statistic, material, entity, null);
long stat = statCalculator.getServerStat(request);
TextComponent prettyStat = statFormatter.formatServerStat(request, stat);
return new ServerStatResult(stat, prettyStat);
}
@Override
public StatResult<?> getTopStats(Statistic statistic, Material material, EntityType entity) {
StatRequest request = getStatRequest(Target.TOP, statistic, material, entity, null);
LinkedHashMap<String, Integer> stat = statCalculator.getTopStats(request);
TextComponent prettyStat = statFormatter.formatTopStat(request, stat);
return new TopStatResult(stat, prettyStat);
}
private PlayerStatResult getPlayerStat(String playerName, Statistic statistic, Material material, EntityType entityType) {
StatRequest request = getStatRequest(Target.PLAYER, statistic, material, entityType, playerName);
int stat = statCalculator.getPlayerStat(request);
TextComponent prettyStat = statFormatter.formatPlayerStat(request, stat);
return new PlayerStatResult(stat, prettyStat);
}
private StatRequest getStatRequest(Target target, Statistic statistic, Material material, EntityType entity, String playerName) throws NullPointerException {
StatRequest request = requestGenerator.generateAPIRequest(target, statistic, material, entity, playerName);
if (requestGenerator.validateAPIRequest(request)) {
return request;
}
throw new NullPointerException("The parameters you supplied did not result in a valid stat-request!");
public TopStatFetcher topStat(int topListSize) {
return new TopStatFetcher(topListSize);
}
}

View File

@ -1,36 +1,37 @@
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.request.StatRequestCore;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.ApiStatus.Internal;
/** Turns user input into a valid {@link StatRequest}. This StatRequest should hold all
/** Turns user input into a valid {@link StatRequestCore}. 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.*/
@Internal
public interface RequestGenerator {
public abstract class 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.
protected StatRequestCore statRequest;
@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>
protected abstract StatRequestCore generateBaseRequest();
@param sender the CommandSender that requested this specific statistic
@return the generated StatRequest
*/
StatRequest generateRequest(CommandSender sender, String[] args);
StatRequestCore untyped(Statistic statistic) {
statRequest.setStatistic(statistic);
return statRequest;
}
StatRequest generateAPIRequest(Target target, Statistic statistic, Material material, EntityType entity, String playerName);
StatRequestCore blockOrItemType(Statistic statistic, Material material) {
statRequest.setSubStatEntryName(material.toString());
if (statistic.getType() == Statistic.Type.BLOCK) {
statRequest.setBlock(material);
} else {
statRequest.setItem(material);
}
return statRequest;
}
boolean validateRequest(StatRequest request);
boolean validateAPIRequest(StatRequest request);
StatRequestCore entityType(Statistic statistic, EntityType entityType) {
return null;
}
}

View File

@ -1,4 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.api;
public interface ServerStatRequest extends APIRequest {
}

View File

@ -1,14 +1,14 @@
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.request.StatRequestCore;
import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.LinkedHashMap;
/** The {@link StatCalculator} is responsible for getting, calculating and/or ordering raw numbers.
It represents the actual statistic-getting magic that happens once a valid
{@link StatRequest} is passed to it.
{@link StatRequestCore} is passed to it.
<br>
<br>The StatCalculator 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}:
@ -17,16 +17,16 @@ import java.util.LinkedHashMap;
<br>- LinkedHashMap[String player-name, Integer number] (for {@link Target#TOP})
<br>
<br>For more information on how to create a valid StatRequest,
see the class description for {@link StatRequest}.*/
see the class description for {@link StatRequestCore}.*/
@Internal
public interface StatCalculator {
/** Returns the requested Statistic*/
int getPlayerStat(StatRequest statRequest);
int getPlayerStat(StatRequestCore statRequestCore);
/** Don't call from main Thread!*/
long getServerStat(StatRequest statRequest);
long getServerStat(StatRequestCore statRequestCore);
/** Don't call from main Thread!*/
LinkedHashMap<String, Integer> getTopStats(StatRequest statRequest);
LinkedHashMap<String, Integer> getTopStats(StatRequestCore statRequestCore);
}

View File

@ -1,6 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.ComponentUtils;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.*;
@ -9,7 +9,7 @@ import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.LinkedHashMap;
/** The {@link StatFormatter} formats raw numbers into pretty messages.
This Formatter takes a {@link StatRequest} and combines it with the raw number(s)
This Formatter takes a {@link StatRequestCore} 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>
@ -38,16 +38,16 @@ public interface StatFormatter {
/** @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] {sub-stat-name}*/
TextComponent formatPlayerStat(StatRequest statRequest, int playerStat);
TextComponent formatPlayerStat(StatRequestCore statRequestCore, int playerStat);
/** @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]*/
TextComponent formatServerStat(StatRequest statRequest, long serverStat);
TextComponent formatServerStat(StatRequestCore statRequestCore, 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 statRequest, LinkedHashMap<String, Integer> topStats);
TextComponent formatTopStat(StatRequestCore statRequestCore, LinkedHashMap<String, Integer> topStats);
}

View File

@ -2,7 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.ShareManager;
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
import com.gmail.artemis.the.gr8.playerstats.models.InternalStatResult;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.InternalStatResult;
import com.gmail.artemis.the.gr8.playerstats.msg.OutputManager;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import org.bukkit.command.Command;

View File

@ -1,9 +1,9 @@
package com.gmail.artemis.the.gr8.playerstats.commands;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
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.request.InternalStatFetcher;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@ -14,12 +14,12 @@ public final class StatCommand implements CommandExecutor {
private static ThreadManager threadManager;
private static OutputManager outputManager;
private final RequestManager requestManager;
private final InternalStatFetcher internalStatFetcher;
public StatCommand(OutputManager m, ThreadManager t, RequestManager r) {
public StatCommand(OutputManager m, ThreadManager t, InternalStatFetcher r) {
threadManager = t;
outputManager = m;
requestManager = r;
internalStatFetcher = r;
}
@Override
@ -32,9 +32,9 @@ public final class StatCommand implements CommandExecutor {
outputManager.sendExamples(sender);
}
else {
StatRequest statRequest = requestManager.generateRequest(sender, args);
if (requestManager.validateRequest(statRequest)) {
threadManager.startStatThread(statRequest);
StatRequestCore statRequestCore = internalStatFetcher.generateRequest(sender, args);
if (internalStatFetcher.validateRequest(statRequestCore)) {
threadManager.startStatThread(statRequestCore);
} else {
return false;
}

View File

@ -5,7 +5,7 @@ import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ExampleMessage;
import com.gmail.artemis.the.gr8.playerstats.msg.components.HelpMessage;
@ -169,15 +169,15 @@ public final class MessageBuilder {
<p>- Integer shareCode: if a shareCode is provided, a clickable "share" button will be added.
<br>- CommandSender sender: if a sender is provided, a signature with "shared by sender-name" will be added.</br>
<br>- If both parameters are null, the statResult will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedPlayerStatFunction(int stat, @NotNull StatRequest statRequest) {
public BiFunction<Integer, CommandSender, TextComponent> formattedPlayerStatFunction(int stat, @NotNull StatRequestCore statRequestCore) {
TextComponent playerStat = Component.text()
.append(componentFactory.playerName(statRequest.getPlayerName(), Target.PLAYER)
.append(componentFactory.playerName(statRequestCore.getPlayerName(), Target.PLAYER)
.append(text(":"))
.append(space()))
.append(getStatNumberComponent(statRequest.getStatistic(), stat, Target.PLAYER, statRequest.isConsoleSender()))
.append(getStatNumberComponent(statRequestCore.getStatistic(), stat, Target.PLAYER, statRequestCore.isConsoleSender()))
.append(space())
.append(getStatNameComponent(statRequest))
.append(getStatUnitComponent(statRequest.getStatistic(), statRequest.getTarget(), statRequest.isConsoleSender())) //space is provided by statUnitComponent
.append(getStatNameComponent(statRequestCore))
.append(getStatUnitComponent(statRequestCore.getStatistic(), statRequestCore.getTarget(), statRequestCore.isConsoleSender())) //space is provided by statUnitComponent
.build();
return getFormattingFunction(playerStat, Target.PLAYER);
@ -188,16 +188,16 @@ public final class MessageBuilder {
<p>- Integer shareCode: if a shareCode is provided, a clickable "share" button will be added.
<br>- CommandSender sender: if a sender is provided, a signature with "shared by sender-name" will be added.</br>
<br>- If both parameters are null, the statResult will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedServerStatFunction(long stat, @NotNull StatRequest statRequest) {
public BiFunction<Integer, CommandSender, TextComponent> formattedServerStatFunction(long stat, @NotNull StatRequestCore statRequestCore) {
TextComponent serverStat = text()
.append(componentFactory.title(config.getServerTitle(), Target.SERVER))
.append(space())
.append(componentFactory.serverName(config.getServerName()))
.append(space())
.append(getStatNumberComponent(statRequest.getStatistic(), stat, Target.SERVER, statRequest.isConsoleSender()))
.append(getStatNumberComponent(statRequestCore.getStatistic(), stat, Target.SERVER, statRequestCore.isConsoleSender()))
.append(space())
.append(getStatNameComponent(statRequest))
.append(getStatUnitComponent(statRequest.getStatistic(), statRequest.getTarget(), statRequest.isConsoleSender())) //space is provided by statUnit
.append(getStatNameComponent(statRequestCore))
.append(getStatUnitComponent(statRequestCore.getStatistic(), statRequestCore.getTarget(), statRequestCore.isConsoleSender())) //space is provided by statUnit
.build();
return getFormattingFunction(serverStat, Target.SERVER);
@ -208,10 +208,10 @@ public final class MessageBuilder {
<p>- Integer shareCode: if a shareCode is provided, a clickable "share" button will be added.
<br>- CommandSender sender: if a sender is provided, a signature with "shared by sender-name" will be added.</br>
<br>- If both parameters are null, the statResult will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedTopStatFunction(@NotNull LinkedHashMap<String, Integer> topStats, @NotNull StatRequest statRequest) {
final TextComponent title = getTopStatsTitleComponent(statRequest, topStats.size());
final TextComponent shortTitle = getTopStatsTitleShortComponent(statRequest, topStats.size());
final TextComponent list = getTopStatListComponent(topStats, statRequest);
public BiFunction<Integer, CommandSender, TextComponent> formattedTopStatFunction(@NotNull LinkedHashMap<String, Integer> topStats, @NotNull StatRequestCore statRequestCore) {
final TextComponent title = getTopStatsTitleComponent(statRequestCore, topStats.size());
final TextComponent shortTitle = getTopStatsTitleShortComponent(statRequestCore, topStats.size());
final TextComponent list = getTopStatListComponent(topStats, statRequestCore);
final boolean useEnters = config.useEnters(Target.TOP, false);
final boolean useEntersForShared = config.useEnters(Target.TOP, true);
@ -302,25 +302,25 @@ public final class MessageBuilder {
return componentFactory.sharerName(sender.getName());
}
private TextComponent getTopStatsTitleComponent(StatRequest statRequest, int statListSize) {
private TextComponent getTopStatsTitleComponent(StatRequestCore statRequestCore, int statListSize) {
return Component.text()
.append(componentFactory.pluginPrefix()).append(space())
.append(componentFactory.title(config.getTopStatsTitle(), Target.TOP)).append(space())
.append(componentFactory.titleNumber(statListSize)).append(space())
.append(getStatNameComponent(statRequest)) //space is provided by statUnitComponent
.append(getStatUnitComponent(statRequest.getStatistic(), statRequest.getTarget(), statRequest.isConsoleSender()))
.append(getStatNameComponent(statRequestCore)) //space is provided by statUnitComponent
.append(getStatUnitComponent(statRequestCore.getStatistic(), statRequestCore.getTarget(), statRequestCore.isConsoleSender()))
.build();
}
private TextComponent getTopStatsTitleShortComponent(StatRequest statRequest, int statListSize) {
private TextComponent getTopStatsTitleShortComponent(StatRequestCore statRequestCore, int statListSize) {
return Component.text()
.append(componentFactory.title(config.getTopStatsTitle(), Target.TOP)).append(space())
.append(componentFactory.titleNumber(statListSize)).append(space())
.append(getStatNameComponent(statRequest)) //space is provided by statUnitComponent
.append(getStatNameComponent(statRequestCore)) //space is provided by statUnitComponent
.build();
}
private TextComponent getTopStatListComponent(LinkedHashMap<String, Integer> topStats, StatRequest statRequest) {
private TextComponent getTopStatListComponent(LinkedHashMap<String, Integer> topStats, StatRequestCore statRequestCore) {
TextComponent.Builder topList = Component.text();
boolean useDots = config.useDots();
boolean boldNames = config.playerNameIsBold();
@ -335,7 +335,7 @@ public final class MessageBuilder {
if (useDots) {
topList.append(playerNameBuilder)
.append(space());
int dots = FontUtils.getNumberOfDotsToAlign(count + ". " + playerName, statRequest.isConsoleSender(), boldNames);
int dots = FontUtils.getNumberOfDotsToAlign(count + ". " + playerName, statRequestCore.isConsoleSender(), boldNames);
if (dots >= 1) {
topList.append(componentFactory.dots().append(text((".".repeat(dots)))));
}
@ -343,33 +343,33 @@ public final class MessageBuilder {
else {
topList.append(playerNameBuilder.append(text(":")));
}
topList.append(space()).append(getStatNumberComponent(statRequest.getStatistic(), topStats.get(playerName), Target.TOP, statRequest.isConsoleSender()));
topList.append(space()).append(getStatNumberComponent(statRequestCore.getStatistic(), topStats.get(playerName), Target.TOP, statRequestCore.isConsoleSender()));
}
return topList.build();
}
/** Depending on the config settings, return either a TranslatableComponent representing
the statName (and potential subStatName), or a TextComponent with capitalized English names.*/
private TextComponent getStatNameComponent(StatRequest statRequest) {
private TextComponent getStatNameComponent(StatRequestCore statRequestCore) {
if (config.useTranslatableComponents()) {
String statKey = languageKeyHandler.getStatKey(statRequest.getStatistic());
String subStatKey = statRequest.getSubStatEntryName();
String statKey = languageKeyHandler.getStatKey(statRequestCore.getStatistic());
String subStatKey = statRequestCore.getSubStatEntryName();
if (subStatKey != null) {
switch (statRequest.getStatistic().getType()) {
case BLOCK -> subStatKey = languageKeyHandler.getBlockKey(statRequest.getBlock());
case ENTITY -> subStatKey = languageKeyHandler.getEntityKey(statRequest.getEntity());
case ITEM -> subStatKey = languageKeyHandler.getItemKey(statRequest.getItem());
switch (statRequestCore.getStatistic().getType()) {
case BLOCK -> subStatKey = languageKeyHandler.getBlockKey(statRequestCore.getBlock());
case ENTITY -> subStatKey = languageKeyHandler.getEntityKey(statRequestCore.getEntity());
case ITEM -> subStatKey = languageKeyHandler.getItemKey(statRequestCore.getItem());
default -> {
}
}
}
return componentFactory.statAndSubStatNameTranslatable(statKey, subStatKey, statRequest.getTarget());
return componentFactory.statAndSubStatNameTranslatable(statKey, subStatKey, statRequestCore.getTarget());
}
else {
return componentFactory.statAndSubStatName(
StringUtils.prettify(statRequest.getStatistic().toString()),
StringUtils.prettify(statRequest.getSubStatEntryName()),
statRequest.getTarget());
StringUtils.prettify(statRequestCore.getStatistic().toString()),
StringUtils.prettify(statRequestCore.getSubStatEntryName()),
statRequestCore.getTarget());
}
}

View File

@ -4,7 +4,7 @@ import com.gmail.artemis.the.gr8.playerstats.ShareManager;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
import com.gmail.artemis.the.gr8.playerstats.msg.components.BukkitConsoleComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.components.PrideComponentFactory;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
@ -50,27 +50,27 @@ public final class OutputManager implements StatFormatter {
}
@Override
public TextComponent formatPlayerStat(@NotNull StatRequest statRequest, int playerStat) {
public TextComponent formatPlayerStat(@NotNull StatRequestCore statRequestCore, int playerStat) {
BiFunction<Integer, CommandSender, TextComponent> playerStatFunction =
getWriter(statRequest).formattedPlayerStatFunction(playerStat, statRequest);
getWriter(statRequestCore).formattedPlayerStatFunction(playerStat, statRequestCore);
return processFunction(statRequest.getCommandSender(), playerStatFunction);
return processFunction(statRequestCore.getCommandSender(), playerStatFunction);
}
@Override
public TextComponent formatServerStat(@NotNull StatRequest statRequest, long serverStat) {
public TextComponent formatServerStat(@NotNull StatRequestCore statRequestCore, long serverStat) {
BiFunction<Integer, CommandSender, TextComponent> serverStatFunction =
getWriter(statRequest).formattedServerStatFunction(serverStat, statRequest);
getWriter(statRequestCore).formattedServerStatFunction(serverStat, statRequestCore);
return processFunction(statRequest.getCommandSender(), serverStatFunction);
return processFunction(statRequestCore.getCommandSender(), serverStatFunction);
}
@Override
public TextComponent formatTopStat(@NotNull StatRequest statRequest, @NotNull LinkedHashMap<String, Integer> topStats) {
public TextComponent formatTopStat(@NotNull StatRequestCore statRequestCore, @NotNull LinkedHashMap<String, Integer> topStats) {
BiFunction<Integer, CommandSender, TextComponent> topStatFunction =
getWriter(statRequest).formattedTopStatFunction(topStats, statRequest);
getWriter(statRequestCore).formattedTopStatFunction(topStats, statRequestCore);
return processFunction(statRequest.getCommandSender(), topStatFunction);
return processFunction(statRequestCore.getCommandSender(), topStatFunction);
}
public void sendFeedbackMsg(@NotNull CommandSender sender, StandardMessage message) {
@ -136,8 +136,8 @@ public final class OutputManager implements StatFormatter {
return sender instanceof ConsoleCommandSender ? consoleWriter : writer;
}
private MessageBuilder getWriter(StatRequest statRequest) {
if (statRequest.isAPIRequest() || !statRequest.isConsoleSender()) {
private MessageBuilder getWriter(StatRequestCore statRequestCore) {
if (statRequestCore.isAPIRequest() || !statRequestCore.isConsoleSender()) {
return writer;
} else {
return consoleWriter;

View File

@ -1,205 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
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.Bukkit;
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.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class RequestManager implements RequestGenerator {
private final EnumHandler enumHandler;
private final OfflinePlayerHandler offlinePlayerHandler;
private static OutputManager outputManager;
public RequestManager(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) {
this.enumHandler = enumHandler;
this.offlinePlayerHandler = offlinePlayerHandler;
RequestManager.outputManager = outputManager;
}
public StatRequest generateRequest(CommandSender sender, String[] args) {
StatRequest statRequest = new StatRequest(sender);
for (String arg : args) {
//check for statName
if (enumHandler.isStatistic(arg) && statRequest.getStatistic() == null) {
statRequest.setStatistic(EnumHandler.getStatEnum(arg));
}
//check for subStatEntry and playerFlag
else if (enumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player") && !statRequest.getPlayerFlag()) {
statRequest.setPlayerFlag(true);
}
else {
if (statRequest.getSubStatEntryName() == null) statRequest.setSubStatEntryName(arg);
}
}
//check for selection
else if (arg.equalsIgnoreCase("top")) {
statRequest.setTarget(Target.TOP);
}
else if (arg.equalsIgnoreCase("server")) {
statRequest.setTarget(Target.SERVER);
}
else if (arg.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
statRequest.setPlayerName(sender.getName());
statRequest.setTarget(Target.PLAYER);
}
else if (sender instanceof ConsoleCommandSender) {
statRequest.setTarget(Target.SERVER);
}
}
else if (offlinePlayerHandler.isRelevantPlayer(arg) && statRequest.getPlayerName() == null) {
statRequest.setPlayerName(arg);
statRequest.setTarget(Target.PLAYER);
}
else if (arg.equalsIgnoreCase("api")) {
statRequest.setAPIRequest();
}
}
patchRequest(statRequest);
return statRequest;
}
/** This method will generate a {@link StatRequest} for a request arriving through the API.*/
public StatRequest generateAPIRequest(@NotNull Target selection, @NotNull Statistic statistic, Material material, EntityType entity, String playerName) {
StatRequest statRequest = new StatRequest(Bukkit.getConsoleSender(), true);
statRequest.setTarget(selection);
statRequest.setStatistic(statistic);
switch (statistic.getType()) {
case BLOCK -> {
statRequest.setBlock(material);
statRequest.setSubStatEntryName(material.toString());
}
case ITEM -> {
statRequest.setItem(material);
statRequest.setSubStatEntryName(material.toString());
}
case ENTITY -> {
statRequest.setEntity(entity);
statRequest.setSubStatEntryName(entity.toString());
}
}
if (selection == Target.PLAYER) statRequest.setPlayerName(playerName);
return statRequest;
}
/** 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 statRequest if it is invalid.
<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 statRequest the StatRequest to check
@return true if the StatRequest is valid, and false otherwise.
*/
public boolean validateRequest(StatRequest statRequest) {
return validateRequestAndSendMessage(statRequest, statRequest.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.
<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 statRequest the StatRequest to check
@return true if the StatRequest is valid, and false otherwise.
*/
public boolean validateAPIRequest(StatRequest statRequest) {
return validateRequestAndSendMessage(statRequest, Bukkit.getConsoleSender());
}
private boolean validateRequestAndSendMessage(StatRequest statRequest, CommandSender sender) {
if (statRequest.getStatistic() == null) {
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_STAT_NAME);
return false;
}
Statistic.Type type = statRequest.getStatistic().getType();
if (statRequest.getSubStatEntryName() == null && type != Statistic.Type.UNTYPED) {
outputManager.sendFeedbackMsgMissingSubStat(sender, type);
return false;
}
else if (!hasMatchingSubStat(statRequest)) {
outputManager.sendFeedbackMsgWrongSubStat(sender, type, statRequest.getSubStatEntryName());
return false;
}
else if (statRequest.getTarget() == Target.PLAYER && statRequest.getPlayerName() == null) {
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_PLAYER_NAME);
return false;
}
else {
return true;
}
}
/** 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 statRequest) {
if (statRequest.getStatistic() != null) {
Statistic.Type type = statRequest.getStatistic().getType();
if (statRequest.getPlayerFlag()) { //unpack the playerFlag
if (type == Statistic.Type.ENTITY && statRequest.getSubStatEntryName() == null) {
statRequest.setSubStatEntryName("player");
}
else {
statRequest.setTarget(Target.PLAYER);
}
}
String subStatEntry = statRequest.getSubStatEntryName();
switch (type) { //attempt to convert relevant subStatEntries into their corresponding Enum Constant
case BLOCK -> {
Material block = EnumHandler.getBlockEnum(subStatEntry);
if (block != null) statRequest.setBlock(block);
}
case ENTITY -> {
EntityType entity = EnumHandler.getEntityEnum(subStatEntry);
if (entity != null) statRequest.setEntity(entity);
}
case ITEM -> {
Material item = EnumHandler.getItemEnum(subStatEntry);
if (item != null) statRequest.setItem(item);
}
case UNTYPED -> { //remove unnecessary subStatEntries
if (subStatEntry != null) statRequest.setSubStatEntryName(null);
}
}
}
}
private boolean hasMatchingSubStat(StatRequest statRequest) {
Statistic.Type type = statRequest.getStatistic().getType();
switch (type) {
case BLOCK -> {
return statRequest.getBlock() != null;
}
case ENTITY -> {
return statRequest.getEntity() != null;
}
case ITEM -> {
return statRequest.getItem() != null;
}
default -> {
return true;
}
}
}
}

View File

@ -1,7 +1,7 @@
package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.google.common.collect.ImmutableList;
@ -18,7 +18,7 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
private final OfflinePlayerHandler offlinePlayerHandler;
private final ImmutableList<String> playerNames;
private final StatRequest statRequest;
private final StatRequestCore statRequestCore;
private final ConcurrentHashMap<String, Integer> allStats;
/**
@ -26,15 +26,15 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
* using the default ForkJoinPool, and returns the ConcurrentHashMap when everything is done
* @param offlinePlayerHandler the OfflinePlayerHandler to convert playerNames into Players
* @param playerNames ImmutableList of playerNames for players that should be included in stat calculations
* @param statRequest a validated statRequest
* @param statRequestCore a validated statRequest
* @param allStats the ConcurrentHashMap to put the results on
*/
public StatAction(OfflinePlayerHandler offlinePlayerHandler, ImmutableList<String> playerNames, StatRequest statRequest, ConcurrentHashMap<String, Integer> allStats) {
public StatAction(OfflinePlayerHandler offlinePlayerHandler, ImmutableList<String> playerNames, StatRequestCore statRequestCore, ConcurrentHashMap<String, Integer> allStats) {
threshold = ThreadManager.getTaskThreshold();
this.offlinePlayerHandler = offlinePlayerHandler;
this.playerNames = playerNames;
this.statRequest = statRequest;
this.statRequestCore = statRequestCore;
this.allStats = allStats;
MyLogger.subActionCreated(Thread.currentThread().getName());
@ -46,8 +46,8 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
return getStatsDirectly();
}
else {
final StatAction subTask1 = new StatAction(offlinePlayerHandler, playerNames.subList(0, playerNames.size()/2), statRequest, allStats);
final StatAction subTask2 = new StatAction(offlinePlayerHandler, playerNames.subList(playerNames.size()/2, playerNames.size()), statRequest, allStats);
final StatAction subTask1 = new StatAction(offlinePlayerHandler, playerNames.subList(0, playerNames.size()/2), statRequestCore, allStats);
final StatAction subTask2 = new StatAction(offlinePlayerHandler, playerNames.subList(playerNames.size()/2, playerNames.size()), statRequestCore, allStats);
//queue and compute all subtasks in the right order
subTask1.fork();
@ -65,11 +65,11 @@ final class StatAction extends RecursiveTask<ConcurrentHashMap<String, Integer>>
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(playerName);
if (player != null) {
int statistic = 0;
switch (statRequest.getStatistic().getType()) {
case UNTYPED -> statistic = player.getStatistic(statRequest.getStatistic());
case ENTITY -> statistic = player.getStatistic(statRequest.getStatistic(), statRequest.getEntity());
case BLOCK -> statistic = player.getStatistic(statRequest.getStatistic(), statRequest.getBlock());
case ITEM -> statistic = player.getStatistic(statRequest.getStatistic(), statRequest.getItem());
switch (statRequestCore.getStatistic().getType()) {
case UNTYPED -> statistic = player.getStatistic(statRequestCore.getStatistic());
case ENTITY -> statistic = player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getEntity());
case BLOCK -> statistic = player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getBlock());
case ITEM -> statistic = player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getItem());
}
if (statistic > 0) {
allStats.put(playerName, statistic);

View File

@ -2,7 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.ThreadManager;
import com.gmail.artemis.the.gr8.playerstats.api.StatCalculator;
import com.gmail.artemis.the.gr8.playerstats.models.StatRequest;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.StatRequestCore;
import com.gmail.artemis.the.gr8.playerstats.utils.MyLogger;
import com.gmail.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
import com.google.common.collect.ImmutableList;
@ -30,28 +30,28 @@ public final class StatManager implements StatCalculator {
/** Gets the statistic data for an individual player. If somehow the player
cannot be found, this returns 0.*/
public int getPlayerStat(StatRequest statRequest) {
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(statRequest.getPlayerName());
public int getPlayerStat(StatRequestCore statRequestCore) {
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(statRequestCore.getPlayerName());
if (player != null) {
return switch (statRequest.getStatistic().getType()) {
case UNTYPED -> player.getStatistic(statRequest.getStatistic());
case ENTITY -> player.getStatistic(statRequest.getStatistic(), statRequest.getEntity());
case BLOCK -> player.getStatistic(statRequest.getStatistic(), statRequest.getBlock());
case ITEM -> player.getStatistic(statRequest.getStatistic(), statRequest.getItem());
return switch (statRequestCore.getStatistic().getType()) {
case UNTYPED -> player.getStatistic(statRequestCore.getStatistic());
case ENTITY -> player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getEntity());
case BLOCK -> player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getBlock());
case ITEM -> player.getStatistic(statRequestCore.getStatistic(), statRequestCore.getItem());
};
}
return 0;
}
public LinkedHashMap<String, Integer> getTopStats(StatRequest statRequest) {
return getAllStatsAsync(statRequest).entrySet().stream()
public LinkedHashMap<String, Integer> getTopStats(StatRequestCore statRequestCore) {
return getAllStatsAsync(statRequestCore).entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(topListMaxSize)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
public long getServerStat(StatRequest statRequest) {
List<Integer> numbers = getAllStatsAsync(statRequest)
public long getServerStat(StatRequestCore statRequestCore) {
List<Integer> numbers = getAllStatsAsync(statRequestCore)
.values()
.parallelStream()
.toList();
@ -60,14 +60,14 @@ public final class StatManager implements StatCalculator {
/** Invokes a bunch of worker pool threads to divide and conquer (get the statistics for all players
that are stored in the {@link OfflinePlayerHandler}) */
private @NotNull ConcurrentHashMap<String, Integer> getAllStatsAsync(StatRequest statRequest) {
private @NotNull ConcurrentHashMap<String, Integer> getAllStatsAsync(StatRequestCore statRequestCore) {
long time = System.currentTimeMillis();
ForkJoinPool commonPool = ForkJoinPool.commonPool();
ConcurrentHashMap<String, Integer> allStats;
try {
allStats = commonPool.invoke(getStatTask(statRequest));
allStats = commonPool.invoke(getStatTask(statRequestCore));
} catch (ConcurrentModificationException e) {
MyLogger.logMsg("The statRequest could not be executed due to a ConcurrentModificationException. " +
"This likely happened because Bukkit hasn't fully initialized all player-data yet. " +
@ -82,12 +82,12 @@ public final class StatManager implements StatCalculator {
return allStats;
}
private StatAction getStatTask(StatRequest statRequest) {
private StatAction getStatTask(StatRequestCore statRequestCore) {
int size = offlinePlayerHandler.getOfflinePlayerCount() != 0 ? offlinePlayerHandler.getOfflinePlayerCount() : 16;
ConcurrentHashMap<String, Integer> allStats = new ConcurrentHashMap<>(size);
ImmutableList<String> playerNames = ImmutableList.copyOf(offlinePlayerHandler.getOfflinePlayerNames());
StatAction task = new StatAction(offlinePlayerHandler, playerNames, statRequest, allStats);
StatAction task = new StatAction(offlinePlayerHandler, playerNames, statRequestCore, allStats);
MyLogger.actionCreated(playerNames.size());
return task;

View File

@ -3,7 +3,7 @@ package com.gmail.artemis.the.gr8.playerstats.statistic;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
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.statistic.request.StatRequestCore;
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;
@ -20,16 +20,16 @@ public final class StatThread extends Thread {
private static StatManager statManager;
private final ReloadThread reloadThread;
private final StatRequest statRequest;
private final StatRequestCore statRequestCore;
public StatThread(OutputManager m, StatManager t, int ID, StatRequest s, @Nullable ReloadThread r) {
public StatThread(OutputManager m, StatManager t, int ID, StatRequestCore s, @Nullable ReloadThread r) {
outputManager = m;
statManager = t;
reloadThread = r;
statRequest = s;
statRequestCore = s;
this.setName("StatThread-" + statRequest.getCommandSender().getName() + "-" + ID);
this.setName("StatThread-" + statRequestCore.getCommandSender().getName() + "-" + ID);
MyLogger.threadCreated(this.getName());
}
@ -37,13 +37,13 @@ public final class StatThread extends Thread {
public void run() throws IllegalStateException, NullPointerException {
MyLogger.threadStart(this.getName());
if (statRequest == null) {
if (statRequestCore == null) {
throw new NullPointerException("No statistic statRequest was found!");
}
if (reloadThread != null && reloadThread.isAlive()) {
try {
MyLogger.waitingForOtherThread(this.getName(), reloadThread.getName());
outputManager.sendFeedbackMsg(statRequest.getCommandSender(), StandardMessage.STILL_RELOADING);
outputManager.sendFeedbackMsg(statRequestCore.getCommandSender(), StandardMessage.STILL_RELOADING);
reloadThread.join();
} catch (InterruptedException e) {
@ -54,27 +54,27 @@ public final class StatThread extends Thread {
long lastCalc = ThreadManager.getLastRecordedCalcTime();
if (lastCalc > 2000) {
outputManager.sendFeedbackMsgWaitAMoment(statRequest.getCommandSender(), lastCalc > 20000);
outputManager.sendFeedbackMsgWaitAMoment(statRequestCore.getCommandSender(), lastCalc > 20000);
}
Target selection = statRequest.getTarget();
Target selection = statRequestCore.getTarget();
try {
TextComponent statResult = switch (selection) {
case PLAYER -> outputManager.formatPlayerStat(statRequest, statManager.getPlayerStat(statRequest));
case TOP -> outputManager.formatTopStat(statRequest, statManager.getTopStats(statRequest));
case SERVER -> outputManager.formatServerStat(statRequest, statManager.getServerStat(statRequest));
case PLAYER -> outputManager.formatPlayerStat(statRequestCore, statManager.getPlayerStat(statRequestCore));
case TOP -> outputManager.formatTopStat(statRequestCore, statManager.getTopStats(statRequestCore));
case SERVER -> outputManager.formatServerStat(statRequestCore, statManager.getServerStat(statRequestCore));
};
if (statRequest.isAPIRequest()) {
if (statRequestCore.isAPIRequest()) {
String msg = StatFormatter.statResultComponentToString(statResult);
statRequest.getCommandSender().sendMessage(msg);
statRequestCore.getCommandSender().sendMessage(msg);
}
else {
outputManager.sendToCommandSender(statRequest.getCommandSender(), statResult);
outputManager.sendToCommandSender(statRequestCore.getCommandSender(), statResult);
}
}
catch (ConcurrentModificationException e) {
if (!statRequest.isConsoleSender()) {
outputManager.sendFeedbackMsg(statRequest.getCommandSender(), StandardMessage.UNKNOWN_ERROR);
if (!statRequestCore.isConsoleSender()) {
outputManager.sendFeedbackMsg(statRequestCore.getCommandSender(), StandardMessage.UNKNOWN_ERROR);
}
}
}

View File

@ -0,0 +1,186 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
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.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.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
public final class InternalStatFetcher {
private final EnumHandler enumHandler;
private final OfflinePlayerHandler offlinePlayerHandler;
private static OutputManager outputManager;
public InternalStatFetcher(EnumHandler enumHandler, OfflinePlayerHandler offlinePlayerHandler, OutputManager outputManager) {
this.enumHandler = enumHandler;
this.offlinePlayerHandler = offlinePlayerHandler;
InternalStatFetcher.outputManager = outputManager;
}
/** This will create a {@link StatRequestCore} 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 StatRequestCore generateRequest(CommandSender sender, String[] args) {
StatRequestCore statRequestCore = new StatRequestCore(sender);
for (String arg : args) {
//check for statName
if (enumHandler.isStatistic(arg) && statRequestCore.getStatistic() == null) {
statRequestCore.setStatistic(EnumHandler.getStatEnum(arg));
}
//check for subStatEntry and playerFlag
else if (enumHandler.isSubStatEntry(arg)) {
if (arg.equalsIgnoreCase("player") && !statRequestCore.getPlayerFlag()) {
statRequestCore.setPlayerFlag(true);
}
else {
if (statRequestCore.getSubStatEntryName() == null) statRequestCore.setSubStatEntryName(arg);
}
}
//check for selection
else if (arg.equalsIgnoreCase("top")) {
statRequestCore.setTarget(Target.TOP);
}
else if (arg.equalsIgnoreCase("server")) {
statRequestCore.setTarget(Target.SERVER);
}
else if (arg.equalsIgnoreCase("me")) {
if (sender instanceof Player) {
statRequestCore.setPlayerName(sender.getName());
statRequestCore.setTarget(Target.PLAYER);
}
else if (sender instanceof ConsoleCommandSender) {
statRequestCore.setTarget(Target.SERVER);
}
}
else if (offlinePlayerHandler.isRelevantPlayer(arg) && statRequestCore.getPlayerName() == null) {
statRequestCore.setPlayerName(arg);
statRequestCore.setTarget(Target.PLAYER);
}
else if (arg.equalsIgnoreCase("api")) {
statRequestCore.setAPIRequest();
}
}
patchRequest(statRequestCore);
return statRequestCore;
}
/** Checks if a given {@link StatRequestCore} would result in a valid statistic look-up,
and sends a feedback message to the CommandSender that prompted the statRequest if it is invalid.
<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 statRequestCore the StatRequest to check
@return true if the StatRequest is valid, and false otherwise.
*/
public boolean validateRequest(StatRequestCore statRequestCore) {
return validateRequestAndSendMessage(statRequestCore, statRequestCore.getCommandSender());
}
/** Checks if a given {@link StatRequestCore} would result in a valid statistic look-up,
and sends a feedback message if it is invalid.
<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 statRequestCore the StatRequest to check
@return true if the StatRequest is valid, and false otherwise.
*/
private boolean validateRequestAndSendMessage(StatRequestCore statRequestCore, CommandSender sender) {
if (statRequestCore.getStatistic() == null) {
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_STAT_NAME);
return false;
}
Statistic.Type type = statRequestCore.getStatistic().getType();
if (statRequestCore.getSubStatEntryName() == null && type != Statistic.Type.UNTYPED) {
outputManager.sendFeedbackMsgMissingSubStat(sender, type);
return false;
}
else if (!hasMatchingSubStat(statRequestCore)) {
outputManager.sendFeedbackMsgWrongSubStat(sender, type, statRequestCore.getSubStatEntryName());
return false;
}
else if (statRequestCore.getTarget() == Target.PLAYER && statRequestCore.getPlayerName() == null) {
outputManager.sendFeedbackMsg(sender, StandardMessage.MISSING_PLAYER_NAME);
return false;
}
else {
return true;
}
}
/** 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(StatRequestCore statRequestCore) {
if (statRequestCore.getStatistic() != null) {
Statistic.Type type = statRequestCore.getStatistic().getType();
if (statRequestCore.getPlayerFlag()) { //unpack the playerFlag
if (type == Statistic.Type.ENTITY && statRequestCore.getSubStatEntryName() == null) {
statRequestCore.setSubStatEntryName("player");
}
else {
statRequestCore.setTarget(Target.PLAYER);
}
}
String subStatEntry = statRequestCore.getSubStatEntryName();
switch (type) { //attempt to convert relevant subStatEntries into their corresponding Enum Constant
case BLOCK -> {
Material block = EnumHandler.getBlockEnum(subStatEntry);
if (block != null) statRequestCore.setBlock(block);
}
case ENTITY -> {
EntityType entity = EnumHandler.getEntityEnum(subStatEntry);
if (entity != null) statRequestCore.setEntity(entity);
}
case ITEM -> {
Material item = EnumHandler.getItemEnum(subStatEntry);
if (item != null) statRequestCore.setItem(item);
}
case UNTYPED -> { //remove unnecessary subStatEntries
if (subStatEntry != null) statRequestCore.setSubStatEntryName(null);
}
}
}
}
private boolean hasMatchingSubStat(StatRequestCore statRequestCore) {
Statistic.Type type = statRequestCore.getStatistic().getType();
switch (type) {
case BLOCK -> {
return statRequestCore.getBlock() != null;
}
case ENTITY -> {
return statRequestCore.getEntity() != null;
}
case ITEM -> {
return statRequestCore.getItem() != null;
}
default -> {
return true;
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import org.bukkit.Bukkit;
public final class PlayerStatFetcher extends RequestGenerator {
private final String playerName;
public PlayerStatFetcher(String playerName) {
super.statRequest = generateBaseRequest();
this.playerName = playerName;
}
@Override
protected StatRequestCore generateBaseRequest() {
StatRequestCore request = new StatRequestCore(Bukkit.getConsoleSender(), true);
request.setTarget(Target.PLAYER);
request.setPlayerName(playerName);
return request;
}
}

View File

@ -0,0 +1,19 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import org.bukkit.Bukkit;
public final class ServerStatFetcher extends RequestGenerator {
public ServerStatFetcher() {
super.statRequest = generateBaseRequest();
}
@Override
protected StatRequestCore generateBaseRequest() {
StatRequestCore request = new StatRequestCore(Bukkit.getConsoleSender(), true);
request.setTarget(Target.SERVER);
return request;
}
}

View File

@ -0,0 +1,16 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.StatResult;
public record StatRequest(StatRequestCore requestCore) {
public <T> StatResult<T> execute() {
return null;
}
public void eeeeeeh() {
StatResult<StringBuffer> lod = execute();
}
}
//TODO fix >:(

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable;
<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 final class StatRequest {
public final class StatRequestCore {
private final CommandSender sender;
private boolean isAPIRequest;
@ -40,7 +40,7 @@ public final class StatRequest {
private Material item;
private boolean playerFlag;
/** Create a new {@link StatRequest} with default values:
/** Create a new {@link StatRequestCore} with default values:
<br>- CommandSender sender (provided)
<br>- Target <code>target</code> = {@link Target#TOP}
<br>- boolean <code>playerFlag</code> = false
@ -48,11 +48,11 @@ public final class StatRequest {
@param sender the CommandSender who prompted this RequestGenerator
*/
public StatRequest(@NotNull CommandSender sender) {
public StatRequestCore(@NotNull CommandSender sender) {
this(sender, false);
}
/** Create a new {@link StatRequest} with default values:
/** Create a new {@link StatRequestCore} with default values:
<br>- CommandSender sender (provided)
<br>- Target target = {@link Target#TOP}
<br>- boolean playerFlag = false
@ -61,7 +61,7 @@ public final class StatRequest {
@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) {
public StatRequestCore(@NotNull CommandSender sender, boolean isAPIRequest) {
this.sender = sender;
this.isAPIRequest = isAPIRequest;
target = Target.TOP;

View File

@ -0,0 +1,22 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import org.bukkit.Bukkit;
public class TopStatFetcher extends RequestGenerator {
private final int topListSize;
public TopStatFetcher(int topListSize) {
this.topListSize = topListSize;
super.statRequest = generateBaseRequest();
}
@Override
protected StatRequestCore generateBaseRequest() {
StatRequestCore request = new StatRequestCore(Bukkit.getConsoleSender(), true);
request.setTarget(Target.TOP);
return request;
}
}

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import net.kyori.adventure.text.TextComponent;

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import net.kyori.adventure.text.TextComponent;

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import net.kyori.adventure.text.TextComponent;

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import net.kyori.adventure.text.TextComponent;

View File

@ -1,4 +1,4 @@
package com.gmail.artemis.the.gr8.playerstats.models;
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import net.kyori.adventure.text.TextComponent;