Added config support to configure time units, made min and max time unit options, took String-to-Unit converting out of ConfigHandler and put it in Unit instead

This commit is contained in:
Artemis-the-gr8 2022-07-03 15:47:51 +02:00
parent cde80fa9d2
commit f22fc6a7ed
6 changed files with 214 additions and 164 deletions

View File

@ -2,7 +2,6 @@ package com.gmail.artemis.the.gr8.playerstats.config;
import com.gmail.artemis.the.gr8.playerstats.Main;
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.utils.MyLogger;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
@ -92,48 +91,43 @@ public class ConfigHandler {
return config.getInt("number-of-days-since-last-joined", 0);
}
public Unit getStatUnit(Unit.Type unitType, boolean isHoverText) {
switch (unitType) {
case DISTANCE -> {
return isHoverText ? getDistanceUnitHoverText() : getDistanceUnit();
}
case DAMAGE -> {
return isHoverText ? getDamageUnitHoverText() : getDamageUnit();
}
default -> {
return Unit.NUMBER;
}
}
}
private Unit getDistanceUnit() {
return getUnitFromString(config.getString("distance-unit", "blocks"), Unit.BLOCK);
}
private Unit getDistanceUnitHoverText() {
return getUnitFromString(config.getString("distance-unit-hover-text", "km"), Unit.KM);
}
private Unit getDamageUnit() {
return getUnitFromString(config.getString("damage-unit", "hearts"), Unit.HEART);
}
private Unit getDamageUnitHoverText() {
return getUnitFromString(config.getString("damage-unit-hover-text", "hp"), Unit.HP);
}
/** Whether to use TranslatableComponents for statistic, block, item and entity names.
/** Whether to use TranslatableComponents wherever possible.
Currently supported: statistic, block, item and entity names.
<p>Default: true</p>*/
public boolean useTranslatableComponents() {
return config.getBoolean("translate-to-client-language", true);
}
/** Whether to use HoverComponents in the usage explanation.
/** Whether to use HoverComponents for additional information.
<p>Default: true</p>*/
public boolean useHoverText() {
return config.getBoolean("enable-hover-text", true);
}
//TODO Test these default units
public String getDistanceUnit(boolean isHoverText) {
return getUnitString(isHoverText, "blocks", "km", "distance-unit");
}
public String getDamageUnit(boolean isHoverText) {
return getUnitString(isHoverText, "hearts", "hp", "damage-unit");
}
/** By default, getTimeUnit will return the maxUnit. If the optional minUnit flag is specified,
the minimum unit will be returned instead. */
public String getTimeUnit(boolean isHoverText) {
return getTimeUnit(isHoverText, false);
}
/** By default, getTimeUnit will return the maxUnit. If the optional minUnit flag is specified,
the minimum unit will be returned instead. */
public String getTimeUnit(boolean isHoverText, boolean minUnit) {
if (minUnit) {
return getUnitString(isHoverText, "seconds", "min-time-unit");
}
return getUnitString(isHoverText, "hours", "days", "max-time-unit");
}
/** Whether to use festive formatting, such as pride colors.
<p>Default: true</p> */
public boolean useFestiveFormatting() {
@ -180,7 +174,7 @@ public class ConfigHandler {
<p>Style: "none"</p>
<p>Color Top: "green"</p>
<p>Color Individual/Server: "gold"</p>*/
public String getPlayerNameFormatting(Target selection, boolean isStyle) {
public String getPlayerNameDecoration(Target selection, boolean getStyle) {
String def;
if (selection == Target.TOP) {
def = "green";
@ -188,7 +182,7 @@ public class ConfigHandler {
else {
def = "gold";
}
return getStringFromConfig(selection, isStyle, def, "player-names");
return getDecorationString(selection, getStyle, def, "player-names");
}
/** Returns true if playerNames Style is "bold", false if it is not.
@ -206,22 +200,22 @@ public class ConfigHandler {
/** Returns a String that represents either a Chat Color, hex color code, or a Style. Default values are:
<p>Style: "none"</p>
<p>Color: "yellow"</p>*/
public String getStatNameFormatting(Target selection, boolean isStyle) {
return getStringFromConfig(selection, isStyle, "yellow", "stat-names");
public String getStatNameDecoration(Target selection, boolean getStyle) {
return getDecorationString(selection, getStyle, "yellow", "stat-names");
}
/** Returns a String that represents either a Chat Color, hex color code, or a Style. Default values are:
<p>Style: "none"</p>
<p>Color: "#FFD52B"</p>*/
public String getSubStatNameFormatting(Target selection, boolean isStyle) {
return getStringFromConfig(selection, isStyle, "#FFD52B", "sub-stat-names");
public String getSubStatNameDecoration(Target selection, boolean getStyle) {
return getDecorationString(selection, getStyle, "#FFD52B", "sub-stat-names");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color Top: "#55AAFF"</p>
<p>Color Individual/Server: "#ADE7FF"</p> */
public String getStatNumberFormatting(Target selection, boolean isStyle) {
public String getStatNumberDecoration(Target selection, boolean getStyle) {
String def;
if (selection == Target.TOP) {
def = "#55AAFF";
@ -229,14 +223,14 @@ public class ConfigHandler {
else {
def = "#ADE7FF";
}
return getStringFromConfig(selection, isStyle, def,"stat-numbers");
return getDecorationString(selection, getStyle, def,"stat-numbers");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color Top: "yellow"</p>
<p>Color Server: "gold"</p>*/
public String getTitleFormatting(Target selection, boolean isStyle) {
public String getTitleDecoration(Target selection, boolean getStyle) {
String def;
if (selection == Target.TOP) {
def = "yellow";
@ -244,72 +238,76 @@ public class ConfigHandler {
else {
def = "gold";
}
return getStringFromConfig(selection, isStyle, def, "title");
return getDecorationString(selection, getStyle, def, "title");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color: "gold"</p>*/
public String getTitleNumberFormatting(boolean isStyle) {
return getStringFromConfig(Target.TOP, isStyle, "gold", "title-number");
public String getTitleNumberDecoration(boolean getStyle) {
return getDecorationString(Target.TOP, getStyle, "gold", "title-number");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color: "#FFB80E"</p>*/
public String getServerNameFormatting(boolean isStyle) {
return getStringFromConfig(Target.SERVER, isStyle, "#FFB80E", "server-name");
public String getServerNameDecoration(boolean getStyle) {
return getDecorationString(Target.SERVER, getStyle, "#FFB80E", "server-name");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color: "gold"</p>*/
public String getRankNumberFormatting(boolean isStyle) {
return getStringFromConfig(Target.TOP, isStyle, "gold", "rank-numbers");
public String getRankNumberDecoration(boolean getStyle) {
return getDecorationString(Target.TOP, getStyle, "gold", "rank-numbers");
}
/** Returns a String that represents either a Chat Color, hex color code, or Style. Default values are:
<p>Style: "none"</p>
<p>Color: "dark_gray"</p> */
public String getDotsFormatting(boolean isStyle) {
return getStringFromConfig(Target.TOP, isStyle, "dark_gray", "dots");
public String getDotsDecoration(boolean getStyle) {
return getDecorationString(Target.TOP, getStyle, "dark_gray", "dots");
}
/** Returns the config value for a color or style option in string-format, the supplied default value, or null if no configSection was found. */
private @Nullable String getStringFromConfig(Target selection, boolean isStyle, String def, String pathName){
String path = isStyle ? pathName + "-style" : pathName;
String defaultValue = isStyle ? "none" : def;
/** Returns a String representing the Unit that should be used for a certain Unit.Type.
If no String can be retrieved from the config, the supplied defaultValue will be returned.
@param isHoverText if true, the unit for hovering text is returned, otherwise the unit for plain text
@param defaultValue the default unit for plain text
@param pathName the config path to retrieve the value from*/
private String getUnitString(boolean isHoverText, String defaultValue, String pathName) {
return getUnitString(isHoverText, defaultValue, null, pathName);
}
/** Returns a String representing the Unit that should be used for a certain Unit.Type.
If no String can be retrieved from the config, the supplied defaultValue will be returned.
If the defaultValue is different for hoverText, an optional String defaultHoverValue can be supplied.
@param isHoverText if true, the unit for hovering text is returned, otherwise the unit for plain text
@param defaultValue the default unit for plain text
@param defaultHoverValue the default unit for hovering text
@param pathName the config path to retrieve the value from*/
private String getUnitString(boolean isHoverText, String defaultValue, String defaultHoverValue, String pathName) {
String path = isHoverText ? pathName + "-for-hover-text" : pathName;
String def = defaultValue;
if (isHoverText && defaultHoverValue != null) {
def = defaultHoverValue;
}
return config.getString(path, def);
}
/** Returns the config value for a color or style option in string-format, the supplied default value,
or null if no configSection was found.
@param selection the Target this decoration is meant for (Player, Server or Top)
@param getStyle if true, the result will be a style String, otherwise a color String
@param defaultColor the default color to return if the config value cannot be found (for style, the default is always "none")
@param pathName the config path to retrieve the value from*/
private @Nullable String getDecorationString(Target selection, boolean getStyle, String defaultColor, String pathName){
String path = getStyle ? pathName + "-style" : pathName;
String defaultValue = getStyle ? "none" : defaultColor;
ConfigurationSection section = getRelevantSection(selection);
return section != null ? section.getString(path, defaultValue) : null;
}
private Unit getUnitFromString(String unitString, Unit defaultUnit) {
switch (unitString.toLowerCase()) {
case "cm" -> {
return Unit.CM;
}
case "m", "block", "blocks" -> {
return Unit.BLOCK;
}
case "mile", "miles" -> {
return Unit.MILE;
}
case "km" -> {
return Unit.KM;
}
case "hp" -> {
return Unit.HP;
}
case "heart", "hearts" -> {
return Unit.HEART;
}
default -> {
return defaultUnit;
}
}
}
/** Returns the config section that contains the relevant color or style option. */
private @Nullable ConfigurationSection getRelevantSection(Target selection) {
switch (selection) {

View File

@ -28,29 +28,10 @@ public enum Unit {
this.type = type;
}
public Type type() {
public Type getType() {
return type;
}
public static @NotNull Type getType(Statistic statistic) {
return getType(statistic.toString());
}
/** Returns the Unit.Type of this Statistic, which can be Untyped, Distance, Damage, or Time.
@param statName the name of the Statistic enum constant in String*/
public static @NotNull Type getType(String statName) {
String name = statName.toLowerCase();
if (name.contains("one_cm")) {
return Type.DISTANCE;
} else if (name.contains("damage")) {
return Type.DAMAGE;
} else if (name.contains("time") || name.contains("one_minute")) {
return Type.TIME;
} else {
return Type.UNTYPED;
}
}
/** Returns a pretty name belonging to this enum constant. If the Unit is
NUMBER, it will return an empty String. */
public @NotNull String getName() throws NullPointerException {
@ -68,34 +49,97 @@ public enum Unit {
return "km";
}
case HP -> {
return "HP";
return "HP";
}
case HEART -> {
return "Hearts";
return "Hearts";
}
case TICK -> {
return "ticks";
return "ticks";
}
case SECOND -> {
return "seconds";
return "seconds";
}
case MINUTE -> {
return "minutes";
return "minutes";
}
case DAY -> {
return "days";
return "days";
}
case HOUR -> {
return "hours";
return "hours";
}
case WEEK -> {
return "weeks";
return "weeks";
}
case NUMBER -> {
return "";
}
default ->
throw new NullPointerException("Trying to get the name of an enum constant that does not exist!");
throw new NullPointerException("Trying to get the name of an enum constant that does not exist!");
}
}
public Unit fromString(String unitName) {
switch (unitName.toLowerCase()) {
case "cm" -> {
return Unit.CM;
}
case "m", "block", "blocks" -> {
return Unit.BLOCK;
}
case "mile", "miles" -> {
return Unit.MILE;
}
case "km" -> {
return Unit.KM;
}
case "hp" -> {
return Unit.HP;
}
case "heart", "hearts" -> {
return Unit.HEART;
}
case "week", "weeks" -> {
return Unit.WEEK;
}
case "day", "days" -> {
return Unit.DAY;
}
case "hour", "hours" -> {
return Unit.HOUR;
}
case "minute", "minutes", "min" -> {
return Unit.MINUTE;
}
case "second", "seconds", "sec" -> {
return Unit.SECOND;
}
case "tick", "ticks" -> {
return Unit.TICK;
}
default -> {
return Unit.NUMBER;
}
}
}
public static @NotNull Type fromStatistic(Statistic statistic) {
return fromStatName(statistic.toString());
}
/** Returns the Unit.Type of this Statistic, which can be Untyped, Distance, Damage, or Time.
@param statName the name of the Statistic enum constant in String*/
public static @NotNull Type fromStatName(String statName) {
String name = statName.toLowerCase();
if (name.contains("one_cm")) {
return Type.DISTANCE;
} else if (name.contains("damage")) {
return Type.DAMAGE;
} else if (name.contains("time") || name.contains("one_minute")) {
return Type.TIME;
} else {
return Type.UNTYPED;
}
}

View File

@ -69,16 +69,16 @@ public class ComponentFactory {
public TextComponent.Builder playerNameBuilder(String playerName, Target selection) {
return getComponentBuilder(playerName,
getColorFromString(config.getPlayerNameFormatting(selection, false)),
getStyleFromString(config.getPlayerNameFormatting(selection, true)));
getColorFromString(config.getPlayerNameDecoration(selection, false)),
getStyleFromString(config.getPlayerNameDecoration(selection, true)));
}
/** @param prettyStatName a statName with underscores removed and each word capitalized
@param prettySubStatName if present, a subStatName with underscores removed and each word capitalized*/
public TextComponent statNameTextComponent(String prettyStatName, @Nullable String prettySubStatName, Target selection) {
TextComponent.Builder totalStatNameBuilder = getComponentBuilder(prettyStatName,
getColorFromString(config.getStatNameFormatting(selection, false)),
getStyleFromString(config.getStatNameFormatting(selection, true)));
getColorFromString(config.getStatNameDecoration(selection, false)),
getStyleFromString(config.getStatNameDecoration(selection, true)));
TextComponent subStat = subStatNameTextComponent(prettySubStatName, selection);
if (!subStat.equals(Component.empty())) {
@ -95,8 +95,8 @@ public class ComponentFactory {
return Component.empty();
} else {
return getComponentBuilder(null,
getColorFromString(config.getSubStatNameFormatting(selection, false)),
getStyleFromString(config.getSubStatNameFormatting(selection, true)))
getColorFromString(config.getSubStatNameDecoration(selection, false)),
getStyleFromString(config.getSubStatNameDecoration(selection, true)))
.append(text("("))
.append(text(prettySubStatName))
.append(text(")"))
@ -107,8 +107,8 @@ public class ComponentFactory {
/** Returns a TextComponent with TranslatableComponent as a child.*/
public TextComponent statNameTransComponent(@NotNull StatRequest request) {
TextComponent.Builder totalStatNameBuilder = getComponentBuilder(null,
getColorFromString(config.getStatNameFormatting(request.getSelection(), false)),
getStyleFromString(config.getStatNameFormatting(request.getSelection(), true)));
getColorFromString(config.getStatNameDecoration(request.getSelection(), false)),
getStyleFromString(config.getStatNameDecoration(request.getSelection(), true)));
TextComponent subStat = subStatNameTransComponent(request);
String statName = languageKeyHandler.getStatKey(request.getStatistic());
@ -142,8 +142,8 @@ public class ComponentFactory {
}
if (subStatName != null) {
return getComponentBuilder(null,
getColorFromString(config.getSubStatNameFormatting(request.getSelection(), false)),
getStyleFromString(config.getSubStatNameFormatting(request.getSelection(), true)))
getColorFromString(config.getSubStatNameDecoration(request.getSelection(), false)),
getStyleFromString(config.getSubStatNameDecoration(request.getSelection(), true)))
.append(text("("))
.append(translatable()
.key(subStatName))
@ -178,13 +178,13 @@ public class ComponentFactory {
//TODO Add hoverComponent with full number
public TextComponent.Builder statNumberComponent(String number, Target selection) {
return getComponentBuilder(number,
getColorFromString(config.getStatNumberFormatting(selection, false)),
getStyleFromString(config.getStatNumberFormatting(selection, true)));
getColorFromString(config.getStatNumberDecoration(selection, false)),
getStyleFromString(config.getStatNumberDecoration(selection, true)));
}
public TextComponent statNumberHoverComponent(String mainNumber, String hoverNumber, Unit hoverUnit, Target selection, boolean isTranslatable) {
TextColor baseColor = getColorFromString(config.getStatNumberFormatting(selection, false));
TextDecoration style = getStyleFromString(config.getStatNumberFormatting(selection, true));
TextColor baseColor = getColorFromString(config.getStatNumberDecoration(selection, false));
TextDecoration style = getStyleFromString(config.getStatNumberDecoration(selection, true));
TextComponent.Builder hoverText = getComponentBuilder(hoverNumber, getLighterColor(baseColor), style);
if (isTranslatable) {
String unitKey = languageKeyHandler.getUnitKey(hoverUnit);
@ -203,10 +203,10 @@ public class ComponentFactory {
//TODO Make this dark gray (or at least darker than statNumber, and at least for time statistics)
public TextComponent statUnitComponent(Unit statUnit, Target selection, boolean isTranslatable) {
if (statUnit.type() != Unit.Type.UNTYPED) {
if (statUnit.getType() != Unit.Type.UNTYPED) {
TextComponent.Builder statUnitBuilder = getComponentBuilder(null,
getColorFromString(config.getSubStatNameFormatting(selection, false)),
getStyleFromString(config.getSubStatNameFormatting(selection, true)))
getColorFromString(config.getSubStatNameDecoration(selection, false)),
getStyleFromString(config.getSubStatNameDecoration(selection, true)))
.append(text("["));
if (isTranslatable) {
String unitKey = languageKeyHandler.getUnitKey(statUnit);
@ -226,34 +226,34 @@ public class ComponentFactory {
public TextComponent titleComponent(String content, Target selection) {
return getComponent(content,
getColorFromString(config.getTitleFormatting(selection, false)),
getStyleFromString(config.getTitleFormatting(selection, true)));
getColorFromString(config.getTitleDecoration(selection, false)),
getStyleFromString(config.getTitleDecoration(selection, true)));
}
public TextComponent titleNumberComponent(int number) {
return getComponent(number + "",
getColorFromString(config.getTitleNumberFormatting(false)),
getStyleFromString(config.getTitleNumberFormatting(true)));
getColorFromString(config.getTitleNumberDecoration(false)),
getStyleFromString(config.getTitleNumberDecoration(true)));
}
public TextComponent serverNameComponent(String serverName) {
TextComponent colon = text(":").color(getColorFromString(config.getServerNameFormatting(false)));
TextComponent colon = text(":").color(getColorFromString(config.getServerNameDecoration(false)));
return getComponent(serverName,
getColorFromString(config.getServerNameFormatting(false)),
getStyleFromString(config.getServerNameFormatting(true)))
getColorFromString(config.getServerNameDecoration(false)),
getStyleFromString(config.getServerNameDecoration(true)))
.append(colon);
}
public TextComponent rankingNumberComponent(String number) {
return getComponent(number,
getColorFromString(config.getRankNumberFormatting(false)),
getStyleFromString(config.getRankNumberFormatting(true)));
getColorFromString(config.getRankNumberDecoration(false)),
getStyleFromString(config.getRankNumberDecoration(true)));
}
public TextComponent.Builder dotsBuilder() {
return getComponentBuilder(null,
getColorFromString(config.getDotsFormatting(false)),
getStyleFromString(config.getDotsFormatting(true)));
getColorFromString(config.getDotsDecoration(false)),
getStyleFromString(config.getDotsDecoration(true)));
}
private TextComponent getComponent(String content, TextColor color, @Nullable TextDecoration style) {

View File

@ -113,7 +113,7 @@ public class MessageWriter {
.append(getStatNameComponent(request))
.append(space())
.append(componentFactory.statUnitComponent(
config.getStatUnit(Unit.getType(request.getStatistic()), false),
config.getStatUnit(Unit.fromStatistic(request.getStatistic()), false),
Target.PLAYER,
config.useTranslatableComponents()))
.build();
@ -128,7 +128,7 @@ public class MessageWriter {
.append(getStatNameComponent(request))
.append(space())
.append(componentFactory.statUnitComponent(
config.getStatUnit(Unit.getType(request.getStatistic()), false),
config.getStatUnit(Unit.fromStatistic(request.getStatistic()), false),
Target.TOP,
config.useTranslatableComponents()));
@ -184,7 +184,7 @@ public class MessageWriter {
.append(getStatNameComponent(request))
.append(space())
.append(componentFactory.statUnitComponent(
config.getStatUnit(Unit.getType(request.getStatistic()), false),
config.getStatUnit(Unit.fromStatistic(request.getStatistic()), false),
Target.SERVER,
config.useTranslatableComponents()))
.build();
@ -204,7 +204,7 @@ public class MessageWriter {
}
private TextComponent getStatNumberComponent(Statistic statistic, long statNumber, Target selection) {
Unit.Type type = Unit.getType(statistic);
Unit.Type type = Unit.fromStatistic(statistic);
Unit baseUnit = config.getStatUnit(type, false);
String prettyNumber = formatter.format(statNumber, baseUnit);
if (config.useHoverText() && type != Unit.Type.UNTYPED) {

View File

@ -18,7 +18,7 @@ public class NumberFormatter {
(number-of-times, time-, damage- or distance-based) according to the
corresponding config settings, and adds commas in groups of 3.*/
public String format(long number, Unit statUnit) {
switch (statUnit.type()) {
switch (statUnit.getType()) {
case DISTANCE -> {
return formatDistance(number, statUnit);
}
@ -73,27 +73,25 @@ public class NumberFormatter {
if (leftover >= 86400) {
double days = leftover / 60 / 60 / 24;
if (days > 999) {
output.append(format.format(Math.round(days)));
}
else {
output.append(days);
}
output.append("D ");
output.append(format.format(Math.round(days)))
.append("D ");
leftover = leftover % (60 * 60 * 24);
}
if (leftover >= 3600) {
double hours = leftover / 60 / 60;
output.append(hours).append("H ");
output.append(format.format(Math.round(hours)))
.append("H ");
leftover = leftover % (60 * 60);
}
if (leftover >= 60) {
double minutes = leftover / 60;
output.append(minutes).append("M ");
output.append(format.format(Math.round(minutes)))
.append("M ");
leftover = leftover % 60;
}
if (leftover > 0) {
output.append(leftover).append("S");
output.append(format.format(Math.round(leftover)))
.append("S");
}
return output.toString();
}

View File

@ -10,7 +10,7 @@ config-version: 5
# How much output you'll get in the server console while PlayerStats is processing
# 1 = low (only show unexpected errors)
# 2 = medium (detail all encountered exceptions, log main tasks and show time taken)
# 2 = medium (log main tasks and time taken)
# 3 = high (log all tasks and time taken)
debug-level: 1
@ -27,22 +27,32 @@ number-of-days-since-last-joined: 0
# # Format & Display # #
# # ------------------------------- # #
# The unit to display certain statistics in.
# Minecraft measures distance in cm. PlayerStats supports the following units: blocks, cm, m (= blocks), miles & km
distance-unit: blocks
distance-unit-hover-text: km
# Minecraft measures damage in 0.5 hearts (1HP). PlayerStats supports the following units: hp, hearts
damage-unit: hearts
damage-unit-hover-text: hp
# Display all statistic, block, item and entity names in the client language of the receiving player
# The actual translation is handled by the Minecraft language files and happens automatically
translate-to-client-language: true
# Use hover-text for additional info in the usage explanation
# Use hover-text for additional info about statistic numbers
enable-hover-text: true
# The unit to display certain statistics in.
# Minecraft measures distance in cm. PlayerStats supports: blocks, cm, m (= blocks), miles, km
distance-unit: blocks
distance-unit-for-hover-text: km
# Minecraft measures damage in 0.5 hearts (1HP). PlayerStats supports: hp, hearts
damage-unit: hearts
damage-unit-for-hover-text: hp
# Minecraft measures time in ticks. PlayerStats supports: weeks, days, hours, minutes, seconds, ticks
# Below you can choose a range between the maximum and minimum unit you want to see
# If the max and min are the same, only that unit will be displayed
# For example, 5.000.000 ticks would become "4D", "3D 21H 27M 40S", "69H 27M 40S", "4168M", etc.
max-time-unit: hours
min-time-unit: seconds
max-time-unit-for-hover-text: days
min-time-unit-for-hover-text: seconds
# Automatically use themed formatting for the duration of certain holidays or festivals
enable-festive-formatting: true