From 870a89a6e4b39c4e4c82632b76409d4547d6bff7 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Tue, 15 Feb 2022 20:39:42 -0800 Subject: [PATCH] color support in text width --- README.md | 2 +- .../bukkit/BukkitElementProperties.java | 3 +- .../denizen/utilities/TextWidthHelper.java | 73 ++++++++++++++++--- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 71d36fbdbc..67b789c1c9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The Denizen Scripting Language - Spigot Impl An implementation of the Denizen Scripting Language for Spigot servers, with strong Citizens interlinks to emphasize the power of using Denizen with NPCs! -**Version 1.2.4**: Compatible with Spigot 1.16.5, 1.17.1, and 1.18! +**Version 1.2.4**: Compatible with Spigot 1.16.5, 1.17.1, and 1.18.1! **Learn about Denizen from the Beginner's guide:** https://guide.denizenscript.com/guides/background/index.html diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementProperties.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementProperties.java index 4eef8f5a3e..80306a9ac7 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementProperties.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementProperties.java @@ -306,7 +306,6 @@ public static void registerTags() { // The width used is based on the vanilla minecraft font. This will not be accurate for other fonts. // This only currently supports ASCII symbols properly. Unicode symbols will be estimated as 6 pixels. // Spaces will be preferred to become newlines, unless a line does not contain any spaces. - // This will transfer colors over to new lines as well. // --> PropertyParser.registerStaticTag(ElementTag.class, "split_lines_by_width", (attribute, object) -> { int width = attribute.getIntParam(); @@ -321,7 +320,7 @@ public static void registerTags() { // Returns the width, in pixels, of the text. // The width used is based on the vanilla minecraft font. This will not be accurate for other fonts. // This only currently supports ASCII symbols properly. Unicode symbols will be estimated as 6 pixels. - // This will not work well with elements that contain newlines. + // If the element contains newlines, will return the widest line width. // --> PropertyParser.registerStaticTag(ElementTag.class, "text_width", (attribute, object) -> { return new ElementTag(TextWidthHelper.getWidth(object.asString())); diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/TextWidthHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/TextWidthHelper.java index 7f23af19d7..0e75fe911a 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/TextWidthHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/TextWidthHelper.java @@ -1,5 +1,8 @@ package com.denizenscript.denizen.utilities; +import com.denizenscript.denizencore.utilities.AsciiMatcher; +import org.bukkit.ChatColor; + public class TextWidthHelper { public static int[] characterWidthMap = new int[128]; @@ -26,15 +29,59 @@ public static int getWidth(char c) { return c > 127 ? 6 : characterWidthMap[c]; } + public static AsciiMatcher formatCharCodeMatcher = new AsciiMatcher("klmnoKLMNO"); + public static int getWidth(String str) { + int maxWidth = 0; int total = 0; - for (char c : str.toCharArray()) { - total += getWidth(c); + boolean bold = false; + char[] rawChars = str.toCharArray(); + for (int i = 0; i < rawChars.length; i++) { + char c = rawChars[i]; + if (c == ChatColor.COLOR_CHAR && (i + 1) < rawChars.length) { + char c2 = rawChars[i + 1]; + if (c2 == '[') { + while (i < rawChars.length && rawChars[i] != ']') { + i++; + } + continue; + } + else if (c2 == 'l' || c2 == 'L') { + bold = true; + } + else if (!formatCharCodeMatcher.isMatch(c2)) { + bold = false; + } + i++; + continue; + } + total += getWidth(c) + (bold ? 2 : 0); if (c == '\n') { + if (total > maxWidth) { + maxWidth = total; + } total = 0; } } - return total; + return Math.max(total, maxWidth); + } + + public static boolean isBold(boolean wasBold, String str) { + boolean bold = wasBold; + char[] rawChars = str.toCharArray(); + for (int i = 0; i < rawChars.length; i++) { + char c = rawChars[i]; + if (c == ChatColor.COLOR_CHAR && (i + 1) < rawChars.length) { + char c2 = rawChars[i + 1]; + if (c2 == 'l' || c2 == 'L') { + bold = true; + } + else if (!formatCharCodeMatcher.isMatch(c2)) { + bold = false; + } + } + } + return bold; } public static String splitLines(String str, int width) { @@ -42,31 +89,33 @@ public static String splitLines(String str, int width) { return str; } StringBuilder output = new StringBuilder(str.length() * 2); - int curLineWidth = 0; int lineStart = 0; + boolean bold = false; mainloop: for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '\n') { - output.append(str, lineStart, i + 1); - curLineWidth = 0; + String lastLine = str.substring(lineStart, i + 1); + bold = isBold(bold, lastLine); + output.append(lastLine); lineStart = i + 1; continue; } - curLineWidth += getWidth(c); - if (curLineWidth > width) { + if (getWidth(((bold ? ChatColor.BOLD.toString() : "") + str.substring(lineStart, i))) > width) { for (int x = i - 1; x > lineStart; x--) { char xc = str.charAt(x); if (xc == ' ') { - output.append(str, lineStart, x).append("\n"); - curLineWidth = 0; + String lastLine = str.substring(lineStart, x); + bold = isBold(bold, lastLine); + output.append(lastLine).append("\n"); lineStart = x + 1; i = x; continue mainloop; } } - output.append(str, lineStart, i).append("\n"); - curLineWidth = 0; + String lastLine = str.substring(lineStart, i); + bold = isBold(bold, lastLine); + output.append(lastLine).append("\n"); lineStart = i; } }