PlayerStats/src/main/java/com/artemis/the/gr8/playerstats/core/msg/components/ComponentFactory.java

503 lines
20 KiB
Java

package com.artemis.the.gr8.playerstats.core.msg.components;
import com.artemis.the.gr8.playerstats.core.config.ConfigHandler;
import com.artemis.the.gr8.playerstats.core.enums.PluginColor;
import com.artemis.the.gr8.playerstats.api.enums.Target;
import com.artemis.the.gr8.playerstats.api.enums.Unit;
import com.artemis.the.gr8.playerstats.core.msg.msgutils.LanguageKeyHandler;
import com.artemis.the.gr8.playerstats.core.msg.MessageBuilder;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.util.HSVLike;
import net.kyori.adventure.util.Index;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static net.kyori.adventure.text.Component.*;
/** Creates Components with the desired formatting for the
* {@link MessageBuilder} to build messages with. This class
* can put Strings into formatted Components with TextColor
* and TextDecoration, or return empty Components with the
* desired formatting (as specified by the {@link ConfigHandler}).
*
* @see PluginColor
*/
public class ComponentFactory {
private static ConfigHandler config;
protected TextColor PREFIX; //gold
protected TextColor BRACKETS; //gray
protected TextColor UNDERSCORE; //dark_purple
protected TextColor HEARTS; //red
protected TextColor FEEDBACK_MSG; //lightest_blue
protected TextColor FEEDBACK_MSG_ACCENT; //light_blue
protected TextColor INFO_MSG; //gold
protected TextColor INFO_MSG_ACCENT_DARKEST; //medium_gold
protected TextColor INFO_MSG_ACCENT_MEDIUM; //light_gold
protected TextColor INFO_MSG_ACCENT_LIGHTEST; //lightest_blue
protected TextColor MSG_HOVER; //lightest_blue
protected TextColor MSG_CLICKED; //light_purple
public ComponentFactory() {
config = ConfigHandler.getInstance();
prepareColors();
}
protected void prepareColors() {
PREFIX = PluginColor.GOLD.getColor();
BRACKETS = PluginColor.GRAY.getColor();
UNDERSCORE = PluginColor.DARK_PURPLE.getColor();
HEARTS = PluginColor.RED.getColor();
FEEDBACK_MSG = PluginColor.LIGHTEST_BLUE.getColor();
FEEDBACK_MSG_ACCENT = PluginColor.LIGHT_BLUE.getColor();
INFO_MSG = PluginColor.GOLD.getColor();
INFO_MSG_ACCENT_DARKEST = PluginColor.MEDIUM_GOLD.getColor();
INFO_MSG_ACCENT_MEDIUM = PluginColor.LIGHT_GOLD.getColor();
INFO_MSG_ACCENT_LIGHTEST = PluginColor.LIGHTEST_BLUE.getColor();
MSG_HOVER = PluginColor.LIGHTEST_BLUE.getColor();
MSG_CLICKED = PluginColor.LIGHT_PURPLE.getColor();
}
@Contract("_ -> new")
protected @NotNull TextComponent miniMessageToComponent(String input) {
return text()
.append(MiniMessage.miniMessage().deserialize(input))
.build();
}
public boolean isConsoleFactory() {
return false;
}
public TextComponent getExampleName() {
return text("Artemis_the_gr8").color(FEEDBACK_MSG);
}
/**
* Returns [PlayerStats].
*/
public TextComponent pluginPrefix() {
return text("[")
.color(BRACKETS)
.append(text("PlayerStats").color(PREFIX))
.append(text("]"));
}
/**
* Returns [PlayerStats] surrounded by underscores on both sides.
*/
public TextComponent pluginPrefixAsTitle() {
return text("____________").color(UNDERSCORE) //12 underscores
.append(text(" ")) //4 spaces
.append(pluginPrefix())
.append(text(" "))
.append(text("____________"));
}
/**
* Returns a TextComponent with the input String as content,
* with color Gray and decoration Italic.
*/
public TextComponent subTitle(String content) {
return text(content).color(BRACKETS).decorate(TextDecoration.ITALIC);
}
/**
* Returns a TextComponents in the style of a default plugin message,
* with color Medium_Blue.
*/
public TextComponent message() {
return text().color(FEEDBACK_MSG).build();
}
public TextComponent messageAccent() {
return text().color(FEEDBACK_MSG_ACCENT).build();
}
public TextComponent infoMessageAccent() {
return text().color(INFO_MSG_ACCENT_MEDIUM).build();
}
public TextComponent title(String content, Target target) {
return getComponent(content,
getColorFromString(config.getTitleDecoration(target, false)),
getStyleFromString(config.getTitleDecoration(target, true)));
}
public TextComponent titleNumber(int number) {
return getComponent(number + "",
getColorFromString(config.getTitleNumberDecoration(false)),
getStyleFromString(config.getTitleNumberDecoration(true)));
}
public TextComponent rankNumber(int number) {
return getComponent(number + ".",
getColorFromString(config.getRankNumberDecoration(false)),
getStyleFromString(config.getRankNumberDecoration(true)));
}
public TextComponent dots(String dots) {
return getComponent(dots,
getColorFromString(config.getDotsDecoration(false)),
getStyleFromString(config.getDotsDecoration(true)));
}
public TextComponent serverName(String serverName) {
TextComponent colon = text(":").color(getColorFromString(config.getServerNameDecoration(false)));
return getComponent(serverName,
getColorFromString(config.getServerNameDecoration(false)),
getStyleFromString(config.getServerNameDecoration(true)))
.append(colon);
}
public TextComponent playerName(String playerName, Target target) {
return getComponent(playerName,
getColorFromString(config.getPlayerNameDecoration(target, false)),
getStyleFromString(config.getPlayerNameDecoration(target, true)));
}
public TextComponent sharerName(String sharerName) {
return getComponent(sharerName,
getColorFromString(config.getSharerNameDecoration(false)),
getStyleFromString(config.getSharerNameDecoration(true)));
}
public TextComponent shareButton(int shareCode) {
return surroundWithBrackets(
text("Share")
.color(FEEDBACK_MSG_ACCENT)
.clickEvent(ClickEvent.runCommand("/statshare " + shareCode))
.hoverEvent(HoverEvent.showText(text("Click here to share this statistic in chat!")
.color(INFO_MSG_ACCENT_MEDIUM))));
}
public TextComponent sharedByMessage(Component playerName) {
return surroundWithBrackets(
text().append(
getComponent("Shared by",
getColorFromString(config.getSharedByTextDecoration(false)),
getStyleFromString(config.getSharedByTextDecoration(true))))
.append(space())
.append(playerName)
.build());
}
public TextComponent statResultInHoverText(TextComponent statResult) {
return surroundWithBrackets(
text().append(text("Hover Here")
.color(MSG_CLICKED)
.decorate(TextDecoration.ITALIC)
.hoverEvent(HoverEvent.showText(statResult)))
.build());
}
/**
* @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 statAndSubStatName(String prettyStatName, @Nullable String prettySubStatName, Target target) {
TextComponent.Builder totalStatNameBuilder = getComponentBuilder(prettyStatName,
getColorFromString(config.getStatNameDecoration(target, false)),
getStyleFromString(config.getStatNameDecoration(target, true)));
TextComponent subStat = subStatName(prettySubStatName, target);
if (!subStat.equals(Component.empty())) {
totalStatNameBuilder
.append(space().decorations(TextDecoration.NAMES.values(), false))
.append(subStatName(prettySubStatName, target));
}
return totalStatNameBuilder.build();
}
/**
* Returns a TextComponent with TranslatableComponent as a child.
* */
public TextComponent statAndSubStatNameTranslatable(String statKey, @Nullable String subStatKey, Target target) {
TextComponent.Builder totalStatNameBuilder = getComponentBuilder(null,
getColorFromString(config.getStatNameDecoration(target, false)),
getStyleFromString(config.getStatNameDecoration(target, true)));
TextComponent subStat = subStatNameTranslatable(subStatKey, target);
if (LanguageKeyHandler.isNormalKeyForKillEntity(statKey)) {
return totalStatNameBuilder.append(killEntityBuilder(subStat)).build();
}
else if (LanguageKeyHandler.isNormalKeyForEntityKilledBy(statKey)) {
return totalStatNameBuilder.append(entityKilledByBuilder(subStat)).build();
}
else {
totalStatNameBuilder.append(translatable().key(statKey));
if (!subStat.equals(Component.empty())) {
totalStatNameBuilder.append(
space().decorations(TextDecoration.NAMES.values(), false)
.append(subStat));
}
return totalStatNameBuilder.build();
}
}
public TextComponent statNumber(String prettyNumber, Target target) {
return getComponent(prettyNumber,
getColorFromString(config.getStatNumberDecoration(target, false)),
getStyleFromString(config.getStatNumberDecoration(target, true)));
}
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);
}
public TextComponent damageNumberWithHeartUnitInHoverText(String mainNumber, String hoverNumber, Target target) {
return statNumberWithHoverText(mainNumber, hoverNumber, null, null, heart(), target);
}
public TextComponent distanceNumber(String prettyNumber, Target target) {
return statNumber(prettyNumber, target);
}
public TextComponent distanceNumberWithHoverText(String mainNumber, String hoverNumber, String hoverUnitName, Target 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, null, target);
}
public TextComponent statUnit(String unitName, Target target) {
TextComponent statUnit = getComponentBuilder(unitName,
getColorFromString(config.getSubStatNameDecoration(target, false)),
getStyleFromString(config.getSubStatNameDecoration(target, true)))
.build();
return surroundWithBrackets(statUnit);
}
public TextComponent statUnitTranslatable(String unitKey, Target target) {
TextComponent statUnit = getComponentBuilder(null,
getColorFromString(config.getSubStatNameDecoration(target, false)),
getStyleFromString(config.getSubStatNameDecoration(target, true)))
.append(translatable()
.key(unitKey))
.build();
return surroundWithBrackets(statUnit);
}
public TextComponent heart() {
return text()
.content(String.valueOf('\u2764'))
.color(HEARTS)
.build();
}
public TextComponent heartBetweenBrackets() {
return surroundWithBrackets(heart());
}
public TextComponent heartBetweenBracketsWithHoverText() {
TextComponent heart = heart()
.toBuilder()
.hoverEvent(HoverEvent.showText(
text(Unit.HEART.getLabel())
.color(INFO_MSG_ACCENT_MEDIUM)))
.build();
return surroundWithBrackets(heart);
}
public TextComponent arrow() {
return text("").color(INFO_MSG); //4 spaces, alt + 26
}
public TextComponent bulletPoint() {
return text("").color(INFO_MSG); //4 spaces, alt + 7
}
public TextComponent bulletPointIndented() {
return text("").color(INFO_MSG); //8 spaces, alt + 7
}
/**
* Returns a TextComponent for the subStatName, or an empty component.
*/
private TextComponent subStatName(@Nullable String prettySubStatName, Target target) {
if (prettySubStatName == null) {
return Component.empty();
} else {
return getComponentBuilder(null,
getColorFromString(config.getSubStatNameDecoration(target, false)),
getStyleFromString(config.getSubStatNameDecoration(target, true)))
.append(text("("))
.append(text(prettySubStatName))
.append(text(")"))
.build();
}
}
/**
* Returns a TranslatableComponent for the subStatName, or an empty component.
*/
private TextComponent subStatNameTranslatable(@Nullable String subStatKey, Target target) {
if (subStatKey != null) {
return getComponentBuilder(null,
getColorFromString(config.getSubStatNameDecoration(target, false)),
getStyleFromString(config.getSubStatNameDecoration(target, true)))
.append(text("("))
.append(translatable()
.key(subStatKey))
.append(text(")"))
.build();
}
return Component.empty();
}
/**
* Construct a custom translation for kill_entity with the language key
* for commands.kill.success.single ("Killed %s").
*
* @return a TranslatableComponent Builder with the subStat Component as args.
*/
private @NotNull TranslatableComponent.Builder killEntityBuilder(@NotNull TextComponent subStat) {
return translatable()
.key(LanguageKeyHandler.getCustomKeyForKillEntity()) //"Killed %s"
.args(subStat);
}
/**
* Construct a custom translation for entity_killed_by with the language
* keys for stat.minecraft.deaths ("Number of Deaths") and book.byAuthor
* ("by %s").
*
* @return a TranslatableComponent Builder with stat.minecraft.deaths as key,
* with a ChildComponent with book.byAuthor as key and the subStat Component as args.
*/
private @NotNull TranslatableComponent.Builder entityKilledByBuilder(@NotNull TextComponent subStat) {
return translatable()
.key(LanguageKeyHandler.getCustomKeyForEntityKilledBy()) //"Number of Deaths"
.append(space())
.append(translatable()
.key(LanguageKeyHandler.getCustomKeyForEntityKilledByArg()) //"by %s"
.args(subStat));
}
private @NotNull 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));
TextComponent.Builder hoverText = getComponentBuilder(hoverNumber, getLighterColor(baseColor), style);
if (heartComponent != null) {
hoverText.append(space())
.append(heartComponent);
}
else if (hoverUnitKey != null) {
hoverText.append(space())
.append(translatable().key(hoverUnitKey));
}
else if (hoverUnitName != null) {
hoverText.append(space())
.append(text(hoverUnitName));
}
return getComponent(mainNumber, baseColor, style).hoverEvent(HoverEvent.showText(hoverText));
}
private @NotNull TextComponent surroundWithBrackets(TextComponent component) {
return getComponent(null, BRACKETS, null)
.append(text("["))
.append(component)
.append(text("]"));
}
protected TextComponent getComponent(String content, @NotNull TextColor color, @Nullable TextDecoration style) {
return getComponentBuilder(content, color, style).build();
}
protected TextComponent.Builder getComponentBuilder(@Nullable String content, TextColor color, @Nullable TextDecoration style) {
TextComponent.Builder builder = text()
.decorations(TextDecoration.NAMES.values(), false)
.color(color);
if (content != null) {
builder.append(text(content));
}
if (style != null) {
builder.decorate(style);
}
return builder;
}
private TextColor getColorFromString(String configString) {
if (configString != null) {
try {
if (configString.contains("#")) {
return getHexColor(configString);
}
else {
return getTextColorByName(configString);
}
}
catch (IllegalArgumentException | NullPointerException exception) {
Bukkit.getLogger().warning(exception.toString());
}
}
return null;
}
protected TextColor getHexColor(String hexColor) {
return TextColor.fromHexString(hexColor);
}
private TextColor getTextColorByName(String textColor) {
Index<String, NamedTextColor> names = NamedTextColor.NAMES;
return names.value(textColor);
}
private @NotNull TextColor getLighterColor(@NotNull TextColor color) {
float multiplier = (float) ((100 - config.getHoverTextAmountLighter()) / 100.0);
HSVLike oldColor = HSVLike.fromRGB(color.red(), color.green(), color.blue());
HSVLike newColor = HSVLike.hsvLike(oldColor.h(), oldColor.s() * multiplier, oldColor.v());
return TextColor.color(newColor);
}
private @Nullable TextDecoration getStyleFromString(@NotNull String configString) {
if (configString.equalsIgnoreCase("none")) {
return null;
}
else if (configString.equalsIgnoreCase("magic")) {
return TextDecoration.OBFUSCATED;
}
else {
Index<String, TextDecoration> styles = TextDecoration.NAMES;
return styles.value(configString);
}
}
}