From a2b3e15e65a0e1d20c54bdfe0d8053c5725f9519 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Thu, 6 Jul 2017 04:02:03 +0200 Subject: [PATCH] Commands classes refactoring + Display API is more clear --- .../java/util/chat_display/Display.java | 161 --------- .../java/util/chat_display/DisplayUtil.java | 201 ----------- .../java/util/commands/AbstractCommand.java | 93 +----- .../java/util/commands/BadCommandUsage.java | 31 ++ .../java/util/commands/TabProposal.java | 66 ++++ .../java/util/text_display/Display.java | 316 ++++++++++++++++++ .../java/util/text_display/DisplayUtil.java | 276 +++++++++++++++ .../TextProgressBar.java | 2 +- 8 files changed, 695 insertions(+), 451 deletions(-) delete mode 100644 src/main/java/fr/pandacube/java/util/chat_display/Display.java delete mode 100644 src/main/java/fr/pandacube/java/util/chat_display/DisplayUtil.java create mode 100644 src/main/java/fr/pandacube/java/util/commands/BadCommandUsage.java create mode 100644 src/main/java/fr/pandacube/java/util/commands/TabProposal.java create mode 100644 src/main/java/fr/pandacube/java/util/text_display/Display.java create mode 100644 src/main/java/fr/pandacube/java/util/text_display/DisplayUtil.java rename src/main/java/fr/pandacube/java/util/{chat_display => text_display}/TextProgressBar.java (97%) diff --git a/src/main/java/fr/pandacube/java/util/chat_display/Display.java b/src/main/java/fr/pandacube/java/util/chat_display/Display.java deleted file mode 100644 index 762d4c5..0000000 --- a/src/main/java/fr/pandacube/java/util/chat_display/Display.java +++ /dev/null @@ -1,161 +0,0 @@ -package fr.pandacube.java.util.chat_display; - -import java.util.List; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; - -public class Display { - - private BaseComponent first = new TextComponent(""); - - private BaseComponent current = null; - - public Display() {} - - /** - * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour - * initialiser la composante suivante - */ - public Display(String legacyText) { - convertAndAddLegacy(legacyText); - } - - /** - * Construit un message en mettant à la ligne après chaque chaine passé en - * paramètre.
- * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour - * initialiser la composante suivante - */ - public Display(String[] legacyText) { - boolean f = true; - for (String s : legacyText) { - if (s == null) s = ""; - if (!f) first.addExtra("\n"); - f = false; - convertAndAddLegacy(s); - } - } - - /** - * Construit un message en mettant à la ligne après chaque chaine passé en - * paramètre.
- * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour - * initialiser la composante suivante - */ - public Display(List legacyText) { - this(legacyText.toArray(new String[legacyText.size()])); - } - - /** - * Après l'appel de ce contructeur, vous devez appeler nextComponent() pour - * initialiser la composante suivante - */ - public Display(BaseComponent firstComponent) { - if (firstComponent == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); - first.addExtra(firstComponent); - } - - /** - * Après l'appel de cette méthode, vous devez appeler nextComponent() pour - * initialiser la composante suivante - */ - public Display convertAndAddLegacy(String legacyText) { - finalizeCurrentComponent(); - - if (legacyText == null) return this; - BaseComponent[] compo = TextComponent.fromLegacyText(legacyText); - - for (BaseComponent c : compo) - first.addExtra(c); - return this; - } - - public Display nextComponent(String str) { - finalizeCurrentComponent(); - if (str == null) str = ""; - current = new TextComponent(str); - return this; - } - - public Display addComponent(BaseComponent cmp) { - if (cmp == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); - finalizeCurrentComponent(); - first.addExtra(cmp); - return this; - } - - /** - * Équivalent à nextComponent("\n"), sauf qu'un nouvel appel à - * nextComponent() est nécessaire après. - */ - public Display nextLine() { - finalizeCurrentComponent(); - first.addExtra(new TextComponent("\n")); - return this; - } - - public Display setColor(ChatColor color) { - current.setColor(color); - return this; - } - - public Display setBold(boolean b) { - current.setBold(b); - return this; - } - - public Display setItalic(boolean i) { - current.setItalic(i); - return this; - } - - public Display setUnderlined(boolean u) { - current.setUnderlined(u); - return this; - } - - public Display setObfuscated(boolean o) { - current.setObfuscated(o); - return this; - } - - public Display setStrikethrough(boolean s) { - current.setStrikethrough(s); - return this; - } - - public Display setHoverText(Display content) { - current.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new BaseComponent[] { content.get() })); - return this; - } - - public Display setClickURL(String url) { - current.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); - return this; - } - - public Display setClickCommand(String cmd) { - current.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd)); - return this; - } - - public Display setClickSuggest(String cmd) { - current.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, cmd)); - return this; - } - - private void finalizeCurrentComponent() { - if (current != null) first.addExtra(current); - current = null; - } - - public BaseComponent get() { - finalizeCurrentComponent(); - return first; - } - -} diff --git a/src/main/java/fr/pandacube/java/util/chat_display/DisplayUtil.java b/src/main/java/fr/pandacube/java/util/chat_display/DisplayUtil.java deleted file mode 100644 index e65e18d..0000000 --- a/src/main/java/fr/pandacube/java/util/chat_display/DisplayUtil.java +++ /dev/null @@ -1,201 +0,0 @@ -package fr.pandacube.java.util.chat_display; - -import java.util.HashMap; -import java.util.Map; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; - -public class DisplayUtil { - - private static Map charList = new HashMap() { - private static final long serialVersionUID = 1L; - - { - put(-6, "§"); - put(2, "!.,:;i|¡"); - put(3, "'`lìí"); - put(4, " I[]tï×"); - put(5, "\"()*<>fk{}"); - put(7, "@~®"); - } - }; - - private static final int defaultChatMaxWidth = 320; - private static int chatMaxWidth = defaultChatMaxWidth; - - private static final int defaultNbCharPerLineForConsole = 50; - private static int nbCharPerLineForConsole = defaultNbCharPerLineForConsole; - - public static final ChatColor COLOR_TITLE = ChatColor.GOLD; - public static final ChatColor COLOR_LINK = ChatColor.GREEN; - public static final ChatColor COLOR_COMMAND = ChatColor.GRAY; - - public static BaseComponent createURLLink(String textLink, String url, String hoverText) { - String dispURL = (url.length() > 50) ? (url.substring(0, 48) + "...") : url; - - return new Display().nextComponent(textLink).setClickURL(url) - .setHoverText(new Display( - ChatColor.GRAY + ((hoverText == null) ? "Cliquez pour accéder au site :" : hoverText) + "\n" - + ChatColor.GRAY + dispURL)) - .setColor(COLOR_LINK).get(); - } - - public static BaseComponent createCommandLink(String textLink, String commandWithSlash, String hoverText) { - Display d = new Display().nextComponent(textLink).setClickCommand(commandWithSlash).setColor(COLOR_COMMAND); - if (hoverText != null) d.setHoverText(new Display(hoverText)); - return d.get(); - } - - public static BaseComponent createCommandSuggest(String textLink, String commandWithSlash, String hoverText) { - Display d = new Display().nextComponent(textLink).setClickSuggest(commandWithSlash).setColor(COLOR_COMMAND); - if (hoverText != null) d.setHoverText(new Display(hoverText)); - return d.get(); - } - - public static BaseComponent centerText(BaseComponent text, char repeatedChar, ChatColor decorationColor, - boolean console) { - - int textWidth = strWidth(text.toPlainText(), console); - if (textWidth > ((console) ? nbCharPerLineForConsole : chatMaxWidth)) return text; - - String current = text.toPlainText(); - int count = 0; - do { - count++; - current = repeatedChar + current + repeatedChar; - } while (strWidth(current, console) <= ((console) ? nbCharPerLineForConsole : chatMaxWidth)); - count--; - - String finalLeftOrRight = ""; - - for (int i = 0; i < count; i++) - finalLeftOrRight += repeatedChar; - - Display d = new Display().nextComponent(finalLeftOrRight).setColor(decorationColor).addComponent(text); - - if (repeatedChar != ' ') d.nextComponent(finalLeftOrRight).setColor(decorationColor); - - return d.get(); - - } - - public static BaseComponent leftText(BaseComponent text, char repeatedChar, ChatColor decorationColor, int nbLeft, - boolean console) { - - int textWidth = strWidth(text.toPlainText(), console); - if (textWidth > ((console) ? nbCharPerLineForConsole : chatMaxWidth) || textWidth - + nbLeft * charW(repeatedChar, console) > ((console) ? nbCharPerLineForConsole : chatMaxWidth)) - return text; - - Display d = new Display(); - - String finalLeft = ""; - if (nbLeft > 0) { - for (int i = 0; i < nbLeft; i++) - finalLeft += repeatedChar; - d.nextComponent(finalLeft).setColor(decorationColor); - } - d.addComponent(text); - - int count = 0; - String current = finalLeft + text.toPlainText(); - do { - count++; - current += repeatedChar; - } while (strWidth(current, console) <= ((console) ? nbCharPerLineForConsole : chatMaxWidth)); - count--; - - if (repeatedChar != ' ') { - String finalRight = ""; - for (int i = 0; i < count; i++) - finalRight += repeatedChar; - d.nextComponent(finalRight).setColor(decorationColor); - } - - return d.get(); - - } - - public static BaseComponent rightText(BaseComponent text, char repeatedChar, ChatColor decorationColor, int nbRight, - boolean console) { - - int textWidth = strWidth(text.toPlainText(), console); - if (textWidth > ((console) ? nbCharPerLineForConsole : chatMaxWidth) || textWidth - + nbRight * charW(repeatedChar, console) > ((console) ? nbCharPerLineForConsole : chatMaxWidth)) - return text; - - String tempText = text.toPlainText(); - if (nbRight > 0) { - tempText += decorationColor; - for (int i = 0; i < nbRight; i++) - tempText += repeatedChar; - } - - int count = 0; - String current = tempText; - do { - count++; - current = repeatedChar + current; - } while (strWidth(current, console) <= ((console) ? nbCharPerLineForConsole : chatMaxWidth)); - count--; - - String finalLeft = ""; - for (int i = 0; i < count; i++) - finalLeft += repeatedChar; - - Display d = new Display().nextComponent(finalLeft).setColor(decorationColor).addComponent(text); - - if (repeatedChar != ' ') { - String finalRight = ""; - for (int i = 0; i < nbRight; i++) - finalRight += repeatedChar; - d.nextComponent(finalRight).setColor(decorationColor); - } - - return d.get(); - - } - - public static BaseComponent emptyLine(char repeatedChar, ChatColor decorationColor, boolean console) { - int count = ((console) ? nbCharPerLineForConsole : chatMaxWidth) / charW(repeatedChar, console); - String finalLine = ""; - for (int i = 0; i < count; i++) - finalLine += repeatedChar; - - return new Display().nextComponent(finalLine).setColor(decorationColor).get(); - } - - public static int strWidth(String str, boolean console) { - int count = 0; - for (char c : str.toCharArray()) - count += charW(c, console); - return (count < 0) ? 0 : count; - } - - private static int charW(char c, boolean console) { - if (console) return (c == '§') ? -1 : 1; - for (int px : charList.keySet()) - if (charList.get(px).indexOf(c) >= 0) return px; - return 6; - } - - public static void setNbCharPerLineForConsole(int nb) { - if (nb < 0) nb = 0; - nbCharPerLineForConsole = nb; - } - - public static void resetNbCharPerLineForConsole() { - nbCharPerLineForConsole = defaultNbCharPerLineForConsole; - } - - public static void setChatMaxWidth(int px) { - if (px < 0) px = 0; - chatMaxWidth = px; - } - - public static void resetChatMaxWidth() { - chatMaxWidth = defaultChatMaxWidth; - } - -} diff --git a/src/main/java/fr/pandacube/java/util/commands/AbstractCommand.java b/src/main/java/fr/pandacube/java/util/commands/AbstractCommand.java index 0e78024..d2402a1 100644 --- a/src/main/java/fr/pandacube/java/util/commands/AbstractCommand.java +++ b/src/main/java/fr/pandacube/java/util/commands/AbstractCommand.java @@ -1,11 +1,9 @@ package fr.pandacube.java.util.commands; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.logging.Logger; +import java.util.stream.Collectors; public class AbstractCommand { @@ -50,91 +48,10 @@ public class AbstractCommand { * @return */ public static List getTabProposalFromToken(String token, Collection allProposal) { - List ret = new ArrayList<>(); - - for (String s : allProposal) - if (s != null && s.toLowerCase().startsWith(token.toLowerCase())) ret.add(s); - - if (ret.isEmpty()) ret.addAll(allProposal); - - ret.removeIf(s -> s == null); - ret.sort(null); // String implents Comparable - - return ret; - } - - - - public static final TabProposal TAB_NO_PROPOSAL = () -> Collections.emptyList(); - - public static TabProposal TAB_PROPOSAL(Collection proposals) { - return () -> proposals; - } - - public static TabProposal TAB_INTEGERS(int startIncluded, int endIncluded) { - List proposals = new ArrayList<>(endIncluded - startIncluded + 1); - for (int i = startIncluded; i <= endIncluded; i++) { - proposals.add(Integer.toString(i)); - } - return () -> proposals; - } - - public static TabProposal TAB_PROPOSAL_LAST_PARAMS(String[] args, int index, Collection proposals) { - String lastParamToken = getLastParams(args, index); - String[] splittedToken = lastParamToken.split(" ", -1); - int currentTokenPosition = splittedToken.length - 1; - String[] previousTokens = Arrays.copyOf(splittedToken, currentTokenPosition); - - List currentTokenProposal = new ArrayList<>(); - for (String p : proposals) { - String[] splittedProposal = p.split(" ", -1); - if (splittedProposal.length <= currentTokenPosition) - continue; - if (!Arrays.equals(Arrays.copyOf(splittedToken, currentTokenPosition), previousTokens)) - continue; - if (splittedProposal[currentTokenPosition].isEmpty()) - continue; - - currentTokenProposal.add(splittedProposal[currentTokenPosition]); - } - - return () -> currentTokenProposal; - } - - @FunctionalInterface - public interface TabProposal { - public abstract Collection getProposal(); - } - - - - - /** - * Throw an instance of this exception to indicate to the plugin command handler - * that the user has missused the command. The message, if provided, must indicate - * the reason of the mussusage of the command. It will be displayed on the screen - * with eventually indication of how to use the command (help command for example). - * If a {@link Throwable} cause is provided, it will be relayed to the plugin {@link Logger}. - * - */ - public static class BadCommandUsage extends RuntimeException { - private static final long serialVersionUID = 1L; - - public BadCommandUsage() { - super(); - } - - public BadCommandUsage(Throwable cause) { - super(cause); - } - - public BadCommandUsage(String message) { - super(message); - } - - public BadCommandUsage(String message, Throwable cause) { - super(message, cause); - } + return allProposal.stream() + .filter(s -> s != null && s.toLowerCase().startsWith(token.toLowerCase())) + .sorted() + .collect(Collectors.toList()); } diff --git a/src/main/java/fr/pandacube/java/util/commands/BadCommandUsage.java b/src/main/java/fr/pandacube/java/util/commands/BadCommandUsage.java new file mode 100644 index 0000000..095c3d7 --- /dev/null +++ b/src/main/java/fr/pandacube/java/util/commands/BadCommandUsage.java @@ -0,0 +1,31 @@ +package fr.pandacube.java.util.commands; + +import java.util.logging.Logger; + +/** + * Throw an instance of this exception to indicate to the plugin command handler + * that the user has missused the command. The message, if provided, must indicate + * the reason of the mussusage of the command. It will be displayed on the screen + * with eventually indication of how to use the command (help command for example). + * If a {@link Throwable} cause is provided, it will be relayed to the plugin {@link Logger}. + * + */ +public class BadCommandUsage extends RuntimeException { + private static final long serialVersionUID = 1L; + + public BadCommandUsage() { + super(); + } + + public BadCommandUsage(Throwable cause) { + super(cause); + } + + public BadCommandUsage(String message) { + super(message); + } + + public BadCommandUsage(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/fr/pandacube/java/util/commands/TabProposal.java b/src/main/java/fr/pandacube/java/util/commands/TabProposal.java new file mode 100644 index 0000000..bcb19ba --- /dev/null +++ b/src/main/java/fr/pandacube/java/util/commands/TabProposal.java @@ -0,0 +1,66 @@ +package fr.pandacube.java.util.commands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@FunctionalInterface +public interface TabProposal { + + + public abstract Collection getProposal(); + + + + + + + + + public static TabProposal empty() { return Collections::emptyList; } + + + public static TabProposal fromCollection(Collection proposals) { + return () -> proposals; + } + + public static TabProposal fromIntRange(int startIncluded, int endIncluded) { + return () -> IntStream.rangeClosed(startIncluded, endIncluded) + .mapToObj(v -> Integer.toString(v)) + .collect(Collectors.toList()); + } + + /** + * Allow tab completion to supply proposal from multi-args (arguments with space, + * generally the last argument of a command) parameters + * @param args all the arguments currently in the buffer + * @param index the index of the first argument of the multi-args parameter + * @param proposals all possible proposals for the multi-args parameter + * @return + */ + public static TabProposal withMultiArgsLastParam(String[] args, int index, Collection proposals) { + String lastParamToken = AbstractCommand.getLastParams(args, index); + String[] splittedToken = lastParamToken.split(" ", -1); + int currentTokenPosition = splittedToken.length - 1; + String[] previousTokens = Arrays.copyOf(splittedToken, currentTokenPosition); + + List currentTokenProposal = new ArrayList<>(); + for (String p : proposals) { + String[] splittedProposal = p.split(" ", -1); + if (splittedProposal.length <= currentTokenPosition) + continue; + if (!Arrays.equals(Arrays.copyOf(splittedToken, currentTokenPosition), previousTokens)) + continue; + if (splittedProposal[currentTokenPosition].isEmpty()) + continue; + + currentTokenProposal.add(splittedProposal[currentTokenPosition]); + } + + return () -> currentTokenProposal; + } +} \ No newline at end of file diff --git a/src/main/java/fr/pandacube/java/util/text_display/Display.java b/src/main/java/fr/pandacube/java/util/text_display/Display.java new file mode 100644 index 0000000..e4b8f26 --- /dev/null +++ b/src/main/java/fr/pandacube/java/util/text_display/Display.java @@ -0,0 +1,316 @@ +package fr.pandacube.java.util.text_display; + +import java.util.Arrays; +import java.util.List; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; + +public class Display { + + private BaseComponent root = new TextComponent(""); + + private BaseComponent current = null; + + + /* + * **************** + * * Constructors * + * **************** + */ + + + /** + * Create a new instance. The current component is not initialized. + */ + public Display() {} + + /** + * Create a new instance, with the current component already initialized with the parameter. + * @param legacyText a text that will be converted to a component and set to the current compoment. + */ + public Display(String legacyText) { + next(legacyText); + } + + /** + * Create a new instance, with the current component already initialized with the parameter. + * @param legacyText a list of text that will be joined by a line return followed by ChatColor.RESET, + * then converted to a component and set to the current component. + */ + public Display(List legacyText) { + this(String.join("\n"+ChatColor.RESET, legacyText)); + } + + /** + * Create a new instance, with the current component already initialized with the parameter. + * @param legacyText an array of text that will be joined by a line return followed by ChatColor.RESET, + * then converted to a component and set to the current component. + */ + public Display(String[] legacyText) { + this(Arrays.asList(legacyText)); + } + + /** + * Create a new instance, with the current component already initialized with the parameter. + * @param firstComponent a component corresponding to the current component. + */ + public Display(BaseComponent firstComponent) { + next(firstComponent); + } + + /** + * Create a new instance, with the current component already initialized with the parameter. + * @param components an array of component that will be inside the current component. + */ + public Display(BaseComponent[] components) { + if (components == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); + next(components); + } + + + /* + * ****************** + * * next() methods * + * ****************** + */ + + /** + * Initialize the current component with the parameter. + * The previous component is stored in the root component. + * @param cmp a component corresponding to the new component. + * @return this + */ + public Display next(BaseComponent cmp) { + if (cmp == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); + finalizeCurrentComponent(); + current = cmp; + return this; + } + + /** + * Initialize the current component with the parameter. + * The previous component is stored in the root component. + * @param str a text that will be converted to a component and set to the current compoment. + * @return this + */ + public Display next(String str) { + return next(TextComponent.fromLegacyText(str == null ? "" : str)); + } + + /** + * Initialize the current component with the parameter. + * The previous component is stored in the root component. + * @param components an array of component that will be inside the current component. + * @return this + */ + public Display next(BaseComponent[] components) { + BaseComponent bc = new TextComponent(); + for (BaseComponent c : components) + bc.addExtra(c); + return next(bc); + } + + /** + * Initialize the current component with the parameter. + * The previous component is stored in the root component. + * @param cmp an other instance of Display that the root component become the current component of this instance. + * @return this + */ + public Display next(Display cmp) { + if (cmp == null) throw new IllegalArgumentException("le paramètre ne doit pas être null"); + return next(cmp.get()); + } + + /** + * Initialize the current component with the text "\n". + * The previous component is stored in the root component. + * @return this + */ + public Display nextLine() { + finalizeCurrentComponent(); + current = new TextComponent("\n"); + return this; + } + + /* + * ************************** + * * Style and behaviour of * + * *** current component **** + * ************************** + */ + + /** + * Set the color of the current component. + * @param color the colour. Can be null; + * @return this + */ + public Display color(ChatColor color) { + current.setColor(color); + return this; + } + + /** + * Set if the current component is bold. + * @param b true if bold, false if not, null if undefined + * @return this + */ + public Display bold(Boolean b) { + current.setBold(b); + return this; + } + + /** + * Set if the current component is italic. + * @param b true if italic, false if not, null if undefined + * @return this + */ + public Display italic(Boolean i) { + current.setItalic(i); + return this; + } + + /** + * Set if the current component is underlined. + * @param b true if underlined, false if not, null if undefined + * @return this + */ + public Display underlined(Boolean u) { + current.setUnderlined(u); + return this; + } + + /** + * Set if the current component is obfuscated. + * In Minecraft user interface, obfuscated text displays randomly generated character in place of the originals. The random text regenerate each frame. + * @param b true if obfuscated, false if not, null if undefined + * @return this + */ + public Display obfuscated(Boolean o) { + current.setObfuscated(o); + return this; + } + + /** + * Set if the current component is strikethrough. + * @param b true if strikethrough, false if not, null if undefined + * @return this + */ + public Display strikethrough(Boolean s) { + current.setStrikethrough(s); + return this; + } + + /** + * Set a text displayed as a tooltip when the cursor is hover the current component. + * This method is only relevant if this Display is intended to be displayed in the chat or in a book + * @param content the text as an array of component. + * @return this + */ + public Display hoverText(BaseComponent[] content) { + current.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, content)); + return this; + } + + /** + * Set a text displayed as a tooltip when the cursor is hover the current component. + * This method is only relevant if this Display is intended to be displayed in the chat or in a book + * @param content the text as a component + * @return this + */ + public Display hoverText(BaseComponent content) { + return hoverText(new BaseComponent[] {content}); + } + + /** + * Set a text displayed as a tooltip when the cursor is hover the current component. + * This method is only relevant if this Display is intended to be displayed in the chat or in a book + * @param content the text as a legacy string. + * @return this + */ + public Display hoverText(String legacyContent) { + return hoverText(TextComponent.fromLegacyText(legacyContent)); + } + + /** + * Set a text displayed as a tooltip when the cursor is hover the current component. + * This method is only relevant if this Display is intended to be displayed in the chat or in a book + * @param content the text as a {@link Display} instance. + * @return this + */ + public Display hoverText(Display content) { + return hoverText(content.get()); + } + + /** + * Allow the player to click on the current component to access to the specified URL. + * This method is only relevant if this Display is intended to be displayed in the chat + * @param url the URL + * @return this + */ + public Display clickURL(String url) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + return this; + } + + /** + * Allow the player to click on the current component to run the specified command. + * This method is only relevant if this Display is intended to be displayed in the chat, in a book or on a sign. + * On the sign, all the commands are executed in a row when the player click on the sign. + * @param cmd the command, with the "/" + * @return this + */ + public Display clickCommand(String cmd) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd)); + return this; + } + + /** + * Allow the player to click on the current component to fill the textfield with the specified command. + * This method is only relevant if this Display is intended to be displayed in the chat. + * @param cmd the command + * @return this + */ + public Display clickSuggest(String cmd) { + current.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, cmd)); + return this; + } + + /** + * Allow the player to shuft-click on the current component to insert the specified string into the textfield (at the cursor location). + * This method is only relevant if this Display is intended to be displayed in the chat. + * @param str the string + * @return this + */ + public Display clickInsertion(String str) { + current.setInsertion(str); + return this; + } + + private void finalizeCurrentComponent() { + if (current != null) root.addExtra(current); + current = null; + } + + /** + * Add the current compoment into the root component and return the root component. + * @return + */ + public BaseComponent get() { + finalizeCurrentComponent(); + return root; + } + + /** + * Add the current compoment into the root component and return all the components in an array. + * @return + */ + public BaseComponent[] getArray() { + finalizeCurrentComponent(); + return root.getExtra().toArray(new BaseComponent[root.getExtra().size()]); + } + +} diff --git a/src/main/java/fr/pandacube/java/util/text_display/DisplayUtil.java b/src/main/java/fr/pandacube/java/util/text_display/DisplayUtil.java new file mode 100644 index 0000000..17b5281 --- /dev/null +++ b/src/main/java/fr/pandacube/java/util/text_display/DisplayUtil.java @@ -0,0 +1,276 @@ +package fr.pandacube.java.util.text_display; + +import java.util.Arrays; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.TranslatableComponent; + +public class DisplayUtil { + + public static final int DEFAULT_CHAR_SIZE = 6; + public static final Map CHARS_SIZE = new ImmutableMap.Builder() + .put(-6, "§") + .put(2, "!.,:;i|¡") + .put(3, "'`lìí") + .put(4, " I[]tï×") + .put(5, "\"()*<>fk{}") + .put(7, "@~®") + .build(); + + + + public static final int DEFAULT_CHAT_WIDTH = 320; + public static final int SIGN_WIDTH = 90; + public static final int BOOK_WIDTH = 116; + + public static final int CONSOLE_NB_CHAR_DEFAULT = 50; + + public static final ChatColor COLOR_TITLE = ChatColor.GOLD; + public static final ChatColor COLOR_LINK = ChatColor.GREEN; + public static final ChatColor COLOR_COMMAND = ChatColor.GRAY; + + + + + + + + public static BaseComponent createURLLink(String text, String url, String hoverText) { + return _createURLLink(new Display(text), url, hoverText); + } + public static BaseComponent createURLLink(BaseComponent text, String url, String hoverText) { + return _createURLLink(new Display(text), url, hoverText); + } + public static BaseComponent createURLLink(BaseComponent[] text, String url, String hoverText) { + return _createURLLink(new Display(text), url, hoverText); + } + + private static BaseComponent _createURLLink(Display d, String url, String hoverText) { + String dispURL = (url.length() > 50) ? (url.substring(0, 48) + "...") : url; + return d.clickURL(url) + .hoverText(ChatColor.GRAY + ((hoverText == null) ? "Cliquez pour accéder au site :" : hoverText) + "\n" + + ChatColor.GRAY + dispURL) + .color(COLOR_LINK).get(); + } + + + + + + + + + public static BaseComponent createCommandLink(String text, String commandWithSlash, String hoverText) { + return createCommandLink(text, commandWithSlash, hoverText == null ? null : TextComponent.fromLegacyText(hoverText)); + } + public static BaseComponent createCommandLink(String text, String commandWithSlash, BaseComponent hoverText) { + return createCommandLink(text, commandWithSlash, hoverText == null ? null : new BaseComponent[] {hoverText}); + } + public static BaseComponent createCommandLink(String text, String commandWithSlash, BaseComponent[] hoverText) { + return _createCommandLink(new Display(text), commandWithSlash, hoverText); + } + + private static BaseComponent _createCommandLink(Display d, String commandWithSlash, BaseComponent[] hoverText) { + d.clickCommand(commandWithSlash).color(COLOR_COMMAND); + if (hoverText != null) d.hoverText(hoverText); + return d.get(); + } + + + + + + + + + + + public static BaseComponent createCommandSuggest(String text, String commandWithSlash, String hoverText) { + return createCommandSuggest(text, commandWithSlash, hoverText == null ? null : TextComponent.fromLegacyText(hoverText)); + } + public static BaseComponent createCommandSuggest(String text, String commandWithSlash, BaseComponent hoverText) { + return createCommandSuggest(text, commandWithSlash, hoverText == null ? null : new BaseComponent[] {hoverText}); + } + public static BaseComponent createCommandSuggest(String text, String commandWithSlash, BaseComponent[] hoverText) { + return _createCommandSuggest(new Display(text), commandWithSlash, hoverText); + } + + private static BaseComponent _createCommandSuggest(Display d, String commandWithSlash, BaseComponent[] hoverText) { + d.clickSuggest(commandWithSlash).color(COLOR_COMMAND); + if (hoverText != null) d.hoverText(hoverText); + return d.get(); + } + + + + + + + + + // TODO refaire les 4 methodes ci-dessous + + + + + public static BaseComponent centerText(BaseComponent text, char repeatedChar, ChatColor decorationColor, + boolean console) { + + int textWidth = strWidth(text.toPlainText(), console, false); + if (textWidth > ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)) return text; + + String current = text.toPlainText(); + int count = 0; + do { + count++; + current = repeatedChar + current + repeatedChar; + } while (strWidth(current, console, false) <= ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)); + count--; + + String finalLeftOrRight = ""; + + for (int i = 0; i < count; i++) + finalLeftOrRight += repeatedChar; + + Display d = new Display().next(finalLeftOrRight).color(decorationColor).next(text); + + if (repeatedChar != ' ') d.next(finalLeftOrRight).color(decorationColor); + + return d.get(); + + } + + public static BaseComponent leftText(BaseComponent text, char repeatedChar, ChatColor decorationColor, int nbLeft, + boolean console) { + + int textWidth = strWidth(text.toPlainText(), console, false); + if (textWidth > ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH) || textWidth + + nbLeft * charW(repeatedChar, console, false) > ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)) + return text; + + Display d = new Display(); + + String finalLeft = ""; + if (nbLeft > 0) { + for (int i = 0; i < nbLeft; i++) + finalLeft += repeatedChar; + d.next(finalLeft).color(decorationColor); + } + d.next(text); + + int count = 0; + String current = finalLeft + text.toPlainText(); + do { + count++; + current += repeatedChar; + } while (strWidth(current, console, false) <= ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)); + count--; + + if (repeatedChar != ' ') { + String finalRight = ""; + for (int i = 0; i < count; i++) + finalRight += repeatedChar; + d.next(finalRight).color(decorationColor); + } + + return d.get(); + + } + + public static BaseComponent rightText(BaseComponent text, char repeatedChar, ChatColor decorationColor, int nbRight, + boolean console) { + + int textWidth = strWidth(text.toPlainText(), console, false); + if (textWidth > ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH) || textWidth + + nbRight * charW(repeatedChar, console, false) > ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)) + return text; + + String tempText = text.toPlainText(); + if (nbRight > 0) { + tempText += decorationColor; + for (int i = 0; i < nbRight; i++) + tempText += repeatedChar; + } + + int count = 0; + String current = tempText; + do { + count++; + current = repeatedChar + current; + } while (strWidth(current, console, false) <= ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH)); + count--; + + String finalLeft = ""; + for (int i = 0; i < count; i++) + finalLeft += repeatedChar; + + Display d = new Display().next(finalLeft).color(decorationColor).next(text); + + if (repeatedChar != ' ') { + String finalRight = ""; + for (int i = 0; i < nbRight; i++) + finalRight += repeatedChar; + d.next(finalRight).color(decorationColor); + } + + return d.get(); + + } + + public static BaseComponent emptyLine(char repeatedChar, ChatColor decorationColor, boolean console) { + int count = ((console) ? CONSOLE_NB_CHAR_DEFAULT : DEFAULT_CHAT_WIDTH) / charW(repeatedChar, console, false); + String finalLine = ""; + for (int i = 0; i < count; i++) + finalLine += repeatedChar; + + return new Display().next(finalLine).color(decorationColor).get(); + } + + + + + + + + + + + + public static int componentWidth(BaseComponent[] components, boolean console) { + return Arrays.stream(components).mapToInt(c -> componentWidth(c, console)).sum(); + } + + public static int componentWidth(BaseComponent component, boolean console) { + int count = 0; + for (BaseComponent c : component.getExtra()) + count += componentWidth(c, console); + if (component instanceof TextComponent) { + count += strWidth(((TextComponent)component).getText(), console, component.isBold()); + } + else if (component instanceof TranslatableComponent) { + for (BaseComponent c : ((TranslatableComponent)component).getWith()) + count += componentWidth(c, console); + } + return count; + } + + public static int strWidth(String str, boolean console, boolean bold) { + int count = 0; + for (char c : str.toCharArray()) + count += charW(c, console, bold); + return (count < 0) ? 0 : count; + } + + private static int charW(char c, boolean console, boolean bold) { + if (console) return (c == '§') ? -1 : 1; + for (int px : CHARS_SIZE.keySet()) + if (CHARS_SIZE.get(px).indexOf(c) >= 0) return px + (bold ? 1 : 0); + return 6 + (bold ? 1 : 0); + } + +} diff --git a/src/main/java/fr/pandacube/java/util/chat_display/TextProgressBar.java b/src/main/java/fr/pandacube/java/util/text_display/TextProgressBar.java similarity index 97% rename from src/main/java/fr/pandacube/java/util/chat_display/TextProgressBar.java rename to src/main/java/fr/pandacube/java/util/text_display/TextProgressBar.java index 5eb46dd..db00813 100644 --- a/src/main/java/fr/pandacube/java/util/chat_display/TextProgressBar.java +++ b/src/main/java/fr/pandacube/java/util/text_display/TextProgressBar.java @@ -1,4 +1,4 @@ -package fr.pandacube.java.util.chat_display; +package fr.pandacube.java.util.text_display; import net.md_5.bungee.api.ChatColor;