Refactor and javadoc pandalib-chat
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,55 @@ | ||||
| package fr.pandacube.lib.chat; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import net.kyori.adventure.text.format.TextColor; | ||||
|  | ||||
| /** | ||||
|  * A custom gradient with a least 2 colors in it. | ||||
|  */ | ||||
| public class ChatColorGradient { | ||||
|     private record GradientColor(float location, TextColor color) { } | ||||
|  | ||||
|     private final List<GradientColor> colors = new ArrayList<>(); | ||||
|  | ||||
|     /** | ||||
|      * Put a specific color at a specific location in the gradient. | ||||
|      * @param gradientLocation the location in the gradient. | ||||
|      * @param gradientColor the color to put at this location. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public synchronized ChatColorGradient add(float gradientLocation, TextColor gradientColor) { | ||||
|         colors.add(new GradientColor(gradientLocation, gradientColor)); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compute a color by interpolating between the 2 colors surrounding the provided location. | ||||
|      * @param gradientLocation the location at which to pick the gradient color. | ||||
|      * @return the computed color. | ||||
|      */ | ||||
|     public synchronized TextColor pickColorAt(float gradientLocation) { | ||||
|         if (colors.isEmpty()) | ||||
|             throw new IllegalStateException("Must define at least one color in this ChatValueGradient instance."); | ||||
|         if (colors.size() == 1) | ||||
|             return colors.get(0).color(); | ||||
|  | ||||
|         colors.sort((p1, p2) -> Float.compare(p1.location(), p2.location())); | ||||
|  | ||||
|         if (gradientLocation <= colors.get(0).location()) | ||||
|             return colors.get(0).color(); | ||||
|         if (gradientLocation >= colors.get(colors.size() - 1).location()) | ||||
|             return colors.get(colors.size() - 1).color(); | ||||
|  | ||||
|         int p1 = 1; | ||||
|         for (; p1 < colors.size(); p1++) { | ||||
|             if (colors.get(p1).location() >= gradientLocation) | ||||
|                 break; | ||||
|         } | ||||
|         int p0 = p1 - 1; | ||||
|         float v0 = colors.get(p0).location(), v1 = colors.get(p1).location(); | ||||
|         TextColor cc0 = colors.get(p0).color(), cc1 = colors.get(p1).color(); | ||||
|         return ChatColorUtil.interpolateColor(v0, v1, gradientLocation, cc0, cc1); | ||||
|     } | ||||
| } | ||||
| @@ -1,30 +1,37 @@ | ||||
| package fr.pandacube.lib.chat; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import net.kyori.adventure.text.format.NamedTextColor; | ||||
| import net.kyori.adventure.text.format.TextColor; | ||||
| import net.kyori.adventure.util.RGBLike; | ||||
| import net.md_5.bungee.api.ChatColor; | ||||
|  | ||||
| /** | ||||
|  * Provides methods to manipulate legacy colors and {@link ChatColor} class. | ||||
|  */ | ||||
| public class ChatColorUtil { | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
|     public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoPpRr"; | ||||
|     /** | ||||
|      * All characters that represent a colorcode. | ||||
|      */ | ||||
|     public static final String ALL_COLORS = "0123456789AaBbCcDdEeFf"; | ||||
|     /** | ||||
|      * All characters that represent a color or format code. | ||||
|      */ | ||||
|     public static final String ALL_CODES = ALL_COLORS + "KkLlMmNnOoPpRr"; | ||||
|  | ||||
|  | ||||
|     private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("§x(?>§[\\da-f]){6}", Pattern.CASE_INSENSITIVE); | ||||
|     private static final Pattern ESS_COLOR_PATTERN = Pattern.compile("§#[\\da-f]{6}", Pattern.CASE_INSENSITIVE); | ||||
|  | ||||
|     /** | ||||
|      * Return the legacy format needed to reproduce the format at the end of the provided legacy text. | ||||
|      * Returns the legacy format needed to reproduce the format at the end of the provided legacy text. | ||||
|      * Supports standard chat colors and formats, BungeeCord Chat rgb format and EssentialsX rgb format. | ||||
|      * The RGB value from EssentialsX format is converted to BungeeCord Chat when included in the returned value. | ||||
|      * @param legacyText the legacy formated text. | ||||
|      * @return the active format at the end of the provided text. | ||||
|      */ | ||||
|     public static String getLastColors(String legacyText) { | ||||
|         StringBuilder result = new StringBuilder(); | ||||
| @@ -76,6 +83,11 @@ public class ChatColorUtil { | ||||
|         return result.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the {@link ChatColor} associated with the provided char, case insensitive. | ||||
|      * @param code the case insensitive char code. | ||||
|      * @return the corresponding {@link ChatColor}. | ||||
|      */ | ||||
|     public static ChatColor getChatColorByChar(char code) { | ||||
|         return ChatColor.getByChar(Character.toLowerCase(code)); | ||||
|     } | ||||
| @@ -84,8 +96,8 @@ public class ChatColorUtil { | ||||
|  | ||||
|  | ||||
|     /** | ||||
| 	 * Translate the color code of the provided string, that uses the the color char, to | ||||
| 	 * the {@code §} color code format. | ||||
|      * Translate the color code of the provided string, that uses the alt color char, to the {@code §} color code | ||||
|      * format. | ||||
|      * <p> | ||||
|      * This method is the improved version of {@link ChatColor#translateAlternateColorCodes(char, String)}, | ||||
|      * because it takes into account essentials RGB color code, and {@code altColorChar} escaping (by doubling it). | ||||
| @@ -94,6 +106,9 @@ public class ChatColorUtil { | ||||
|      * <p> | ||||
|      * This method should be used for user input (no permission check) or string configuration, but not string | ||||
|      * from another API or containing URLs. | ||||
|      * @param altColorChar the alternative character to prefix color codes (usually {@code '&'}). | ||||
|      * @param textToTranslate the text to translate. | ||||
|      * @return the string translated to proper legacy text. | ||||
|      */ | ||||
|     public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) | ||||
|     { | ||||
| @@ -161,8 +176,8 @@ public class ChatColorUtil { | ||||
|     /** | ||||
|      * Force a text to be italic, while keeping other formatting and colors. | ||||
|      * The text is prefixed with the ITALIC tag, but is not reset at the end. | ||||
| 	 * @param legacyText the original text | ||||
| 	 * @return the text fully italic | ||||
|      * @param legacyText the original text. | ||||
|      * @return the text fully italic. | ||||
|      */ | ||||
|     public static String forceItalic(String legacyText) { | ||||
|         return forceFormat(legacyText, ChatColor.ITALIC); | ||||
| @@ -171,8 +186,8 @@ public class ChatColorUtil { | ||||
|     /** | ||||
|      * Force a text to be bold, while keeping other formatting and colors. | ||||
|      * The text is prefixed with the BOLD tag, but is not reset at the end. | ||||
| 	 * @param legacyText the original text | ||||
| 	 * @return the text fully bold | ||||
|      * @param legacyText the original text. | ||||
|      * @return the text fully bold. | ||||
|      */ | ||||
|     public static String forceBold(String legacyText) { | ||||
|         return forceFormat(legacyText, ChatColor.BOLD); | ||||
| @@ -181,8 +196,8 @@ public class ChatColorUtil { | ||||
|     /** | ||||
|      * Force a text to be underlined, while keeping other formatting and colors. | ||||
|      * The text is prefixed with the UNDERLINE tag, but is not reset at the end. | ||||
| 	 * @param legacyText the original text | ||||
| 	 * @return the text fully underlined | ||||
|      * @param legacyText the original text. | ||||
|      * @return the text fully underlined. | ||||
|      */ | ||||
|     public static String forceUnderline(String legacyText) { | ||||
|         return forceFormat(legacyText, ChatColor.UNDERLINE); | ||||
| @@ -191,8 +206,8 @@ public class ChatColorUtil { | ||||
|     /** | ||||
|      * Force a text to be stroked through, while keeping other formatting and colors. | ||||
|      * The text is prefixed with the STRIKETHROUGH tag, but is not reset at the end. | ||||
| 	 * @param legacyText the original text | ||||
| 	 * @return the text fully stroked through | ||||
|      * @param legacyText the original text. | ||||
|      * @return the text fully stroked through. | ||||
|      */ | ||||
|     public static String forceStrikethrough(String legacyText) { | ||||
|         return forceFormat(legacyText, ChatColor.STRIKETHROUGH); | ||||
| @@ -201,8 +216,8 @@ public class ChatColorUtil { | ||||
|     /** | ||||
|      * Force a text to be obfuscated, while keeping other formatting and colors. | ||||
|      * The text is prefixed with the MAGIC tag, but is not reset at the end. | ||||
| 	 * @param legacyText the original text | ||||
| 	 * @return the text fully obfuscated | ||||
|      * @param legacyText the original text. | ||||
|      * @return the text fully obfuscated. | ||||
|      */ | ||||
|     public static String forceObfuscated(String legacyText) { | ||||
|         return forceFormat(legacyText, ChatColor.MAGIC); | ||||
| @@ -224,8 +239,8 @@ public class ChatColorUtil { | ||||
|      * Replace the RESET tag of the input string to the specified color tag. | ||||
|      * @param legacyText the original text | ||||
|      * @param color the color to used to replace the RESET tag | ||||
| 	 * 			(can be a combination of a color tag followed by multiple format tag) | ||||
| 	 * @return the resulting text | ||||
|      * 			(can be a combination of a color tag followed by multiple format tag). | ||||
|      * @return the resulting text. | ||||
|      */ | ||||
|     public static String resetToColor(String legacyText, String color) { | ||||
|         return legacyText.replace(ChatColor.RESET.toString(), color); | ||||
| @@ -234,6 +249,11 @@ public class ChatColorUtil { | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Converts the provided {@link ChatColor} to its Adventure counterpart. | ||||
|      * @param bungee a BungeeCord {@link ChatColor} instance. | ||||
|      * @return the {@link TextColor} equivalent to the provided {@link ChatColor}. | ||||
|      */ | ||||
|     public static TextColor toAdventure(ChatColor bungee) { | ||||
|         if (bungee == null) | ||||
|             return null; | ||||
| @@ -242,6 +262,11 @@ public class ChatColorUtil { | ||||
|         return TextColor.color(bungee.getColor().getRGB()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts the provided {@link TextColor} to its BungeeCord counterpart. | ||||
|      * @param col a Adventure {@link TextColor} instance. | ||||
|      * @return the {@link ChatColor} equivalent to the provided {@link TextColor}. | ||||
|      */ | ||||
|     public static ChatColor toBungee(TextColor col) { | ||||
|         if (col == null) | ||||
|             return null; | ||||
| @@ -252,52 +277,20 @@ public class ChatColorUtil { | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
|     /** | ||||
|      * Create a color, interpolating between 2 colors. | ||||
|      * @param v0 the value corresponding to color {@code cc0}. | ||||
|      * @param v1 the value corresponding to color {@code cc1}. | ||||
|      * @param v the value between {@code v0} and {@code v1} to interpolate. | ||||
|      * @param cc0 the first color. | ||||
|      * @param cc1 the second color. | ||||
|      * @return the interpolated color. | ||||
|      * @see TextColor#lerp(float, RGBLike, RGBLike) | ||||
|      */ | ||||
|     public static TextColor interpolateColor(float v0, float v1, float v, TextColor cc0, TextColor cc1) { | ||||
|         float normV = (v - v0) / (v1 - v0); | ||||
|         return TextColor.lerp(normV, cc0, cc1); | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	public static class ChatValueGradient { | ||||
| 		private record GradientValueColor(float value, TextColor color) { } // Java 16 | ||||
| 		 | ||||
| 		final List<GradientValueColor> colors = new ArrayList<>(); | ||||
| 		 | ||||
| 		public synchronized ChatValueGradient add(float v, TextColor col) { | ||||
| 			colors.add(new GradientValueColor(v, col)); | ||||
| 			return this; | ||||
| 		} | ||||
| 		 | ||||
| 		public synchronized TextColor pickColorAt(float v) { | ||||
| 			if (colors.isEmpty()) | ||||
| 				throw new IllegalStateException("Must define at least one color in this ChatValueGradient instance."); | ||||
| 			if (colors.size() == 1) | ||||
| 				return colors.get(0).color(); | ||||
| 			 | ||||
| 			colors.sort((p1, p2) -> Float.compare(p1.value(), p2.value())); | ||||
| 			 | ||||
| 			if (v <= colors.get(0).value()) | ||||
| 				return colors.get(0).color(); | ||||
| 			if (v >= colors.get(colors.size() - 1).value()) | ||||
| 				return colors.get(colors.size() - 1).color(); | ||||
| 			 | ||||
| 			int p1 = 1; | ||||
| 			for (; p1 < colors.size(); p1++) { | ||||
| 				if (colors.get(p1).value() >= v) | ||||
| 					break; | ||||
| 			} | ||||
| 			int p0 = p1 - 1; | ||||
| 			float v0 = colors.get(p0).value(), v1 = colors.get(p1).value(); | ||||
| 			TextColor cc0 = colors.get(p0).color(), cc1 = colors.get(p1).color(); | ||||
| 			return interpolateColor(v0, v1, v, cc0, cc1); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| @@ -0,0 +1,90 @@ | ||||
| package fr.pandacube.lib.chat; | ||||
|  | ||||
| import java.util.function.Supplier; | ||||
|  | ||||
| import net.kyori.adventure.text.format.NamedTextColor; | ||||
| import net.kyori.adventure.text.format.TextColor; | ||||
|  | ||||
| /** | ||||
|  * Class holding static configuration values for chat component rendering. | ||||
|  */ | ||||
| public class ChatConfig { | ||||
|  | ||||
|     /** | ||||
|      * The color used for decoration. | ||||
|      */ | ||||
|     public static TextColor decorationColor = NamedTextColor.YELLOW; | ||||
|  | ||||
|     /** | ||||
|      * The character used as a pattern for decoration. | ||||
|      */ | ||||
|     public static char decorationChar = '-'; | ||||
|  | ||||
|     /** | ||||
|      * The default margin for left and right aligned text. | ||||
|      */ | ||||
|     public static int nbCharMargin = 1; | ||||
|  | ||||
|     /** | ||||
|      * The color used for successful messages. | ||||
|      */ | ||||
|     public static TextColor successColor = NamedTextColor.GREEN; | ||||
|  | ||||
|     /** | ||||
|      * The color used for error/failure messages. | ||||
|      */ | ||||
|     public static TextColor failureColor = NamedTextColor.RED; | ||||
|  | ||||
|     /** | ||||
|      * the color used for informational messages. | ||||
|      */ | ||||
|     public static TextColor infoColor = NamedTextColor.GOLD; | ||||
|  | ||||
|     /** | ||||
|      * The color used for warning messages. | ||||
|      */ | ||||
|     public static TextColor warningColor = NamedTextColor.GOLD; | ||||
|  | ||||
|     /** | ||||
|      * The color used to display data in a message. | ||||
|      */ | ||||
|     public static TextColor dataColor = NamedTextColor.GRAY; | ||||
|  | ||||
|     /** | ||||
|      * The color used for displayed URLs and clickable URLs. | ||||
|      */ | ||||
|     public static TextColor urlColor = NamedTextColor.GREEN; | ||||
|  | ||||
|     /** | ||||
|      * The color used for displayed commands and clickable commands. | ||||
|      */ | ||||
|     public static TextColor commandColor = NamedTextColor.GRAY; | ||||
|  | ||||
|     /** | ||||
|      * The color sued to display a command that is highlighted. For example, the current page in a pagination. | ||||
|      */ | ||||
|     public static TextColor highlightedCommandColor = NamedTextColor.WHITE; | ||||
|  | ||||
|     /** | ||||
|      * The color used for broadcasted messages. | ||||
|      * It is often used in combination with {@link #prefix}. | ||||
|      */ | ||||
|     public static TextColor broadcastColor = NamedTextColor.YELLOW; | ||||
|      | ||||
|     /** | ||||
|      * The prefix used for prefixed messages. | ||||
|      * It can be a sylized name of the server, like {@code "[Pandacube] "}. | ||||
|      * It is often used in combination with {@link #broadcastColor}. | ||||
|      */ | ||||
|     public static Supplier<Chat> prefix; | ||||
|  | ||||
|     /** | ||||
|      * Gets the width of the configured {@link #prefix}. | ||||
|      * @param console if the width has to be calculated for the console or not. | ||||
|      * @return the width of the configured {@link #prefix}. | ||||
|      */ | ||||
|     public static int getPrefixWidth(boolean console) { | ||||
|         Chat c; | ||||
|         return prefix == null ? 0 : (c = prefix.get()) == null ? 0 : ChatUtil.componentWidth(c.getAdv(), console); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,208 @@ | ||||
| package fr.pandacube.lib.chat; | ||||
|  | ||||
| import net.kyori.adventure.text.Component; | ||||
| import net.kyori.adventure.text.ComponentLike; | ||||
| import net.kyori.adventure.text.format.TextColor; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
|  | ||||
| import fr.pandacube.lib.chat.Chat.FormatableChat; | ||||
|  | ||||
| /** | ||||
|  * Builder for a {@link Chat} component for filling a chat line, with decoration and eventual aligned text. | ||||
|  */ | ||||
| public class ChatFilledLine implements ComponentLike { | ||||
|  | ||||
|     /** | ||||
|      * Builder for a filled line with the provided left-aligned text. | ||||
|      * @param text the text to align ont the left. | ||||
|      * @return a new {@link ChatFilledLine} builder. | ||||
|      */ | ||||
|     public static ChatFilledLine leftText(ComponentLike text) { | ||||
|         return new ChatFilledLine(text, Alignment.LEFT); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Builder for a filled line with the provided right-aligned text. | ||||
|      * @param text the text to align ont the right. | ||||
|      * @return a new {@link ChatFilledLine} builder. | ||||
|      */ | ||||
|     public static ChatFilledLine rightText(ComponentLike text) { | ||||
|         return new ChatFilledLine(text, Alignment.RIGHT); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Builder for a filled line with the provided centered text. | ||||
|      * @param text the text to center. | ||||
|      * @return a new {@link ChatFilledLine} builder. | ||||
|      */ | ||||
|     public static ChatFilledLine centerText(ComponentLike text) { | ||||
|         return new ChatFilledLine(text, Alignment.CENTER); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Builder for a filled line with no text. | ||||
|      * @return a new {@link ChatFilledLine} builder. | ||||
|      */ | ||||
|     public static ChatFilledLine filled() { | ||||
|         return new ChatFilledLine(null, Alignment.NONE); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     private final ComponentLike text; | ||||
|     private final Alignment alignment; | ||||
|     private char decorationChar = ChatConfig.decorationChar; | ||||
|     private TextColor decorationColor = ChatConfig.decorationColor; | ||||
|     private boolean decorationBold = false; | ||||
|     private int nbSide = ChatConfig.nbCharMargin; | ||||
|     private boolean spacesAroundText = false; | ||||
|     private boolean console = false; | ||||
|     private Integer maxWidth = null; | ||||
|  | ||||
|     private ChatFilledLine(ComponentLike text, Alignment alignment) { | ||||
|         this.text = text; | ||||
|         this.alignment = alignment; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Sets the decoration char. | ||||
|      * @param decoChar the character that will fill the line. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine decoChar(char decoChar) { | ||||
|         decorationChar = decoChar; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the decoration color. | ||||
|      * @param decoColor the color of the characters filling the line. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine decoColor(TextColor decoColor) { | ||||
|         decorationColor = decoColor; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the decoration in bold. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine decoBold() { | ||||
|         decorationBold = true; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the number of side character when the text is aligned left or right. | ||||
|      * @param nbSide the number of character that will separate the border from the side of the text. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine nbSide(int nbSide) { | ||||
|         this.nbSide = nbSide; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds spaces around the text. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine spacesAroundText() { | ||||
|         spacesAroundText = true; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Configure if the line will be rendered on console or not. | ||||
|      * @param console true for console, false for game UI. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine console(boolean console) { | ||||
|         this.console = console; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Configure the width of the line. | ||||
|      * @param maxWidth the width to consider when rendering the line. In pixel for game UI rendering, n character for | ||||
|      *                 console rendering. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatFilledLine maxWidth(int maxWidth) { | ||||
|         this.maxWidth = maxWidth; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Renders this line to a {@link FormatableChat}. | ||||
|      * @return a new {@link FormatableChat} builded by this {@link ChatFilledLine}. | ||||
|      */ | ||||
|     public FormatableChat toChat() { | ||||
|         int maxWidth = (this.maxWidth != null) | ||||
|                 ? this.maxWidth | ||||
|                 : console ? ChatUtil.CONSOLE_NB_CHAR_DEFAULT : ChatUtil.DEFAULT_CHAT_WIDTH; | ||||
|  | ||||
|         if (alignment == Alignment.NONE) { | ||||
|             int count = maxWidth / ChatUtil.charW(decorationChar, console, decorationBold); | ||||
|             return Chat.text(ChatUtil.repeatedChar(decorationChar, count)).color(decorationColor).bold(decorationBold); | ||||
|         } | ||||
|  | ||||
|         ComponentLike text = spacesAroundText | ||||
|                 ? Chat.text(" ").then(this.text).thenText(" ") | ||||
|                 : this.text; | ||||
|  | ||||
|         int textWidth = ChatUtil.componentWidth(text.asComponent(), console); | ||||
|  | ||||
|         if (textWidth > maxWidth) | ||||
|             return (FormatableChat) text; | ||||
|  | ||||
|         int repeatedCharWidth = ChatUtil.charW(decorationChar, console, decorationBold); | ||||
|         int nbCharLeft = 0, nbCharRight = 0; | ||||
|  | ||||
|         switch (alignment) { | ||||
|             case CENTER -> { | ||||
|                 nbCharLeft = nbCharRight = (maxWidth - textWidth) / 2 / repeatedCharWidth; | ||||
|                 if (nbCharLeft == 0) | ||||
|                     return (FormatableChat) text; | ||||
|             } | ||||
|             case LEFT, RIGHT -> { | ||||
|                 int remWidth = textWidth + nbSide * repeatedCharWidth; | ||||
|                 if (remWidth > maxWidth) | ||||
|                     return (FormatableChat) text; | ||||
|                 boolean left = alignment == Alignment.LEFT; | ||||
|                 int nbOtherSide = (maxWidth - remWidth) / repeatedCharWidth; | ||||
|                 nbCharLeft  = left ? nbSide : nbOtherSide; | ||||
|                 nbCharRight = left ? nbOtherSide : nbSide; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Chat d = Chat.chat() | ||||
|                 .then(Chat.text(ChatUtil.repeatedChar(decorationChar, nbCharLeft)).color(decorationColor).bold(decorationBold)) | ||||
|                 .then(text); | ||||
|         if (decorationChar != ' ') | ||||
|             d.then(Chat.text(ChatUtil.repeatedChar(decorationChar, nbCharRight)).color(decorationColor).bold(decorationBold)); | ||||
|         return (FormatableChat) d; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public @NotNull Component asComponent() { | ||||
|         return toChat().asComponent(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     private enum Alignment { | ||||
|         LEFT, | ||||
|         CENTER, | ||||
|         RIGHT, | ||||
|         NONE | ||||
|     } | ||||
| } | ||||
| @@ -2,44 +2,82 @@ package fr.pandacube.lib.chat; | ||||
|  | ||||
| import java.util.Objects; | ||||
|  | ||||
| import net.kyori.adventure.text.BlockNBTComponent; | ||||
| import net.kyori.adventure.text.Component; | ||||
| import net.kyori.adventure.text.ComponentBuilder; | ||||
| import net.kyori.adventure.text.ComponentLike; | ||||
| import net.kyori.adventure.text.EntityNBTComponent; | ||||
| import net.kyori.adventure.text.KeybindComponent; | ||||
| import net.kyori.adventure.text.ScoreComponent; | ||||
| import net.kyori.adventure.text.SelectorComponent; | ||||
| import net.kyori.adventure.text.StorageNBTComponent; | ||||
| import net.kyori.adventure.text.TextComponent; | ||||
| import net.kyori.adventure.text.TranslatableComponent; | ||||
| import net.kyori.adventure.text.event.HoverEventSource; | ||||
| import net.kyori.adventure.text.format.NamedTextColor; | ||||
| import net.kyori.adventure.text.format.TextColor; | ||||
| import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| import fr.pandacube.lib.chat.Chat.FormatableChat; | ||||
|  | ||||
| /** | ||||
|  * Abstract class holding the publicly accessible methods to create an instance of {@link Chat} component. | ||||
|  */ | ||||
| public abstract class ChatStatic { | ||||
|  | ||||
|  | ||||
|  | ||||
|     private static FormatableChat chatComponent(Component c) { | ||||
| 		return new FormatableChat(Chat.componentToBuilder(c)); | ||||
|         return new FormatableChat(componentToBuilder(c)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent}. | ||||
|      * @param c the {@link BaseComponent}. | ||||
|      * @return a new {@link FormatableChat}. | ||||
|      */ | ||||
|     public static FormatableChat chatComponent(BaseComponent c) { | ||||
| 		return new FormatableChat(Chat.componentToBuilder(Chat.toAdventure(c))); | ||||
|         return new FormatableChat(componentToBuilder(Chat.toAdventure(c))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} from the provided {@link ComponentLike}. | ||||
|      * If the provided component is an instance of {@link Chat}, its content will be duplicated, and the provided one | ||||
|      * will be untouched. | ||||
|      * @param c the {@link ComponentLike}. | ||||
|      * @return a new {@link FormatableChat}. | ||||
|      */ | ||||
|     public static FormatableChat chatComponent(ComponentLike c) { | ||||
|         return chatComponent(c.asComponent()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with an empty main text content. | ||||
|      * @return a new empty {@link FormatableChat}. | ||||
|      */ | ||||
|     public static FormatableChat chat() { | ||||
|         return new FormatableChat(Component.text()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} from the provided Bungee {@link BaseComponent BaseComponent[]}. | ||||
|      * @param c the array of {@link BaseComponent}. | ||||
|      * @return a new {@link FormatableChat}. | ||||
|      */ | ||||
|     public static FormatableChat chatComponent(BaseComponent[] c) { | ||||
|         return chatComponent(Chat.toAdventure(c)); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
| 	 * Create a Chat instance with the provided plain text as its main text content. | ||||
| 	 * | ||||
| 	 * @param plainText the text to use as he content of the new Chat instance. | ||||
| 	 * @return a Chat instance with the provided text as its main text content. | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} | ||||
|      *         instead. | ||||
| @@ -53,10 +91,9 @@ public abstract class ChatStatic { | ||||
|  | ||||
|  | ||||
|     /** | ||||
| 	 * Create a Chat instance with the provided legacy text as its main text content. | ||||
| 	 * | ||||
| 	 * @param legacyText the text to use as he content of the new Chat instance. | ||||
| 	 * @return a Chat instance with the provided text as its main text content. | ||||
|      * Creates a {@link FormatableChat} with the provided legacy text as its content. | ||||
|      * @param legacyText the legacy text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its content. | ||||
|      * @throws IllegalArgumentException If the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} | ||||
|      *         instead. | ||||
| @@ -68,55 +105,159 @@ public abstract class ChatStatic { | ||||
|         return chatComponent(LegacyComponentSerializer.legacySection().deserialize(Objects.toString(legacyText))); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#infoColor configured info color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#infoColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat infoText(Object plainText) { | ||||
|         return text(plainText).infoColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#warningColor configured warning color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#warningColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat warningText(Object plainText) { | ||||
|         return text(plainText).warningColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#dataColor configured data color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#dataColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat dataText(Object plainText) { | ||||
|         return text(plainText).dataColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#decorationColor configured decorationColor color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#decorationColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat decorationText(Object plainText) { | ||||
|         return text(plainText).decorationColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#successColor configured success color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#successColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat successText(Object plainText) { | ||||
|         return text(plainText).successColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided plain text as its main text content, and colored using the | ||||
|      * {@link ChatConfig#failureColor configured failure color}. | ||||
|      * @param plainText the text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#failureColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat failureText(Object plainText) { | ||||
|         return text(plainText).failureColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided legacy text as its main text content, and colored in white in | ||||
|      * case there is no color on the generated parent component. | ||||
|      * @param legacyText the legacy text to use as the content. | ||||
|      * @return a new {@link FormatableChat} with the provided text as its main text content, and the configured color. | ||||
|      * @throws IllegalArgumentException if the {@code plainText} parameter is instance of {@link Chat} or | ||||
|      *         {@link Component}. The caller should use {@link #chatComponent(ComponentLike)} and | ||||
|      *         {@link FormatableChat#failureColor()} instead. | ||||
|      */ | ||||
|     public static FormatableChat playerNameText(String legacyText) { | ||||
|         FormatableChat fc = legacyText(legacyText); | ||||
|         fc.builder.colorIfAbsent(NamedTextColor.WHITE); | ||||
|         return fc; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} from the provided {@link Component}, coloring in white the generated parent | ||||
|      * component in case there is no color defined. | ||||
|      * If the provided component is an instance of {@link Chat}, its content will be duplicated, and the provided one | ||||
|      * will be untouched. | ||||
|      * @param c the {@link Component}. | ||||
|      * @return a new {@link FormatableChat}. | ||||
|      */ | ||||
|     public static FormatableChat playerNameComponent(Component c) { | ||||
|         FormatableChat fc = chatComponent(c); | ||||
|         fc.builder.colorIfAbsent(NamedTextColor.WHITE); | ||||
|         return fc; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided translation key and parameters. | ||||
|      * @param key the translation key. | ||||
|      * @param with the translation parameters. | ||||
|      * @return a new {@link FormatableChat} with the provided translation key and parameters. | ||||
|      */ | ||||
|     public static FormatableChat translation(String key, Object... with) { | ||||
|         return new FormatableChat(Component.translatable().key(key).args(Chat.filterObjToComponentLike(with))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided keybind. | ||||
|      * @param key the keybind to display. | ||||
|      * @return a new {@link FormatableChat} with the provided keybind. | ||||
|      */ | ||||
|     public static FormatableChat keybind(String key) { | ||||
|         return new FormatableChat(Component.keybind().keybind(key)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} with the provided score name and objective. | ||||
|      * @param name the score name. | ||||
|      * @param objective the score objective. | ||||
|      * @return a new {@link FormatableChat} with the provided score name and objective. | ||||
|      */ | ||||
|     public static FormatableChat score(String name, String objective) { | ||||
|         return new FormatableChat(Component.score().name(name).objective(objective)); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableURL(Chat inner, String url, Chat hover) { | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that leads to a URL when clicked. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param url the target url. Must start with {@code "http://"} or {@code "https://"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that leads to a URL when clicked. | ||||
|      */ | ||||
|     public static FormatableChat clickableURL(ComponentLike inner, String url, HoverEventSource<?> hover) { | ||||
|         Objects.requireNonNull(url, "url"); | ||||
|         if (inner == null) | ||||
|             inner = text(url); | ||||
| @@ -125,19 +266,61 @@ public abstract class ChatStatic { | ||||
|         return (FormatableChat) chat().clickURL(url).urlColor().hover(hover).then(inner); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableURL(Chat inner, String url) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that leads to a URL when clicked. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the url. To customize the hover content, use | ||||
|      * {@link #clickableURL(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param url the target url. Must start with {@code "http://"} or {@code "https://"}. | ||||
|      * @return a new {@link FormatableChat} that leads to a URL when clicked. | ||||
|      */ | ||||
|     public static FormatableChat clickableURL(ComponentLike inner, String url) { | ||||
|         return clickableURL(inner, url, null); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableURL(String url, Chat hover) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that leads to a URL when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the URL itself. To configure the clicked text, use | ||||
|      * {@link #clickableURL(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param url the target url. Must start with {@code "http://"} or {@code "https://"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that leads to a URL when clicked. | ||||
|      */ | ||||
|     public static FormatableChat clickableURL(String url, HoverEventSource<?> hover) { | ||||
|         return clickableURL(null, url, hover); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that leads to a URL when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the URL itself. To configure the clicked text, use | ||||
|      * {@link #clickableURL(ComponentLike, String)}. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the url. To customize the hover content, use | ||||
|      * {@link #clickableURL(String, HoverEventSource)}. | ||||
|      * @param url the target url. Must start with {@code "http://"} or {@code "https://"}. | ||||
|      * @return a new {@link FormatableChat} that leads to a URL when clicked. | ||||
|      */ | ||||
|     public static FormatableChat clickableURL(String url) { | ||||
|         return clickableURL(null, url, null); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableCommand(Chat inner, String commandWithSlash, Chat hover) { | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that runs a command when clicked. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param commandWithSlash the command to run. Must start with {@code "/"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that runs a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableCommand(ComponentLike inner, String commandWithSlash, HoverEventSource<?> hover) { | ||||
|         Objects.requireNonNull(commandWithSlash, "commandWithSlash"); | ||||
|         if (!commandWithSlash.startsWith("/")) | ||||
|             throw new IllegalArgumentException("commandWithSlash must start with a '/' character."); | ||||
| @@ -148,19 +331,64 @@ public abstract class ChatStatic { | ||||
|         return (FormatableChat) chat().clickCommand(commandWithSlash).commandColor().hover(hover).then(inner); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableCommand(Chat inner, String commandWithSlash) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that runs a command when clicked. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the command itself. To customize the hover content, use | ||||
|      * {@link #clickableCommand(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param commandWithSlash the command to run. Must start with {@code "/"}. | ||||
|      * @return a new {@link FormatableChat} that runs a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableCommand(ComponentLike inner, String commandWithSlash) { | ||||
|         return clickableCommand(inner, commandWithSlash, null); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableCommand(String commandWithSlash, Chat hover) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that runs a command when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the command itself. To configure the clicked text, use | ||||
|      * {@link #clickableCommand(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param commandWithSlash the command to run. Must start with {@code "/"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that runs a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableCommand(String commandWithSlash, HoverEventSource<?> hover) { | ||||
|         return clickableCommand(null, commandWithSlash, hover); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that runs a command when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the command itself. To configure the clicked text, use | ||||
|      * {@link #clickableCommand(ComponentLike, String)}. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the command itself. To customize the hover content, use | ||||
|      * {@link #clickableCommand(String, HoverEventSource)}. | ||||
|      * @param commandWithSlash the command to run. Must start with {@code "/"}. | ||||
|      * @return a new {@link FormatableChat} that runs a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableCommand(String commandWithSlash) { | ||||
|         return clickableCommand(null, commandWithSlash, null); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableSuggest(Chat inner, String commandWithSlash, Chat hover) { | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param commandWithSlash the command to suggest. Must start with {@code "/"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableSuggest(ComponentLike inner, String commandWithSlash, HoverEventSource<?> hover) { | ||||
|         Objects.requireNonNull(commandWithSlash, "commandWithSlash"); | ||||
|         if (!commandWithSlash.startsWith("/")) | ||||
|             throw new IllegalArgumentException("commandWithSlash must start with a '/' character."); | ||||
| @@ -171,14 +399,46 @@ public abstract class ChatStatic { | ||||
|         return (FormatableChat) chat().clickSuggest(commandWithSlash).commandColor().hover(hover).then(inner); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableSuggest(Chat inner, String commandWithSlash) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the command itself. To customize the hover content, use | ||||
|      * {@link #clickableSuggest(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param inner the component to make clickable. | ||||
|      * @param commandWithSlash the command to suggest. Must start with {@code "/"}. | ||||
|      * @return a new {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableSuggest(ComponentLike inner, String commandWithSlash) { | ||||
|         return clickableSuggest(inner, commandWithSlash, null); | ||||
|     } | ||||
|  | ||||
| 	public static FormatableChat clickableSuggest(String commandWithSlash, Chat hover) { | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the command itself. To configure the clicked text, use | ||||
|      * {@link #clickableSuggest(ComponentLike, String, HoverEventSource)}. | ||||
|      * @param commandWithSlash the command to suggest. Must start with {@code "/"}. | ||||
|      * @param hover the content to display when hovering the component. | ||||
|      * @return a new {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableSuggest(String commandWithSlash, HoverEventSource<?> hover) { | ||||
|         return clickableSuggest(null, commandWithSlash, hover); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * <p> | ||||
|      * The text on which to click will be the command itself. To configure the clicked text, use | ||||
|      * {@link #clickableSuggest(ComponentLike, String)}. | ||||
|      * <p> | ||||
|      * When hovered, the component will display the command itself. To customize the hover content, use | ||||
|      * {@link #clickableSuggest(String, HoverEventSource)}. | ||||
|      * @param commandWithSlash the command to suggest. Must start with {@code "/"}. | ||||
|      * @return a new {@link FormatableChat} that pre-fill the chat box with a command when clicked. | ||||
|      * @throws IllegalArgumentException if {@code commandWithSlash} does not start with a {@code "/"}. | ||||
|      */ | ||||
|     public static FormatableChat clickableSuggest(String commandWithSlash) { | ||||
|         return clickableSuggest(null, commandWithSlash, null); | ||||
|     } | ||||
| @@ -188,13 +448,195 @@ public abstract class ChatStatic { | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a left-aligned text. | ||||
|      * @param text the text aligned to the left. | ||||
|      * @param decorationChar the character used for decoration around the text. | ||||
|      * @param decorationColor the color used for the decoration characters. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a left-aligned text. | ||||
|      * @see ChatFilledLine#leftText(ComponentLike) | ||||
|      */ | ||||
|     public static FormatableChat leftText(ComponentLike text, char decorationChar, TextColor decorationColor, boolean console) { | ||||
|         return ChatFilledLine.leftText(text).decoChar(decorationChar).decoColor(decorationColor).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and | ||||
|      * color and a left-aligned text. | ||||
|      * @param text the text aligned to the left. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character | ||||
|      *         and color and a left-aligned text. | ||||
|      * @see ChatFilledLine#leftText(ComponentLike) | ||||
|      * @see ChatConfig#decorationChar | ||||
|      * @see ChatConfig#decorationColor | ||||
|      */ | ||||
|     public static FormatableChat leftText(ComponentLike text, boolean console) { | ||||
|         return ChatFilledLine.leftText(text).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a right-aligned text. | ||||
|      * @param text the text aligned to the right. | ||||
|      * @param decorationChar the character used for decoration around the text. | ||||
|      * @param decorationColor the color used for the decoration characters. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a right-aligned | ||||
|      *         text. | ||||
|      * @see ChatFilledLine#rightText(ComponentLike) | ||||
|      */ | ||||
|     public static FormatableChat rightText(ComponentLike text, char decorationChar, TextColor decorationColor, boolean console) { | ||||
|         return ChatFilledLine.rightText(text).decoChar(decorationChar).decoColor(decorationColor).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and | ||||
|      * color and a right-aligned text. | ||||
|      * @param text the text aligned to the right. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character | ||||
|      *         and color and a right-aligned text. | ||||
|      * @see ChatFilledLine#rightText(ComponentLike) | ||||
|      * @see ChatConfig#decorationChar | ||||
|      * @see ChatConfig#decorationColor | ||||
|      */ | ||||
|     public static FormatableChat rightText(ComponentLike text, boolean console) { | ||||
|         return ChatFilledLine.rightText(text).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with decoration and a centered text. | ||||
|      * @param text the text aligned to the center. | ||||
|      * @param decorationChar the character used for decoration around the text. | ||||
|      * @param decorationColor the color used for the decoration characters. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with decoration and a centered text. | ||||
|      * @see ChatFilledLine#centerText(ComponentLike) | ||||
|      */ | ||||
|     public static FormatableChat centerText(ComponentLike text, char decorationChar, TextColor decorationColor, boolean console) { | ||||
|         return ChatFilledLine.centerText(text).decoChar(decorationChar).decoColor(decorationColor).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and | ||||
|      * color and a centered text. | ||||
|      * @param text the text aligned to the center. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with the configured decoration character | ||||
|      *         and color and a centered text. | ||||
|      * @see ChatFilledLine#centerText(ComponentLike) | ||||
|      * @see ChatConfig#decorationChar | ||||
|      * @see ChatConfig#decorationColor | ||||
|      */ | ||||
|     public static FormatableChat centerText(ComponentLike text, boolean console) { | ||||
|         return ChatFilledLine.centerText(text).spacesAroundText().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with a decoration character and color. | ||||
|      * @param decorationChar the character used for decoration. | ||||
|      * @param decorationColor the color used for the decoration characters. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with a decoration character and color. | ||||
|      * @see ChatFilledLine#filled() | ||||
|      */ | ||||
|     public static FormatableChat filledLine(char decorationChar, TextColor decorationColor, boolean console) { | ||||
|         return ChatFilledLine.filled().decoChar(decorationChar).decoColor(decorationColor).console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a {@link FormatableChat} filling a line of chat (or console) with the configured decoration character and | ||||
|      * color. | ||||
|      * @param console if the line is rendered on console (true) or IG (false). | ||||
|      * @return a new {@link FormatableChat} filling a line of chat (or console) with a decoration character and color. | ||||
|      * @see ChatFilledLine#filled() | ||||
|      * @see ChatConfig#decorationChar | ||||
|      * @see ChatConfig#decorationColor | ||||
|      */ | ||||
|     public static FormatableChat filledLine(boolean console) { | ||||
|         return ChatFilledLine.filled().console(console).toChat(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Adds the configured prefix and broadcast color to the provided message. | ||||
|      * @param message the message to decorate. | ||||
|      * @return the decorated message. | ||||
|      */ | ||||
|     public static Chat prefixedAndColored(ComponentLike message) { | ||||
|         return Chat.chat() | ||||
|                 .broadcastColor() | ||||
| 				.then(Chat.getConfig().prefix.get()) | ||||
|                 .then(ChatConfig.prefix.get()) | ||||
|                 .then(message); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     private static ComponentBuilder<?, ?> componentToBuilder(Component c) { | ||||
|         ComponentBuilder<?, ?> builder; | ||||
|         if (c instanceof TextComponent) { | ||||
|             builder = Component.text() | ||||
|                     .content(((TextComponent) c).content()); | ||||
|         } | ||||
|         else if (c instanceof TranslatableComponent) { | ||||
|             builder = Component.translatable() | ||||
|                     .key(((TranslatableComponent) c).key()) | ||||
|                     .args(((TranslatableComponent) c).args()); | ||||
|         } | ||||
|         else if (c instanceof SelectorComponent) { | ||||
|             builder = Component.selector() | ||||
|                     .pattern(((SelectorComponent) c).pattern()); | ||||
|         } | ||||
|         else if (c instanceof ScoreComponent) { | ||||
|             builder = Component.score() | ||||
|                     .name(((ScoreComponent) c).name()) | ||||
|                     .objective(((ScoreComponent) c).objective()); | ||||
|         } | ||||
|         else if (c instanceof KeybindComponent) { | ||||
|             builder = Component.keybind() | ||||
|                     .keybind(((KeybindComponent) c).keybind()); | ||||
|         } | ||||
|         else if (c instanceof BlockNBTComponent) { | ||||
|             builder = Component.blockNBT() | ||||
|                     .interpret(((BlockNBTComponent) c).interpret()) | ||||
|                     .nbtPath(((BlockNBTComponent) c).nbtPath()) | ||||
|                     .pos(((BlockNBTComponent) c).pos()); | ||||
|         } | ||||
|         else if (c instanceof EntityNBTComponent) { | ||||
|             builder = Component.entityNBT() | ||||
|                     .interpret(((EntityNBTComponent) c).interpret()) | ||||
|                     .nbtPath(((EntityNBTComponent) c).nbtPath()) | ||||
|                     .selector(((EntityNBTComponent) c).selector()); | ||||
|         } | ||||
|         else if (c instanceof StorageNBTComponent) { | ||||
|             builder = Component.storageNBT() | ||||
|                     .interpret(((StorageNBTComponent) c).interpret()) | ||||
|                     .nbtPath(((StorageNBTComponent) c).nbtPath()) | ||||
|                     .storage(((StorageNBTComponent) c).storage()); | ||||
|         } | ||||
|         else { | ||||
|             throw new IllegalArgumentException("Unknows component type " + c.getClass()); | ||||
|         } | ||||
|         return builder.style(c.style()).append(c.children()); | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| package fr.pandacube.lib.chat; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * A tree structure of {@link Chat} component intended to be rendered using {@link #render(boolean)}. | ||||
|  */ | ||||
| public class ChatTreeNode { | ||||
|  | ||||
|     private static final String TREE_MIDDLE_CONNECTED = "├"; | ||||
|     private static final String TREE_END_CONNECTED = "└"; | ||||
|     private static final String TREE_MIDDLE_OPEN = "│§0`§r"; | ||||
|     private static final String TREE_END_OPEN = "§0```§r"; | ||||
|     private static final String TREE_MIDDLE_OPEN_CONSOLE = "│"; | ||||
|     private static final String TREE_END_OPEN_CONSOLE = " "; // nbsp | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * The component for the current node. | ||||
|      */ | ||||
|     public final Chat component; | ||||
|  | ||||
|     /** | ||||
|      * Children nodes. | ||||
|      */ | ||||
|     public final List<ChatTreeNode> children = new ArrayList<>(); | ||||
|  | ||||
|     /** | ||||
|      * Construct an new {@link ChatTreeNode}. | ||||
|      * @param cmp the component for the current node. | ||||
|      */ | ||||
|     public ChatTreeNode(Chat cmp) { | ||||
|         component = cmp; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a child to the current node. | ||||
|      * @param child the child to add. | ||||
|      * @return this. | ||||
|      */ | ||||
|     public ChatTreeNode addChild(ChatTreeNode child) { | ||||
|         children.add(child); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate a tree view based on this tree structure. | ||||
|      * <p> | ||||
|      * Each element in the returned list represent 1 line of this tree view. | ||||
|      * Thus, the caller may send each line separately or at once depending of the quantity of data. | ||||
|      * @param console true to render for console, false otherwise. | ||||
|      * @return an array of component, each element being a single line. | ||||
|      */ | ||||
|     public List<Chat> render(boolean console) { | ||||
|         List<Chat> ret = new ArrayList<>(); | ||||
|  | ||||
|         ret.add(ChatStatic.chat() | ||||
|                 .then(component)); | ||||
|  | ||||
|         for (int i = 0; i < children.size(); i++) { | ||||
|             List<Chat> childComponents = children.get(i).render(console); | ||||
|             boolean last = i == children.size() - 1; | ||||
|             for (int j = 0; j < childComponents.size(); j++) { | ||||
|  | ||||
|                 String prefix = last ? (j == 0 ? TREE_END_CONNECTED : (console ? TREE_END_OPEN_CONSOLE : TREE_END_OPEN)) | ||||
|                         : (j == 0 ? TREE_MIDDLE_CONNECTED : (console ? TREE_MIDDLE_OPEN_CONSOLE : TREE_MIDDLE_OPEN)); | ||||
|  | ||||
|                 ret.add(ChatStatic.text(prefix) | ||||
|                         .then(childComponents.get(j))); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         return ret; | ||||
|     } | ||||
| } | ||||
| @@ -98,91 +98,6 @@ public class ChatUtil { | ||||
|  | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable URL link. | ||||
| 	 * It is equivalent to the HTML {@code <a>} tag pointing to another page. | ||||
| 	 * @param text the link text. | ||||
| 	 * @param url the destination url. must starts with {@code http} or {@code https}. | ||||
| 	 * @return a {@link Chat} that is a cliquable URL link. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableURL(Chat, String)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createURLLink(String text, String url) { | ||||
| 		return Chat.clickableURL(text == null ? null : Chat.legacyText(text), url); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable URL link. | ||||
| 	 * It is equivalent to the HTML {@code <a>} tag pointing to another page. | ||||
| 	 * @param text the link text. | ||||
| 	 * @param url the destination url. must starts with {@code http} or {@code https}. | ||||
| 	 * @param hoverText the text displayed when hovering the link. | ||||
| 	 * @return a {@link Chat} that is a cliquable URL link. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableURL(Chat, String, Chat)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createURLLink(String text, String url, String hoverText) { | ||||
| 		return Chat.clickableURL(text == null ? null : Chat.legacyText(text), url, hoverText == null ? null : Chat.legacyText(hoverText)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable command link. | ||||
| 	 * When the players clicks on it, they will execute the command. | ||||
| 	 * @param text the link text. | ||||
| 	 * @param commandWithSlash the command to execute when clicked. | ||||
| 	 * @param hoverText the text displayed when hovering the link. | ||||
| 	 * @return a {@link Chat} that is a cliquable command link. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableCommand(Chat, String, Chat)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createCommandLink(String text, String commandWithSlash, String hoverText) { | ||||
| 		return Chat.clickableCommand(text == null ? null : Chat.legacyText(text), commandWithSlash, hoverText == null ? null : Chat.legacyText(hoverText)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable command link. | ||||
| 	 * When the players clicks on it, they will execute the command. | ||||
| 	 * @param text the link text. | ||||
| 	 * @param commandWithSlash the command to execute when clicked. | ||||
| 	 * @param hoverText the text displayed when hovering the link. | ||||
| 	 * @return a {@link Chat} that is a cliquable command link. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableCommand(Chat, String, Chat)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createCommandLink(String text, String commandWithSlash, Chat hoverText) { | ||||
| 		return Chat.clickableCommand(text == null ? null : Chat.legacyText(text), commandWithSlash, hoverText); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable command suggestion. | ||||
| 	 * When the players clicks on it, they will execute the command. | ||||
| 	 * @param inner the link text. | ||||
| 	 * @param commandWithSlash the command to put in the chat box when clicked. | ||||
| 	 * @param hover the text displayed when hovering the link. | ||||
| 	 * @return a {@link Chat} that is a cliquable command suggestion. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableSuggest(Chat, String, Chat)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createCommandSuggest(String inner, String commandWithSlash, String hover) { | ||||
| 		return Chat.clickableSuggest(inner == null ? null : Chat.legacyText(inner), commandWithSlash, hover == null ? null : Chat.legacyText(hover)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a {@link Chat} that is a cliquable command suggestion. | ||||
| 	 * When the players clicks on it, they will execute the command. | ||||
| 	 * @param inner the link text. | ||||
| 	 * @param commandWithSlash the command to put in the chat box when clicked. | ||||
| 	 * @param hover the text displayed when hovering the link. | ||||
| 	 * @return a {@link Chat} that is a cliquable command suggestion. | ||||
| 	 * @deprecated it uses String for displayed text. Use {@link Chat#clickableSuggest(Chat, String, Chat)} instead. | ||||
| 	 */ | ||||
| 	@Deprecated(forRemoval = true, since = "2022-07-27") | ||||
| 	public static FormatableChat createCommandSuggest(String inner, String commandWithSlash, Chat hover) { | ||||
| 		return Chat.clickableSuggest(inner == null ? null : Chat.legacyText(inner), commandWithSlash, hover); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	 | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -224,7 +139,7 @@ public class ChatUtil { | ||||
|                 else { | ||||
|                     if (cmdFormat.endsWith("%d")) { | ||||
|                         d.thenText(" "); | ||||
| 						d.then(Chat.clickableSuggest(Chat.text("..."), cmdFormat.substring(0, cmdFormat.length() - 2), Chat.text("Choisir la page"))); | ||||
|                         d.thenCommandSuggest(Chat.text("..."), cmdFormat.substring(0, cmdFormat.length() - 2), Chat.text("Choisir la page")); | ||||
|                         d.thenText(" "); | ||||
|                     } | ||||
|                     else | ||||
| @@ -254,133 +169,34 @@ public class ChatUtil { | ||||
|  | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * @param decorationColor support null values | ||||
| 	 */ | ||||
| 	public static Chat centerText(Chat text, char repeatedChar, TextColor decorationColor, boolean console) { | ||||
| 		return centerText(text, repeatedChar, decorationColor, console, console ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH); | ||||
| 	} | ||||
| 	public static Chat centerText(Chat text, char repeatedChar, TextColor decorationColor, boolean console, int maxWidth) { | ||||
| 		return centerText(text, repeatedChar, decorationColor, false, console, maxWidth); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param decorationColor support null values | ||||
| 	 */ | ||||
| 	public static Chat centerText(Chat text, char repeatedChar, TextColor decorationColor, boolean decorationBold, boolean console, int maxWidth) { | ||||
|  | ||||
| 		int textWidth = componentWidth(text.getAdv(), console); | ||||
| 		 | ||||
| 		if (textWidth > maxWidth) | ||||
| 			return text; | ||||
| 		 | ||||
| 		int repeatedCharWidth = charW(repeatedChar, console, decorationBold); | ||||
| 		int sideWidth = (maxWidth - textWidth) / 2; | ||||
| 		int sideNbChar = sideWidth / repeatedCharWidth; | ||||
| 		 | ||||
| 		if (sideNbChar == 0) | ||||
| 			return text; | ||||
| 		 | ||||
| 		String sideChars = repeatedChar(repeatedChar, sideNbChar); | ||||
| 		FormatableChat side = ChatStatic.text(sideChars).color(decorationColor); | ||||
| 		if (decorationBold) | ||||
| 			side.bold(); | ||||
|  | ||||
| 		Chat d = Chat.chat() | ||||
| 				.then(side) | ||||
| 				.then(text); | ||||
| 		if (repeatedChar != ' ') | ||||
| 			d.then(side); | ||||
|  | ||||
| 		return d; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	public static Chat leftText(Chat text, char repeatedChar, TextColor decorationColor, int nbLeft, boolean console) { | ||||
| 		return leftText(text, repeatedChar, decorationColor, nbLeft, console, console ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH); | ||||
| 	} | ||||
|  | ||||
| 	public static Chat leftText(Chat text, char repeatedChar, TextColor decorationColor, int nbLeft, boolean console, int maxWidth) { | ||||
| 		 | ||||
| 		int textWidth = componentWidth(text.getAdv(), console); | ||||
| 		int repeatedCharWidth = charW(repeatedChar, console, false); | ||||
| 		int leftWidth = nbLeft * repeatedCharWidth; | ||||
| 		 | ||||
| 		if (textWidth + leftWidth > maxWidth) | ||||
| 			return text; | ||||
|  | ||||
| 		int rightNbChar = (maxWidth - (textWidth + leftWidth)) / repeatedCharWidth; | ||||
| 		 | ||||
| 		Chat d = ChatStatic.chat() | ||||
| 				.then(ChatStatic.text(repeatedChar(repeatedChar, nbLeft)).color(decorationColor)) | ||||
| 				.then(text); | ||||
| 		if (repeatedChar != ' ') { | ||||
| 			d.then(ChatStatic.text(repeatedChar(repeatedChar, rightNbChar)).color(decorationColor)); | ||||
| 		} | ||||
| 		return d; | ||||
| 		 | ||||
| 	} | ||||
|  | ||||
| 	public static Chat rightText(Chat text, char repeatedChar, TextColor decorationColor, int nbRight, boolean console) { | ||||
| 		return rightText(text, repeatedChar, decorationColor, nbRight, console, console ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH); | ||||
| 	} | ||||
|  | ||||
| 	public static Chat rightText(Chat text, char repeatedChar, TextColor decorationColor, int nbRight, | ||||
| 			boolean console, int maxWidth) { | ||||
| 		 | ||||
| 		int textWidth = componentWidth(text.getAdv(), console); | ||||
| 		int repeatedCharWidth = charW(repeatedChar, console, false); | ||||
| 		int rightWidth = nbRight * repeatedCharWidth; | ||||
| 		 | ||||
| 		if (textWidth + rightWidth > maxWidth) | ||||
| 			return text; | ||||
|  | ||||
| 		int leftNbChar = (maxWidth - (textWidth + rightWidth)) / repeatedCharWidth; | ||||
| 		 | ||||
| 		Chat d = ChatStatic.chat() | ||||
| 				.then(ChatStatic.text(repeatedChar(repeatedChar, leftNbChar)).color(decorationColor)) | ||||
| 				.then(text); | ||||
| 		if (repeatedChar != ' ') { | ||||
| 			d.then(ChatStatic.text(repeatedChar(repeatedChar, nbRight)).color(decorationColor)); | ||||
| 		} | ||||
| 		return d; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	public static Chat emptyLine(char repeatedChar, TextColor decorationColor, boolean console) { | ||||
| 		return emptyLine(repeatedChar, decorationColor, false, console); | ||||
| 	} | ||||
|  | ||||
| 	public static Chat emptyLine(char repeatedChar, TextColor decorationColor, boolean decorationBold, boolean console) { | ||||
| 		return emptyLine(repeatedChar, decorationColor, decorationBold, console, (console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH); | ||||
| 	} | ||||
|  | ||||
| 	public static Chat emptyLine(char repeatedChar, TextColor decorationColor, boolean decorationBold, boolean console, int maxWidth) { | ||||
| 		int count = maxWidth / charW(repeatedChar, console, decorationBold); | ||||
| 		FormatableChat line = ChatStatic.text(repeatedChar(repeatedChar, count)).color(decorationColor); | ||||
| 		if (decorationBold) | ||||
| 			line.bold(); | ||||
| 		return line; | ||||
| 	} | ||||
|  | ||||
| 	private static String repeatedChar(char repeatedChar, int count) { | ||||
|     /* package */ static String repeatedChar(char repeatedChar, int count) { | ||||
|         char[] c = new char[count]; | ||||
|         Arrays.fill(c, repeatedChar); | ||||
|         return new String(c); | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
|  | ||||
| 	 | ||||
|     /** | ||||
|      * Compute the width of the provided component. | ||||
|      * @param component the component to compute the width. | ||||
|      * @param console true to compute the width when displayed on console (so it will count the characters), | ||||
|      *                false to compute the width when displayed in game (so it will count the pixels). | ||||
|      * @return the width of the provided component. | ||||
|      */ | ||||
|     public static int componentWidth(Component component, boolean console) { | ||||
|         return componentWidth(component, console, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compute the width of the provided component, with extra information about the parent component. | ||||
|      * @param component the component to compute the width. | ||||
|      * @param console true to compute the width when displayed on console (so it will count the characters), | ||||
|      *                false to compute the width when displayed in game (so it will count the pixels). | ||||
|      * @param parentBold if the component inherits a bold styling from an eventual parent component. | ||||
|      * @return the width of the provided component. | ||||
|      */ | ||||
|     public static int componentWidth(Component component, boolean console, boolean parentBold) { | ||||
|         if (component == null) | ||||
|             return 0; | ||||
| @@ -408,6 +224,14 @@ public class ChatUtil { | ||||
|         return (parent && child != State.FALSE) || (!parent && child == State.TRUE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compute the width of the provided text. | ||||
|      * @param str the text to compute the width. | ||||
|      * @param console true to compute the width when displayed on console (so it will count the characters), | ||||
|      *                false to compute the width when displayed in game (so it will count the pixels). | ||||
|      * @param bold if the text is bold (may change its width). | ||||
|      * @return the width of the provided text. | ||||
|      */ | ||||
|     public static int strWidth(String str, boolean console, boolean bold) { | ||||
|         int count = 0; | ||||
|         for (char c : str.toCharArray()) | ||||
| @@ -415,6 +239,17 @@ public class ChatUtil { | ||||
|         return Math.max(count, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compute the width of the provided character. | ||||
|      * <p> | ||||
|      * It uses the mapping in {@link #CHAR_SIZES} for in-game display. For console, every character is size 1. | ||||
|      * The {@code §} character is treated has a negative value, to make legacy codes take 0 width. | ||||
|      * @param c the character to compute the width. | ||||
|      * @param console true to compute the width when displayed on console (so it will count the characters), | ||||
|      *                false to compute the width when displayed in game (so it will count the pixels). | ||||
|      * @param bold if the character is bold (may change its width). | ||||
|      * @return the width of the provided character. | ||||
|      */ | ||||
|     public static int charW(char c, boolean console, boolean bold) { | ||||
|         if (console) | ||||
|             return (c == '§') ? -1 : 1; | ||||
| @@ -422,18 +257,28 @@ public class ChatUtil { | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|     /** | ||||
|      * Wraps the provided text in multiple lines, taking into account the legacy formating. | ||||
|      * <p> | ||||
|      * This method only takes into account IG text width. Use a regular text-wrapper for console instead. | ||||
|      * @param legacyText the text to wrap. | ||||
|      * @param pixelWidth the width in which the text must fit. | ||||
|      * @return the wrapped text in a {@link List} of {@link Chat} components. | ||||
|      */ | ||||
|     public static List<Chat> wrapInLimitedPixelsToChat(String legacyText, int pixelWidth) { | ||||
|         return wrapInLimitedPixels(legacyText, pixelWidth).stream() | ||||
|                 .map(ChatStatic::legacyText) | ||||
|                 .collect(Collectors.toList()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Wraps the provided text in multiple lines, taking into account the legacy formating. | ||||
|      * <p> | ||||
|      * This method only takes into account IG text width. Use a regular text-wrapper for console instead. | ||||
|      * @param legacyText the text to wrap. | ||||
|      * @param pixelWidth the width in which the text must fit. | ||||
|      * @return the wrapped text in a {@link List} of line. | ||||
|      */ | ||||
|     public static List<String> wrapInLimitedPixels(String legacyText, int pixelWidth) { | ||||
|         List<String> lines = new ArrayList<>(); | ||||
|  | ||||
| @@ -522,12 +367,19 @@ public class ChatUtil { | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	public static List<Component> renderTable(List<List<Chat>> rows, String space, boolean console) { | ||||
| 		List<List<Component>> compRows = new ArrayList<>(rows.size()); | ||||
| 		for (List<Chat> row : rows) { | ||||
|     /** | ||||
|      * Try to render a matrix of {@link Chat} components into a table in the chat or console. | ||||
|      * @param data the component, in the form of {@link List} of {@link List} of {@link Chat}. The englobing list holds | ||||
|      *             the table lines (line 0 being the top line). Each sublist holds the cells content (element 0 is the | ||||
|      *             leftText one). The row lengths can be different. | ||||
|      * @param space a spacer to put between columns. | ||||
|      * @param console true to display the table on the console (character alignement), false in game chat (pixel | ||||
|      *                alignment, much harder). | ||||
|      * @return a List containing each rendered line of the table. | ||||
|      */ | ||||
|     public static List<Component> renderTable(List<List<Chat>> data, String space, boolean console) { | ||||
|         List<List<Component>> compRows = new ArrayList<>(data.size()); | ||||
|         for (List<Chat> row : data) { | ||||
|             List<Component> compRow = new ArrayList<>(row.size()); | ||||
|             for (Chat c : row) { | ||||
|                 compRow.add(c.getAdv()); | ||||
| @@ -538,10 +390,20 @@ public class ChatUtil { | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	public static List<Component> renderTableComp(List<List<Component>> rows, String space, boolean console) { | ||||
|     /** | ||||
|      * Try to render a matrix of {@link Component} components into a table in the chat or console. | ||||
|      * @param data the component, in the form of {@link List} of {@link List} of {@link Component}. The englobing list holds | ||||
|      *             the table lines (line 0 being the top line). Each sublist holds the cells content (element 0 is the | ||||
|      *             leftText one). The row lengths can be different. | ||||
|      * @param space a spacer to put between columns. | ||||
|      * @param console true to display the table on the console (character alignement), false in game chat (pixel | ||||
|      *                alignment, much harder). | ||||
|      * @return a List containing each rendered line of the table. | ||||
|      */ | ||||
|     public static List<Component> renderTableComp(List<List<Component>> data, String space, boolean console) { | ||||
|         // determine columns width | ||||
|         List<Integer> nbPixelPerColumn = new ArrayList<>(); | ||||
| 		for (List<Component> row : rows) { | ||||
|         for (List<Component> row : data) { | ||||
|             for (int i = 0; i < row.size(); i++) { | ||||
|                 int w = componentWidth(row.get(i), console); | ||||
|                 if (nbPixelPerColumn.size() <= i) | ||||
| @@ -552,8 +414,8 @@ public class ChatUtil { | ||||
|         } | ||||
|  | ||||
|         // create the lines with appropriate spacing | ||||
| 		List<Component> spacedRows = new ArrayList<>(rows.size()); | ||||
| 		for (List<Component> row : rows) { | ||||
|         List<Component> spacedRows = new ArrayList<>(data.size()); | ||||
|         for (List<Component> row : data) { | ||||
|             Chat spacedRow = Chat.chat(); | ||||
|             for (int i = 0; i < row.size() - 1; i++) { | ||||
|                 int w = componentWidth(row.get(i), console); | ||||
| @@ -571,8 +433,19 @@ public class ChatUtil { | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
|     /** | ||||
|      * Provides a component acting as a spacer of a specific width. | ||||
|      * <p> | ||||
|      * The returned component contains mostly spaces. If it has visible characters, the component color will be set to | ||||
|      * black to be the least visible as possible. | ||||
|      * <p> | ||||
|      * For console, the method returns a {@link Component} with a regular space repeated {@code width} times. | ||||
|      * For IG, the methods returns a {@link Component} with a combination of spaces and some small characters, with part | ||||
|      * of them bold. For some specific width, the returned {@link Component} may not have the intended width. | ||||
|      * @param width the width of the space to produce. | ||||
|      * @param console true if the spacer is intended to be displayed on the console, false if it’s in game chat. | ||||
|      * @return a component acting as a spacer of a specific width. | ||||
|      */ | ||||
|     public static Component customWidthSpace(int width, boolean console) { | ||||
|         if (console) | ||||
|             return Chat.text(" ".repeat(width)).getAdv(); | ||||
| @@ -631,10 +504,19 @@ public class ChatUtil { | ||||
|     private static final char PROGRESS_BAR_EMPTY_CHAR = '.'; | ||||
|     private static final char PROGRESS_BAR_FULL_CHAR = '|'; | ||||
|  | ||||
| 	public static Chat progressBar(double[] values, TextColor[] colors, double total, int pixelWidth, boolean console) { | ||||
|     /** | ||||
|      * Generate a (eventually multi-part) progress bar using text. | ||||
|      * @param values the values to render in the progress bar. | ||||
|      * @param colors the colors attributed to each values. | ||||
|      * @param total the total value of the progress bar. | ||||
|      * @param width the width in which the progress bar should fit (in pixel for IG, in character count for console) | ||||
|      * @param console true if the progress bar is intended to be displayed on the console, false if it’s in game chat. | ||||
|      * @return a progress bar using text. | ||||
|      */ | ||||
|     public static Chat progressBar(double[] values, TextColor[] colors, double total, int width, boolean console) { | ||||
|  | ||||
|         // 1. Compute char size for each values | ||||
| 		int progressPixelWidth = pixelWidth - strWidth(PROGRESS_BAR_START + PROGRESS_BAR_END, console, false); | ||||
|         int progressPixelWidth = width - strWidth(PROGRESS_BAR_START + PROGRESS_BAR_END, console, false); | ||||
|         int charPixelWidth = charW(PROGRESS_BAR_EMPTY_CHAR, console, false); | ||||
|  | ||||
|         assert charPixelWidth == charW(PROGRESS_BAR_FULL_CHAR, console, false) : "PROGRESS_BAR_EMPTY_CHAR and PROGRESS_BAR_FULL_CHAR should have the same pixel width according to #charW(...)"; | ||||
| @@ -673,23 +555,27 @@ public class ChatUtil { | ||||
|                 .thenText(PROGRESS_BAR_END); | ||||
|     } | ||||
|  | ||||
| 	public static Chat progressBar(double value, TextColor color, double total, int pixelWidth, boolean console) { | ||||
| 		return progressBar(new double[] { value }, new TextColor[] { color }, total, pixelWidth, console); | ||||
|     /** | ||||
|      * Generate a progress bar using text. | ||||
|      * @param value the value to render in the progress bar. | ||||
|      * @param color the color of the filled part of the bar. | ||||
|      * @param total the total value of the progress bar. | ||||
|      * @param width the width in which the progress bar should fit (in pixel for IG, in character count for console) | ||||
|      * @param console true if the progress bar is intended to be displayed on the console, false if it’s in game chat. | ||||
|      * @return a progress bar using text. | ||||
|      */ | ||||
|     public static Chat progressBar(double value, TextColor color, double total, int width, boolean console) { | ||||
|         return progressBar(new double[] { value }, new TextColor[] { color }, total, width, console); | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|     /** | ||||
|      * Truncate an eventually too long prefix (like team prefix or permission group prefix), keep the last color and | ||||
|      * format. | ||||
|      * @param prefix the prefix that eventually needs truncation. | ||||
|      * @param maxLength the maximum length of the prefix. | ||||
|      * @return a truncated prefix, with the last color kept. | ||||
|      */ | ||||
|     public static String truncatePrefix(String prefix, int maxLength) { | ||||
|         if (prefix.length() > maxLength) { | ||||
|             String lastColor = ChatColorUtil.getLastColors(prefix); | ||||
| @@ -700,83 +586,21 @@ public class ChatUtil { | ||||
|         return prefix; | ||||
|     } | ||||
|  | ||||
| 	 | ||||
| 	public static String truncateAtLengthWithoutReset(String prefix, int l) { | ||||
| 		if (prefix.length() > l) { | ||||
| 			prefix = prefix.substring(0, l); | ||||
| 			if (prefix.endsWith("§")) | ||||
| 				prefix = prefix.substring(0, prefix.length()-1); | ||||
| 		} | ||||
| 		return prefix; | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	private static final String TREE_MIDDLE_CONNECTED = "├"; | ||||
| 	private static final String TREE_END_CONNECTED = "└"; | ||||
| 	private static final String TREE_MIDDLE_OPEN = "│§0`§r"; | ||||
| 	private static final String TREE_END_OPEN = "§0```§r"; | ||||
| 	private static final String TREE_MIDDLE_OPEN_CONSOLE = "│"; | ||||
| 	private static final String TREE_END_OPEN_CONSOLE = " "; // nbsp | ||||
| 	 | ||||
|     /** | ||||
| 	 * Generate a tree view based on the tree structure {@code node}. | ||||
| 	 *  | ||||
| 	 * Each element in the returned list represent 1 line of the tree view. | ||||
| 	 * Thus, the caller may send each line separately or at once depending of the quantity of data. | ||||
| 	 * @return A array of component, each element being a single line. | ||||
|      * Truncate an eventually too long string, also taking care of removing an eventual {@code §} character leftText alone | ||||
|      * at the end. | ||||
|      * @param str the string to eventually truncate. | ||||
|      * @param maxLength the maximum length of the string. | ||||
|      * @return a truncated string. | ||||
|      */ | ||||
| 	public static List<Chat> treeView(DisplayTreeNode node, boolean console) { | ||||
| 		List<Chat> ret = new ArrayList<>(); | ||||
| 		 | ||||
| 		ret.add(ChatStatic.chat() | ||||
| 				.then(node.component)); | ||||
| 		 | ||||
| 		for (int i = 0; i < node.children.size(); i++) { | ||||
| 			List<Chat> childComponents = treeView(node.children.get(i), console); | ||||
| 			boolean last = i == node.children.size() - 1; | ||||
| 			for (int j = 0; j < childComponents.size(); j++) { | ||||
| 				 | ||||
| 				String prefix = last ? (j == 0 ? TREE_END_CONNECTED : (console ? TREE_END_OPEN_CONSOLE : TREE_END_OPEN)) | ||||
| 						: (j == 0 ? TREE_MIDDLE_CONNECTED : (console ? TREE_MIDDLE_OPEN_CONSOLE : TREE_MIDDLE_OPEN)); | ||||
| 				 | ||||
| 				ret.add(ChatStatic.text(prefix) | ||||
| 						.then(childComponents.get(j))); | ||||
|     public static String truncateAtLengthWithoutReset(String str, int maxLength) { | ||||
|         if (str.length() > maxLength) { | ||||
|             str = str.substring(0, maxLength); | ||||
|             if (str.endsWith("§")) | ||||
|                 str = str.substring(0, str.length()-1); | ||||
|         } | ||||
|         return str; | ||||
|     } | ||||
|  | ||||
|  | ||||
| 		return ret; | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	public static class DisplayTreeNode { | ||||
| 		public final Chat component; | ||||
| 		public final List<DisplayTreeNode> children = new ArrayList<>(); | ||||
| 		 | ||||
| 		public DisplayTreeNode(Chat cmp) { | ||||
| 			component = cmp; | ||||
| 		} | ||||
| 		 | ||||
| 		public DisplayTreeNode addChild(DisplayTreeNode child) { | ||||
| 			children.add(child); | ||||
| 			return this; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import java.util.OptionalLong; | ||||
| import java.util.Set; | ||||
| import java.util.stream.LongStream; | ||||
|  | ||||
| import fr.pandacube.lib.chat.ChatUtil.DisplayTreeNode; | ||||
| import fr.pandacube.lib.chat.ChatTreeNode; | ||||
| import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedEntity; | ||||
| import fr.pandacube.lib.permissions.SQLPermissions.EntityType; | ||||
| import fr.pandacube.lib.util.Log; | ||||
| @@ -50,7 +50,7 @@ public abstract class PermEntity { | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	public DisplayTreeNode debugPrefix() { | ||||
| 	public ChatTreeNode debugPrefix() { | ||||
| 		return Permissions.resolver.debugPrefix(name, type); | ||||
| 	} | ||||
| 	 | ||||
| @@ -69,7 +69,7 @@ public abstract class PermEntity { | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	public DisplayTreeNode debugSuffix() { | ||||
| 	public ChatTreeNode debugSuffix() { | ||||
| 		return Permissions.resolver.debugSuffix(name, type); | ||||
| 	} | ||||
| 	 | ||||
| @@ -159,15 +159,15 @@ public abstract class PermEntity { | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	public DisplayTreeNode debugPermission(String permission) { | ||||
| 	public ChatTreeNode debugPermission(String permission) { | ||||
| 		return debugPermission(permission, null, null); | ||||
| 	} | ||||
| 	 | ||||
| 	public DisplayTreeNode debugPermission(String permission, String server) { | ||||
| 	public ChatTreeNode debugPermission(String permission, String server) { | ||||
| 		return debugPermission(permission, server, null); | ||||
| 	} | ||||
| 	 | ||||
| 	public DisplayTreeNode debugPermission(String permission, String server, String world) { | ||||
| 	public ChatTreeNode debugPermission(String permission, String server, String world) { | ||||
| 		return Permissions.resolver.debugPermission(name, type, permission, server, world); | ||||
| 	} | ||||
| 	 | ||||
|   | ||||
| @@ -18,8 +18,7 @@ import com.google.common.cache.CacheBuilder; | ||||
| import net.md_5.bungee.api.ChatColor; | ||||
|  | ||||
| import fr.pandacube.lib.chat.Chat; | ||||
| import fr.pandacube.lib.chat.ChatUtil; | ||||
| import fr.pandacube.lib.chat.ChatUtil.DisplayTreeNode; | ||||
| import fr.pandacube.lib.chat.ChatTreeNode; | ||||
| import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedEntity; | ||||
| import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedGroup; | ||||
| import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedPlayer; | ||||
| @@ -66,10 +65,10 @@ public class PermissionsResolver { | ||||
| 		return getEffectiveData(name, type, DataType.SUFFIX); | ||||
| 	} | ||||
| 	 | ||||
| 	/* package */ DisplayTreeNode debugPrefix(String name, EntityType type) { | ||||
| 	/* package */ ChatTreeNode debugPrefix(String name, EntityType type) { | ||||
| 		return debugData(name, type, DataType.PREFIX); | ||||
| 	} | ||||
| 	/* package */ DisplayTreeNode debugSuffix(String name, EntityType type) { | ||||
| 	/* package */ ChatTreeNode debugSuffix(String name, EntityType type) { | ||||
| 		return debugData(name, type, DataType.SUFFIX); | ||||
| 	} | ||||
|  | ||||
| @@ -89,7 +88,7 @@ public class PermissionsResolver { | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	private DisplayTreeNode debugData(String name, EntityType type, DataType dataType) { | ||||
| 	private ChatTreeNode debugData(String name, EntityType type, DataType dataType) { | ||||
| 		CachedEntity entity = (type == EntityType.User) | ||||
| 				? backendReader.getCachedPlayer(UUID.fromString(name)) | ||||
| 				: backendReader.getCachedGroup(name); | ||||
| @@ -104,7 +103,7 @@ public class PermissionsResolver { | ||||
| 		 | ||||
| 		if (resolutionResult.conflict) { | ||||
| 			Log.warning("For data " + dataType + ":\n" | ||||
| 					+ ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream() | ||||
| 					+ resolutionResult.toDisplayTreeNode().render(true).stream() | ||||
| 					.map(Chat::getLegacyText) | ||||
| 					.collect(Collectors.joining(ChatColor.RESET + "\n"))); | ||||
| 		} | ||||
| @@ -163,7 +162,7 @@ public class PermissionsResolver { | ||||
| 			conflict = c != null; | ||||
| 		} | ||||
| 		 | ||||
| 		public DisplayTreeNode toDisplayTreeNode() { | ||||
| 		public ChatTreeNode toDisplayTreeNode() { | ||||
| 			Chat c = Chat.text(entity.name); | ||||
| 			if (result == null) | ||||
| 				c.then(Chat.text(" (non défini)").gray()); | ||||
| @@ -171,11 +170,11 @@ public class PermissionsResolver { | ||||
| 				c.thenLegacyText(" \"" + ChatColor.RESET + result + ChatColor.RESET + "\""); | ||||
| 			if (conflictMessage != null) | ||||
| 				c.thenFailure(" " + conflictMessage); | ||||
| 			DisplayTreeNode node = new DisplayTreeNode(c); | ||||
| 			ChatTreeNode node = new ChatTreeNode(c); | ||||
| 			 | ||||
| 			if (result == null && !conflict && !inheritances.isEmpty()) { | ||||
| 				// there is nothing interesting to show on current or subnode | ||||
| 				node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); | ||||
| 				node.children.add(new ChatTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); | ||||
| 				return node; | ||||
| 			} | ||||
| 			 | ||||
| @@ -290,7 +289,7 @@ public class PermissionsResolver { | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/* package */ DisplayTreeNode debugPermission(String name, EntityType type, String permission, String server, String world) { | ||||
| 	/* package */ ChatTreeNode debugPermission(String name, EntityType type, String permission, String server, String world) { | ||||
| 		CachedEntity entity = (type == EntityType.User) | ||||
| 				? backendReader.getCachedPlayer(UUID.fromString(name)) | ||||
| 				: backendReader.getCachedGroup(name); | ||||
| @@ -306,7 +305,7 @@ public class PermissionsResolver { | ||||
| 		 | ||||
| 		if (resolutionResult.conflict) { | ||||
| 			Log.warning("For permission " + permission + ":\n" | ||||
| 					+ ChatUtil.treeView(resolutionResult.toDisplayTreeNode(), true).stream() | ||||
| 					+ resolutionResult.toDisplayTreeNode().render(true).stream() | ||||
| 					.map(Chat::getLegacyText) | ||||
| 					.collect(Collectors.joining(ChatColor.RESET + "\n"))); | ||||
| 		} | ||||
| @@ -484,7 +483,7 @@ public class PermissionsResolver { | ||||
| 			conflict = c != null; | ||||
| 		} | ||||
| 		 | ||||
| 		public DisplayTreeNode toDisplayTreeNode() { | ||||
| 		public ChatTreeNode toDisplayTreeNode() { | ||||
| 			Chat c = Chat.chat() | ||||
| 					.then(result == PermState.UNDEFINED ? Chat.dataText("■") : result == PermState.GRANTED ? Chat.successText("✔") : Chat.failureText("✘")) | ||||
| 					.then(Chat.text(entity instanceof CachedPlayer cp ? Permissions.playerNameGetter.apply(cp.playerId) : entity.name) | ||||
| @@ -496,13 +495,13 @@ public class PermissionsResolver { | ||||
| 				c.thenData(" w=" + world); | ||||
| 			if (conflictMessage != null) | ||||
| 				c.then(Chat.failureText(" " + conflictMessage)); | ||||
| 			DisplayTreeNode node = new DisplayTreeNode(c); | ||||
| 			ChatTreeNode node = new ChatTreeNode(c); | ||||
| 			 | ||||
| 			selfPermissions.forEach(p -> node.children.add(p.toDisplayTreeNode())); | ||||
| 			 | ||||
| 			if (result == PermState.UNDEFINED && !conflict && !inheritances.isEmpty()) { | ||||
| 				// there is nothing interesting to show on current or subnode | ||||
| 				node.children.add(new DisplayTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); | ||||
| 				node.children.add(new ChatTreeNode(Chat.text("(Inheritances hidden for brevety)").darkGray().italic())); | ||||
| 				return node; | ||||
| 			} | ||||
| 			 | ||||
| @@ -521,8 +520,8 @@ public class PermissionsResolver { | ||||
| 			result = r; | ||||
| 			type = t; | ||||
| 		} | ||||
| 		public DisplayTreeNode toDisplayTreeNode() { | ||||
| 			return new DisplayTreeNode(Chat.chat() | ||||
| 		public ChatTreeNode toDisplayTreeNode() { | ||||
| 			return new ChatTreeNode(Chat.chat() | ||||
| 					.then(result ? Chat.successText("✔") : Chat.failureText("✘")) | ||||
| 					.then(Chat.text(permission).color(type == PermType.WILDCARD ? ChatColor.YELLOW : type == PermType.SPECIAL ? ChatColor.LIGHT_PURPLE : ChatColor.WHITE))); | ||||
| 		} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user