Started separating regular output from API-output and started creating more format methods for the API

This commit is contained in:
Artemis-the-gr8 2022-08-09 21:02:19 +02:00
parent 3c9e454ad4
commit 21dc6ef275
26 changed files with 329 additions and 214 deletions

View File

@ -1,8 +1,9 @@
package com.gmail.artemis.the.gr8.playerstats;
import com.gmail.artemis.the.gr8.playerstats.api.ApiOutputManager;
import com.gmail.artemis.the.gr8.playerstats.api.PlayerStats;
import com.gmail.artemis.the.gr8.playerstats.api.PlayerStatsAPI;
import com.gmail.artemis.the.gr8.playerstats.api.StatFormatter;
import com.gmail.artemis.the.gr8.playerstats.msg.InternalFormatter;
import com.gmail.artemis.the.gr8.playerstats.commands.ReloadCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.ShareCommand;
import com.gmail.artemis.the.gr8.playerstats.commands.StatCommand;
@ -105,7 +106,7 @@ public final class Main extends JavaPlugin {
return statCalculator;
}
public static @NotNull StatFormatter getStatFormatter() throws IllegalStateException {
public static @NotNull InternalFormatter getStatFormatter() throws IllegalStateException {
if (outputManager == null) {
throw new IllegalStateException("PlayerStats does not seem to be loaded!");
}
@ -127,10 +128,11 @@ public final class Main extends JavaPlugin {
offlinePlayerHandler = new OfflinePlayerHandler();
shareManager = new ShareManager(config);
outputManager = new OutputManager(getAdventure(), config, shareManager);
statCalculator = new StatCalculator(offlinePlayerHandler);
outputManager = new OutputManager(adventure, config, shareManager);
threadManager = new ThreadManager(config, statCalculator, outputManager);
playerStatsAPI = new PlayerStatsAPI(outputManager, offlinePlayerHandler);
ApiOutputManager apiOutputManager = new ApiOutputManager(config);
playerStatsAPI = new PlayerStatsAPI(apiOutputManager, offlinePlayerHandler);
}
}

View File

@ -93,10 +93,10 @@ public final class ShareManager {
return sharedResults.contains(shareCode);
}
/** Takes a formattedValue from the internal ConcurrentHashmap,
/** Takes a formattedComponent from the internal ConcurrentHashmap,
puts the current time in the shareTimeStamp (ConcurrentHashMap),
puts the shareCode (int hashCode) in the sharedResults (ArrayBlockingQueue),
and returns the formattedValue. If no formattedValue was found, returns null.*/
and returns the formattedComponent. If no formattedComponent was found, returns null.*/
public @Nullable InternalStatResult getStatResult(String playerName, int shareCode) {
if (statResultQueue.containsKey(shareCode)) {
shareTimeStamp.put(playerName, Instant.now());

View File

@ -0,0 +1,56 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.NumberFormatter;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Statistic;
/** Formats messages meant for usage outside PlayerStats.
The output is ready to be sent to a Minecraft client or console with the Adventure library.
To send a Component, you need to get a {@link BukkitAudiences} object. Normally you would
have to add the library as a dependency, but since the library is included in PlayerStats, you can
access it directly. Information on how to get and use the BukkitAudiences object can be found on
<a href="https://docs.adventure.kyori.net/platform/bukkit.html">Adventure's website</a>.*/
public interface ApiFormatter {
/** Turns a TextComponent into its String representation. This method is equipped
to turn all PlayerStats' formatted statResults into String.
@return a String representation of this TextComponent, without hover/click events,
but with color, style and formatting. TranslatableComponents will be turned into
plain English.*/
default String TextComponentToString(TextComponent component) {
return ComponentUtils.getTranslatableComponentSerializer()
.serialize(component);
}
/** Gets a {@link NumberFormatter} to format raw numbers into something more readable.*/
default NumberFormatter getNumberFormatter() {
return new NumberFormatter();
}
/** @return [PlayerStats]*/
TextComponent getPluginPrefix();
TextComponent getRainbowPluginPrefix();
/** @return ________ [PlayerStats] ________*/
TextComponent getPluginPrefixAsTitle();
TextComponent getRainbowPluginPrefixAsTitle();
TextComponent getTopStatTitle(int topStatSize, Statistic statistic);
TextComponent getTopStatTitle(int topStatSize, Statistic statistic, String subStatisticName);
TextComponent getTopStatTitle(int topStatSize, Statistic statistic, Unit unit);
/** @return a single line from a top-x statistic:
* <br> x. Player-name ......... number */
TextComponent getFormattedTopStatLine(int positionInTopList, String playerName, long statNumber, Unit unit);
TextComponent getFormattedServerStat(long statNumber, Unit unit);
}

View File

@ -0,0 +1,113 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.config.ConfigHandler;
import com.gmail.artemis.the.gr8.playerstats.enums.Target;
import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.components.PrideComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.FontUtils;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.NumberFormatter;
import com.gmail.artemis.the.gr8.playerstats.msg.msgutils.StringUtils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Statistic;
import org.jetbrains.annotations.Nullable;
import static net.kyori.adventure.text.Component.space;
public class ApiOutputManager implements ApiFormatter {
private final ComponentFactory componentFactory;
private final PrideComponentFactory prideComponentFactory;
private final NumberFormatter numberFormatter;
public ApiOutputManager(ConfigHandler config) {
componentFactory = new ComponentFactory(config);
prideComponentFactory = new PrideComponentFactory(config);
numberFormatter = new NumberFormatter();
}
@Override
public TextComponent getPluginPrefix() {
return componentFactory.pluginPrefix();
}
@Override
public TextComponent getRainbowPluginPrefix() {
return prideComponentFactory.pluginPrefix();
}
@Override
public TextComponent getPluginPrefixAsTitle() {
return componentFactory.pluginPrefixAsTitle();
}
@Override
public TextComponent getRainbowPluginPrefixAsTitle() {
return prideComponentFactory.pluginPrefixAsTitle();
}
@Override
public TextComponent getTopStatTitle(int topStatSize, Statistic statistic) {
return getTopStatTitle(topStatSize, statistic, null, null);
}
@Override
public TextComponent getTopStatTitle(int topListSize, Statistic statistic, @Nullable String subStatName) {
return getTopStatTitle(topListSize, statistic, subStatName, null);
}
@Override
public TextComponent getTopStatTitle(int topListSize, Statistic statistic, Unit unit) {
return getTopStatTitle(topListSize, statistic, null, unit);
}
private TextComponent getTopStatTitle(int topListSize, Statistic statistic, String subStatName, Unit unit) {
String prettyStatName = StringUtils.prettify(statistic.toString());
TextComponent.Builder titleBuilder = Component.text()
.append(componentFactory.title("Top", Target.TOP))
.append(space())
.append(componentFactory.titleNumber(topListSize))
.append(space())
.append(componentFactory.statAndSubStatName(prettyStatName, subStatName, Target.TOP));
if (unit != null) {
titleBuilder.append(space())
.append(componentFactory.statUnit(unit.getLabel(), Target.TOP));
}
return titleBuilder.build();
}
@Override
public TextComponent getFormattedTopStatLine(int positionInTopList, String playerName, long statNumber, Unit unit) {
TextComponent.Builder topStatLineBuilder = Component.text()
.append(space())
.append(componentFactory.rankNumber(positionInTopList))
.append(space());
int dots = FontUtils.getNumberOfDotsToAlign(positionInTopList + ". " + playerName);
if (dots >= 1) {
topStatLineBuilder.append(componentFactory.dots(".".repeat(dots)));
}
TextComponent numberComponent = getTopStatNumberComponent(unit, statNumber);
return topStatLineBuilder
.append(space())
.append(numberComponent)
.build();
}
@Override
public TextComponent getFormattedServerStat(long statNumber, Unit unit) {
}
private TextComponent getTopStatNumberComponent(Unit unit, long statNumber) {
return switch (unit.getType()) {
case DISTANCE -> componentFactory.distanceNumber(numberFormatter.formatDistanceNumber(statNumber, unit), Target.TOP);
case DAMAGE -> componentFactory.damageNumber(numberFormatter.formatDamageNumber(statNumber, unit), Target.TOP);
case TIME -> componentFactory.timeNumber(numberFormatter.formatTimeNumber(statNumber, unit, unit), Target.TOP);
default -> componentFactory.statNumber(numberFormatter.formatNumber(statNumber), Target.TOP);
};
}
}

View File

@ -1,33 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Statistic;
public interface Formatter {
/** Turns a TextComponent into its String representation. This method is equipped
to turn all PlayerStats' formatted statResults into String.
@return a String representation of this TextComponent, without hover/click events,
but with color, style and formatting. TranslatableComponents will be turned into
plain English.*/
default String TextComponentToString(TextComponent component) {
return ComponentUtils.getTranslatableComponentSerializer()
.serialize(component);
}
/** @return [PlayerStats]*/
TextComponent getPluginPrefix();
TextComponent getRainbowPluginPrefix();
/** @return ________ [PlayerStats] ________*/
TextComponent getPluginPrefixAsTitle();
TextComponent getRainbowPluginPrefixAsTitle();
/** @return a single line from a top-x statistic:
* <br> x. Player-name ......... number */
TextComponent formatSingleTopStatLine(int positionInTopList, String playerName, long statNumber, Statistic statistic);
}

View File

@ -27,5 +27,5 @@ public interface PlayerStats {
StatManager getStatManager();
Formatter getFormatter();
ApiFormatter getFormatter();
}

View File

@ -9,17 +9,17 @@ import static org.jetbrains.annotations.ApiStatus.Internal;
public final class PlayerStatsAPI implements PlayerStats, StatManager {
private final OfflinePlayerHandler offlinePlayerHandler;
private static StatFormatter statFormatter;
private static ApiFormatter apiFormatter;
@Internal
public PlayerStatsAPI(StatFormatter format, OfflinePlayerHandler offlinePlayers) {
statFormatter = format;
public PlayerStatsAPI(ApiFormatter formatter, OfflinePlayerHandler offlinePlayers) {
apiFormatter = formatter;
offlinePlayerHandler = offlinePlayers;
}
@Override
public Formatter getFormatter() {
return statFormatter;
public ApiFormatter getFormatter() {
return apiFormatter;
}
@Override
@ -46,7 +46,7 @@ public final class PlayerStatsAPI implements PlayerStats, StatManager {
}
@Override
public TopStatRequest totalTopStatListRequest() {
public TopStatRequest totalTopStatRequest() {
int playerCount = offlinePlayerHandler.getOfflinePlayerCount();
return topStatRequest(playerCount);
}

View File

@ -1,44 +0,0 @@
package com.gmail.artemis.the.gr8.playerstats.api;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.RequestSettings;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatCalculator;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.*;
import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.LinkedHashMap;
/** The {@link StatFormatter} formats raw numbers into pretty messages.
This Formatter takes a {@link RequestSettings} object and combines it with the raw number(s)
returned by the {@link StatCalculator}, and transforms those into a pretty message
(by default a TextComponent) with all the relevant information in it.
<br>
<br>The output is ready to be sent to a Minecraft client or console with the Adventure library.
To send a Component, you need to get a {@link BukkitAudiences} object. Normally you would
have to add the library as a dependency, but since the library is included in PlayerStats, you can
access it directly. Information on how to get and use the BukkitAudiences object can be found on
<a href="https://docs.adventure.kyori.net/platform/bukkit.html">Adventure's website</a>.
<br>
<br>Alternatively, you can also turn your TextComponent into a plain String with
{@link #TextComponentToString(TextComponent)}. Don't use Adventure's method .content()
on your formattedValue to do this - because of the way the TextComponent is built by PlayerStats,
you won't be able to get the full content that way.*/
@Internal
public
interface StatFormatter extends Formatter {
/** @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] {sub-stat-name}*/
TextComponent formatPlayerStat(RequestSettings requestSettings, int playerStat);
/** @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]*/
TextComponent formatServerStat(RequestSettings requestSettings, 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(RequestSettings requestSettings, LinkedHashMap<String, Integer> topStats);
}

View File

@ -32,5 +32,5 @@ public interface StatManager {
all default settings for a top-statistic-lookup are configured.
@return the RequestGenerator*/
RequestGenerator<LinkedHashMap<String, Integer>> totalTopStatListRequest();
RequestGenerator<LinkedHashMap<String, Integer>> totalTopStatRequest();
}

View File

@ -38,7 +38,7 @@ public final class ShareCommand implements CommandExecutor {
}
else {
InternalStatResult result = shareManager.getStatResult(sender.getName(), shareCode);
if (result == null) { //at this point the only possible cause of formattedValue being null is the request being older than 25 player-requests ago
if (result == null) { //at this point the only possible cause of formattedComponent being null is the request being older than 25 player-requests ago
outputManager.sendFeedbackMsg(sender, StandardMessage.STAT_RESULTS_TOO_OLD);
} else {
outputManager.sendToAllPlayers(result.formattedValue());

View File

@ -146,7 +146,7 @@ public enum Unit {
}
}
/** Returns the most suitable timeUnit for this number.
/** Returns the most suitable Unit for this number.
@param type the Unit.Type of the statistic this number belongs to
@param number the statistic number as returned by Player.getStatistic()*/
public static Unit getMostSuitableUnit(Unit.Type type, long number) {

View File

@ -0,0 +1,31 @@
package com.gmail.artemis.the.gr8.playerstats.msg;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.RequestSettings;
import com.gmail.artemis.the.gr8.playerstats.statistic.StatCalculator;
import net.kyori.adventure.text.*;
import org.jetbrains.annotations.ApiStatus.Internal;
import java.util.LinkedHashMap;
/** The {@link InternalFormatter} formats raw numbers into pretty messages.
This ApiFormatter takes a {@link RequestSettings} object and combines it with the raw data
returned by the {@link StatCalculator}, and transforms those into a pretty message
with all the relevant information in it.*/
@Internal
public interface InternalFormatter {
/** @return a TextComponent with the following parts:
<br>[player-name]: [number] [stat-name] {sub-stat-name}*/
TextComponent formatPlayerStat(RequestSettings requestSettings, int playerStat);
/** @return a TextComponent with the following parts:
<br>[Total on] [server-name]: [number] [stat-name] [sub-stat-name]*/
TextComponent formatServerStat(RequestSettings requestSettings, 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(RequestSettings requestSettings, LinkedHashMap<String, Integer> topStats);
}

View File

@ -128,7 +128,6 @@ public final class MessageBuilder {
"Please wait for your previous lookup to finish!"));
}
//TODO Make this say amount of time left
public TextComponent stillOnShareCoolDown() {
int waitTime = config.getStatShareWaitingTime();
String minutes = waitTime == 1 ? " minute" : " minutes";
@ -177,11 +176,11 @@ public final class MessageBuilder {
}
}
/** Returns a BiFunction for a player statistic. This BiFunction will return a formattedValue,
/** Returns a BiFunction for a player statistic. This BiFunction will return a formattedComponent,
the shape of which is determined by the 2 parameters the BiFunction gets.
<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 formattedValue will be returned as is.</br>*/
<br>- If both parameters are null, the formattedComponent will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedPlayerStatFunction(int stat, @NotNull RequestSettings requestSettings) {
TextComponent playerStat = Component.text()
.append(componentFactory.playerName(requestSettings.getPlayerName(), Target.PLAYER)
@ -196,11 +195,11 @@ public final class MessageBuilder {
return getFormattingFunction(playerStat, Target.PLAYER);
}
/** Returns a BiFunction for a server statistic. This BiFunction will return a formattedValue,
/** Returns a BiFunction for a server statistic. This BiFunction will return a formattedComponent,
the shape of which is determined by the 2 parameters the BiFunction gets.
<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 formattedValue will be returned as is.</br>*/
<br>- If both parameters are null, the formattedComponent will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedServerStatFunction(long stat, @NotNull RequestSettings requestSettings) {
TextComponent serverStat = text()
.append(componentFactory.title(config.getServerTitle(), Target.SERVER))
@ -216,11 +215,11 @@ public final class MessageBuilder {
return getFormattingFunction(serverStat, Target.SERVER);
}
/** Returns a BiFunction for a top statistic. This BiFunction will return a formattedValue,
/** Returns a BiFunction for a top statistic. This BiFunction will return a formattedComponent,
the shape of which is determined by the 2 parameters the BiFunction gets.
<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 formattedValue will be returned as is.</br>*/
<br>- If both parameters are null, the formattedComponent will be returned as is.</br>*/
public BiFunction<Integer, CommandSender, TextComponent> formattedTopStatFunction(@NotNull LinkedHashMap<String, Integer> topStats, @NotNull RequestSettings requestSettings) {
final TextComponent title = getTopStatsTitleComponent(requestSettings, topStats.size());
final TextComponent shortTitle = getTopStatDescription(requestSettings, topStats.size());
@ -268,24 +267,6 @@ public final class MessageBuilder {
};
}
public TextComponent singleTopStatLine(int positionInTopList, String playerName, long statNumber, Statistic statistic) {
TextComponent.Builder topStatLineBuilder = Component.text()
.append(space())
.append(componentFactory.rankNumber(positionInTopList))
.append(space());
if (config.useDots()) {
topStatLineBuilder.append(getPlayerNameWithDotsComponent(positionInTopList, playerName));
} else {
topStatLineBuilder.append(componentFactory.playerName(playerName + ":", Target.TOP));
}
return topStatLineBuilder
.append(space())
.append(getStatNumberComponent(statistic, Target.TOP, statNumber))
.build();
}
private Component getSharerNameComponent(CommandSender sender) {
if (sender instanceof Player player) {
Component senderName = EasterEggProvider.getPlayerName(player);
@ -337,15 +318,25 @@ public final class MessageBuilder {
}
private TextComponent getPlayerNameWithDotsComponent(int positionInTopList, String playerName) {
int dots = FontUtils.getNumberOfDotsToAlign(positionInTopList + ". " + playerName, isConsoleBuilder, config.playerNameIsBold());
TextComponent.Builder nameWithDots = Component.text()
TextComponent.Builder nameBuilder = Component.text()
.append(componentFactory.playerName(playerName, Target.TOP))
.append(space());
int dots = getNumberOfDotsToAlign(positionInTopList + ". " + playerName);
if (dots >= 1) {
nameWithDots.append(componentFactory.dots().append(text(".".repeat(dots))));
nameBuilder.append(componentFactory.dots(".".repeat(dots)));
}
return nameBuilder.build();
}
private int getNumberOfDotsToAlign(String displayText) {
if (isConsoleBuilder) {
return FontUtils.getNumberOfDotsToAlignForConsole(displayText);
} else if (config.playerNameIsBold()) {
return FontUtils.getNumberOfDotsToAlignForBoldText(displayText);
} else {
return FontUtils.getNumberOfDotsToAlign(displayText);
}
return nameWithDots.build();
}
/** Depending on the config settings, return either a TranslatableComponent representing
@ -374,12 +365,11 @@ public final class MessageBuilder {
}
private TextComponent getStatNumberComponent(RequestSettings request, long statNumber) {
return getStatNumberComponent(request.getStatistic(), request.getTarget(), statNumber);
}
Statistic statistic = request.getStatistic();
Target target = request.getTarget();
Unit.Type unitType = Unit.getTypeFromStatistic(statistic);
private TextComponent getStatNumberComponent(Statistic statistic, Target target, long statNumber) {
Unit.Type statUnitType = Unit.getTypeFromStatistic(statistic);
return switch (statUnitType) {
return switch (unitType) {
case DISTANCE -> getDistanceNumberComponent(statNumber, target);
case DAMAGE -> getDamageNumberComponent(statNumber, target);
case TIME -> getTimeNumberComponent(statNumber, target);
@ -426,17 +416,16 @@ public final class MessageBuilder {
MyLogger.logMsg(
"There is something wrong with the time-units you specified, please check your config!",
true);
return componentFactory.statNumber("-", target);
return componentFactory.timeNumber(formatter.formatNumber(statNumber), target);
}
else {
String mainNumber = formatter.formatTimeNumber(statNumber, unitRange.get(0), unitRange.get(1));
if (!useHoverText) {
return componentFactory.statNumber(mainNumber, target);
return componentFactory.timeNumber(mainNumber, target);
} else {
String hoverNumber = formatter.formatTimeNumber(statNumber, unitRange.get(2), unitRange.get(3));
MyLogger.logMsg("mainNumber: " + mainNumber + ", hoverNumber: " + hoverNumber, DebugLevel.HIGH);
return componentFactory.statNumberWithHoverText(mainNumber, hoverNumber,
null, null, target);
return componentFactory.timeNumberWithHoverText(mainNumber, hoverNumber, target);
}
}
}
@ -445,6 +434,7 @@ public final class MessageBuilder {
return componentFactory.statNumber(formatter.formatNumber(statNumber), target);
}
/** Provides its own space in front of it! */
private TextComponent getStatUnitComponent(Statistic statistic, Target target) {
return switch (Unit.getTypeFromStatistic(statistic)) {
case DAMAGE -> getDamageUnit(target);
@ -453,6 +443,7 @@ public final class MessageBuilder {
};
}
/** Provides its own space in front of it! */
private TextComponent getDistanceUnit(Target target) {
Unit statUnit = Unit.fromString(config.getDistanceUnit(false));
if (config.useTranslatableComponents()) {
@ -466,6 +457,7 @@ public final class MessageBuilder {
.append(componentFactory.statUnit(statUnit.getLabel(), target));
}
/** Provides its own space in front of it! */
private TextComponent getDamageUnit(Target target) {
Unit statUnit = Unit.fromString(config.getDamageUnit(false));
if (statUnit == Unit.HEART) {

View File

@ -1,10 +1,8 @@
package com.gmail.artemis.the.gr8.playerstats.msg;
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.msg.components.ComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.statistic.request.RequestSettings;
import com.gmail.artemis.the.gr8.playerstats.msg.components.BukkitConsoleComponentFactory;
import com.gmail.artemis.the.gr8.playerstats.msg.components.PrideComponentFactory;
@ -27,9 +25,9 @@ import java.util.function.Function;
import static com.gmail.artemis.the.gr8.playerstats.enums.StandardMessage.*;
/** This class manages all PlayerStats output. It is the only place where messages are sent.
It gets the messages from a {@link MessageBuilder}, which is different for a Console as for Players
It gets its messages from a {@link MessageBuilder} configured for either a Console or for Players
(mainly to deal with the lack of hover-text, and for Bukkit consoles to make up for the lack of hex-colors).*/
public final class OutputManager implements StatFormatter {
public final class OutputManager implements InternalFormatter {
private static BukkitAudiences adventure;
private static ConfigHandler config;
@ -52,30 +50,6 @@ public final class OutputManager implements StatFormatter {
getMessageBuilders();
}
@Override
public TextComponent getPluginPrefix() {
ComponentFactory factory = new ComponentFactory(config);
return factory.pluginPrefix();
}
@Override
public TextComponent getRainbowPluginPrefix() {
ComponentFactory prideFactory = new PrideComponentFactory(config);
return prideFactory.pluginPrefix();
}
@Override
public TextComponent getPluginPrefixAsTitle() {
ComponentFactory factory = new ComponentFactory(config);
return factory.pluginPrefixAsTitle();
}
@Override
public TextComponent getRainbowPluginPrefixAsTitle() {
ComponentFactory prideFactory = new PrideComponentFactory(config);
return prideFactory.pluginPrefixAsTitle();
}
@Override
public TextComponent formatPlayerStat(@NotNull RequestSettings requestSettings, int playerStat) {
BiFunction<Integer, CommandSender, TextComponent> playerStatFunction =
@ -92,11 +66,6 @@ public final class OutputManager implements StatFormatter {
return processFunction(requestSettings.getCommandSender(), serverStatFunction);
}
@Override
public TextComponent formatSingleTopStatLine(int positionInTopList, String playerName, long statNumber, Statistic statistic) {
return messageBuilder.singleTopStatLine(positionInTopList, playerName, statNumber, statistic);
}
@Override
public TextComponent formatTopStat(@NotNull RequestSettings requestSettings, @NotNull LinkedHashMap<String, Integer> topStats) {
BiFunction<Integer, CommandSender, TextComponent> topStatFunction =

View File

@ -76,7 +76,6 @@ public class ComponentFactory {
return getColorFromString(config.getSharerNameDecoration(false));
}
/** Returns [PlayerStats]. */
public TextComponent pluginPrefix() {
return text("[")
@ -127,8 +126,8 @@ public class ComponentFactory {
getStyleFromString(config.getRankNumberDecoration(true)));
}
public TextComponent dots() {
return getComponent(null,
public TextComponent dots(String dots) {
return getComponent(dots,
getColorFromString(config.getDotsDecoration(false)),
getStyleFromString(config.getDotsDecoration(true)));
}
@ -228,13 +227,18 @@ public class ComponentFactory {
getStyleFromString(config.getStatNumberDecoration(target, true)));
}
public TextComponent statNumberWithHoverText(String mainNumber, String hoverNumber, @Nullable String hoverUnitName, @Nullable String hoverUnitKey, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, hoverUnitName, hoverUnitKey, null, target);
public TextComponent timeNumber(String prettyNumber, Target target) {
return statNumber(prettyNumber, target);
}
public TextComponent timeNumberWithHoverText(String mainNumber, String hoverNumber, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, null, null, null, target);
}
public TextComponent damageNumber(String prettyNumber, Target target) {
return statNumber(prettyNumber, target);
}
public TextComponent damageNumberWithHoverText(String mainNumber, String hoverNumber, String hoverUnitName, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, hoverUnitName, null, null, target);
}
@ -248,11 +252,11 @@ public class ComponentFactory {
}
public TextComponent distanceNumberWithHoverText(String mainNumber, String hoverNumber, String hoverUnitName, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, hoverUnitName, null, target);
return statNumberWithHoverText(mainNumber, hoverNumber, hoverUnitName, null, null, target);
}
public TextComponent distanceNumberWithTranslatableHoverText(String mainNumber, String hoverNumber, String hoverUnitKey, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, null, hoverUnitKey, target);
return statNumberWithHoverText(mainNumber, hoverNumber, null, hoverUnitKey, null, target);
}
public TextComponent statUnit(String unitName, Target target) {
@ -354,7 +358,11 @@ public class ComponentFactory {
.args(subStat));
}
private TextComponent statNumberWithHoverText(String mainNumber, String hoverNumber, @Nullable String hoverUnitName, @Nullable String hoverUnitKey, @Nullable TextComponent heartComponent, Target target) {
private TextComponent statNumberWithHoverText(String mainNumber, String hoverNumber,
@Nullable String hoverUnitName,
@Nullable String hoverUnitKey,
@Nullable TextComponent heartComponent, Target target) {
TextColor baseColor = getColorFromString(config.getStatNumberDecoration(target, false));
TextDecoration style = getStyleFromString(config.getStatNumberDecoration(target, true));

View File

@ -79,7 +79,7 @@ public class PrideComponentFactory extends ComponentFactory {
.build();
}
public TextComponent backwardsPluginPrefixComponent() {
private TextComponent backwardsPluginPrefixComponent() {
return text()
.append(MiniMessage.miniMessage()
.deserialize("<#631ae6>[</#631ae6>" +

View File

@ -8,13 +8,15 @@ public final class FontUtils {
private FontUtils() {
}
public static int getNumberOfDotsToAlign(String displayText, boolean isConsoleSender, boolean fontIsBold) {
if (isConsoleSender) {
return (int) Math.round((130.0 - MinecraftFont.Font.getWidth(displayText))/6) + 7;
} else if (!fontIsBold) {
public static int getNumberOfDotsToAlign(String displayText) {
return (int) Math.round((130.0 - MinecraftFont.Font.getWidth(displayText))/2);
} else {
}
public static int getNumberOfDotsToAlignForConsole(String displayText) {
return (int) Math.round((130.0 - MinecraftFont.Font.getWidth(displayText))/6) + 7;
}
public static int getNumberOfDotsToAlignForBoldText(String displayText) {
return (int) Math.round((130.0 - (MinecraftFont.Font.getWidth(displayText) * 1.5))/2);
}
}
}

View File

@ -5,8 +5,9 @@ import com.gmail.artemis.the.gr8.playerstats.enums.Unit;
import java.text.DecimalFormat;
/** A utility class that formats statistic numbers into something more readable.
It transforms {@link Unit} Type TIME, DAMAGE, and DISTANCE into a more Minecraft-appropriate Unit,
and adds commas to break up large numbers.*/
It transforms numbers of {@link Unit.Type} Time, Damage, and Distance into numbers
that are easier to understand (for example: from ticks to hours) and adds commas
to break up large numbers.*/
public final class NumberFormatter {
private final DecimalFormat format;

View File

@ -2,6 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.PlayerStatResult;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Material;
@ -42,11 +43,18 @@ public final class PlayerStatRequest extends StatRequest<Integer> implements Req
}
private PlayerStatResult getStatResult(RequestSettings completedRequest) {
int stat = Main.getStatCalculator()
int stat = Main
.getStatCalculator()
.getPlayerStat(completedRequest);
TextComponent prettyStat = Main.getStatFormatter()
TextComponent prettyComponent = Main
.getStatFormatter()
.formatPlayerStat(completedRequest, stat);
return new PlayerStatResult(stat, prettyStat);
String prettyString = ComponentUtils
.getTranslatableComponentSerializer()
.serialize(prettyComponent);
return new PlayerStatResult(stat, prettyComponent, prettyString);
}
}

View File

@ -82,7 +82,7 @@ public final class RequestHandler {
}
/**
This will create a {@link RequestSettings} from the provided args, with the requesting Player (or Console)
This will create a {@link RequestSettings} object from the provided args, with the requesting Player (or Console)
as CommandSender. This CommandSender will receive feedback messages if the RequestSettings could not be created.
@param args an Array of args such as a CommandSender would put in Minecraft chat:

View File

@ -2,6 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.ServerStatResult;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Material;
@ -42,11 +43,18 @@ public final class ServerStatRequest extends StatRequest<Long> implements Reques
}
private ServerStatResult getStatResult(RequestSettings completedRequest) {
long stat = Main.getStatCalculator()
long stat = Main
.getStatCalculator()
.getServerStat(completedRequest);
TextComponent prettyStat = Main.getStatFormatter()
TextComponent prettyComponent = Main
.getStatFormatter()
.formatServerStat(completedRequest, stat);
return new ServerStatResult(stat, prettyStat);
String prettyString = ComponentUtils
.getTranslatableComponentSerializer()
.serialize(prettyComponent);
return new ServerStatResult(stat, prettyComponent, prettyString);
}
}

View File

@ -2,6 +2,7 @@ package com.gmail.artemis.the.gr8.playerstats.statistic.request;
import com.gmail.artemis.the.gr8.playerstats.Main;
import com.gmail.artemis.the.gr8.playerstats.api.RequestGenerator;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import com.gmail.artemis.the.gr8.playerstats.statistic.result.TopStatResult;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Material;
@ -44,11 +45,18 @@ public final class TopStatRequest extends StatRequest<LinkedHashMap<String, Inte
}
private TopStatResult getStatResult(RequestSettings completedRequest) {
LinkedHashMap<String, Integer> stat = Main.getStatCalculator()
LinkedHashMap<String, Integer> stat = Main
.getStatCalculator()
.getTopStats(completedRequest);
TextComponent prettyStat = Main.getStatFormatter()
TextComponent prettyComponent = Main
.getStatFormatter()
.formatTopStat(completedRequest, stat);
return new TopStatResult(stat, prettyStat);
String prettyString = ComponentUtils
.getTranslatableComponentSerializer()
.serialize(prettyComponent);
return new TopStatResult(stat, prettyComponent, prettyString);
}
}

View File

@ -1,9 +1,8 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import net.kyori.adventure.text.TextComponent;
public record PlayerStatResult(int value, TextComponent formattedValue) implements StatResult<Integer> {
public record PlayerStatResult(int value, TextComponent formattedComponent, String formattedString) implements StatResult<Integer> {
@Override
public Integer getNumericalValue() {
@ -12,12 +11,11 @@ public record PlayerStatResult(int value, TextComponent formattedValue) implemen
@Override
public TextComponent getFormattedTextComponent() {
return formattedValue;
return formattedComponent;
}
@Override
public String getFormattedString() {
return ComponentUtils.getTranslatableComponentSerializer()
.serialize(formattedValue);
return formattedString;
}
}

View File

@ -1,9 +1,8 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import net.kyori.adventure.text.TextComponent;
public record ServerStatResult(long value, TextComponent formattedValue) implements StatResult<Long> {
public record ServerStatResult(long value, TextComponent formattedComponent, String formattedString) implements StatResult<Long> {
@Override
public Long getNumericalValue() {
@ -12,12 +11,11 @@ public record ServerStatResult(long value, TextComponent formattedValue) impleme
@Override
public TextComponent getFormattedTextComponent() {
return formattedValue;
return formattedComponent;
}
@Override
public String getFormattedString() {
return ComponentUtils.getTranslatableComponentSerializer()
.serialize(formattedValue);
return formattedString;
}
}

View File

@ -1,6 +1,6 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.api.Formatter;
import com.gmail.artemis.the.gr8.playerstats.api.ApiFormatter;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.TextComponent;
@ -34,9 +34,9 @@ import net.kyori.adventure.text.TextComponent;
found on <a href="https://docs.adventure.kyori.net/platform/bukkit.html">Adventure's website</a>.
<p>You can also use the provided {@link #getFormattedString()} method to get the same information
in String-format. Don't use Adventure's toString methods on the Components
- those are for debugging purposes. And finally, if you want the results to be
formatted differently, you can get an instance of the {@link Formatter}.
in String-format. Don't use Adventure's .content() or .toString() methods on the Components
- those won't get the actual message. And finally, if you want the results to be
formatted differently, you can get an instance of the {@link ApiFormatter}.
*/
public interface StatResult<T> {
@ -53,7 +53,7 @@ public interface StatResult<T> {
PlayerStats config. See class description for more information. */
TextComponent getFormattedTextComponent();
/** Turns the formatted message for the completed stat-lookup into String.
/** Gets the formatted message for the completed stat-lookup this {@link StatResult} stores.
@return a String message containing the formatted number. This message follows
the same style and color settings that are specified in the PlayerStats config,

View File

@ -1,11 +1,10 @@
package com.gmail.artemis.the.gr8.playerstats.statistic.result;
import com.gmail.artemis.the.gr8.playerstats.msg.components.ComponentUtils;
import net.kyori.adventure.text.TextComponent;
import java.util.LinkedHashMap;
public record TopStatResult(LinkedHashMap<String, Integer> value, TextComponent formattedValue) implements StatResult<LinkedHashMap<String,Integer>> {
public record TopStatResult(LinkedHashMap<String, Integer> value, TextComponent formattedComponent, String formattedString) implements StatResult<LinkedHashMap<String,Integer>> {
@Override
public LinkedHashMap<String, Integer> getNumericalValue() {
@ -14,12 +13,11 @@ public record TopStatResult(LinkedHashMap<String, Integer> value, TextComponent
@Override
public TextComponent getFormattedTextComponent() {
return formattedValue;
return formattedComponent;
}
@Override
public String getFormattedString() {
return ComponentUtils.getTranslatableComponentSerializer()
.serialize(formattedValue);
return formattedString;
}
}