From 2a0ee4b65d63043564b0dfe001c7f9804a07b477 Mon Sep 17 00:00:00 2001 From: Josh Roy Date: Sat, 20 Feb 2021 13:12:58 -0500 Subject: [PATCH] Add support for hex color codes in console --- ...pport-for-hex-color-codes-in-console.patch | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 Spigot-Server-Patches/0676-Add-support-for-hex-color-codes-in-console.patch diff --git a/Spigot-Server-Patches/0676-Add-support-for-hex-color-codes-in-console.patch b/Spigot-Server-Patches/0676-Add-support-for-hex-color-codes-in-console.patch new file mode 100644 index 0000000000..dc392d5529 --- /dev/null +++ b/Spigot-Server-Patches/0676-Add-support-for-hex-color-codes-in-console.patch @@ -0,0 +1,224 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Roy <10731363+JRoy@users.noreply.github.com> +Date: Sat, 20 Feb 2021 13:09:59 -0500 +Subject: [PATCH] Add support for hex color codes in console + +Converts upstream's hex color code legacy format into actual hex color codes in the console. + +diff --git a/src/main/java/io/papermc/paper/console/HexFormattingConverter.java b/src/main/java/io/papermc/paper/console/HexFormattingConverter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d51db8864fce4b7eade5f39d84329a3f8591611d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/HexFormattingConverter.java +@@ -0,0 +1,181 @@ ++package io.papermc.paper.console; ++ ++import net.minecrell.terminalconsole.TerminalConsoleAppender; ++import org.apache.logging.log4j.core.LogEvent; ++import org.apache.logging.log4j.core.config.Configuration; ++import org.apache.logging.log4j.core.config.plugins.Plugin; ++import org.apache.logging.log4j.core.layout.PatternLayout; ++import org.apache.logging.log4j.core.pattern.*; ++import org.apache.logging.log4j.util.PerformanceSensitive; ++import org.apache.logging.log4j.util.PropertiesUtil; ++ ++import java.awt.*; ++import java.util.List; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; ++ ++import static net.minecrell.terminalconsole.MinecraftFormattingConverter.KEEP_FORMATTING_PROPERTY; ++ ++/** ++ * Modified version of ++ * TerminalConsoleAppender's MinecraftFormattingConverter to support hex color codes using the md_5 &x&r&r&g&g&b&b format. ++ */ ++@Plugin(name = "paperMinecraftFormatting", category = PatternConverter.CATEGORY) ++@ConverterKeys({ "paperMinecraftFormatting" }) ++@PerformanceSensitive("allocation") ++public final class HexFormattingConverter extends LogEventPatternConverter { ++ ++ private static final boolean KEEP_FORMATTING = PropertiesUtil.getProperties().getBooleanProperty(KEEP_FORMATTING_PROPERTY); ++ ++ private static final String ANSI_RESET = "\u001B[m"; ++ ++ private static final char COLOR_CHAR = '§'; ++ private static final String LOOKUP = "0123456789abcdefklmnor"; ++ ++ private static final String RGB_ANSI = "\u001B[38;2;%d;%d;%dm"; ++ private static final Pattern RGB_PATTERN = Pattern.compile(COLOR_CHAR + "x(" + COLOR_CHAR + "[0-9a-fA-F]){6}"); ++ ++ private static final String[] ansiCodes = new String[] { ++ "\u001B[0;30m", // Black §0 ++ "\u001B[0;34m", // Dark Blue §1 ++ "\u001B[0;32m", // Dark Green §2 ++ "\u001B[0;36m", // Dark Aqua §3 ++ "\u001B[0;31m", // Dark Red §4 ++ "\u001B[0;35m", // Dark Purple §5 ++ "\u001B[0;33m", // Gold §6 ++ "\u001B[0;37m", // Gray §7 ++ "\u001B[0;30;1m", // Dark Gray §8 ++ "\u001B[0;34;1m", // Blue §9 ++ "\u001B[0;32;1m", // Green §a ++ "\u001B[0;36;1m", // Aqua §b ++ "\u001B[0;31;1m", // Red §c ++ "\u001B[0;35;1m", // Light Purple §d ++ "\u001B[0;33;1m", // Yellow §e ++ "\u001B[0;37;1m", // White §f ++ "\u001B[5m", // Obfuscated §k ++ "\u001B[21m", // Bold §l ++ "\u001B[9m", // Strikethrough §m ++ "\u001B[4m", // Underline §n ++ "\u001B[3m", // Italic §o ++ ANSI_RESET, // Reset §r ++ }; ++ ++ private final boolean ansi; ++ private final List formatters; ++ ++ /** ++ * Construct the converter. ++ * ++ * @param formatters The pattern formatters to generate the text to manipulate ++ * @param strip If true, the converter will strip all formatting codes ++ */ ++ protected HexFormattingConverter(List formatters, boolean strip) { ++ super("minecraftFormatting", null); ++ this.formatters = formatters; ++ this.ansi = !strip; ++ } ++ ++ @Override ++ public void format(LogEvent event, StringBuilder toAppendTo) { ++ int start = toAppendTo.length(); ++ //noinspection ForLoopReplaceableByForEach ++ for (int i = 0, size = formatters.size(); i < size; i++) { ++ formatters.get(i).format(event, toAppendTo); ++ } ++ ++ if (KEEP_FORMATTING || toAppendTo.length() == start) { ++ // Skip replacement if disabled or if the content is empty ++ return; ++ } ++ ++ boolean useAnsi = ansi && TerminalConsoleAppender.isAnsiSupported(); ++ String content = useAnsi ? convertRGBColors(toAppendTo.substring(start)) : stripRGBColors(toAppendTo.substring(start)); ++ format(content, toAppendTo, start, useAnsi); ++ } ++ ++ private static String convertRGBColors(String input) { ++ Matcher matcher = RGB_PATTERN.matcher(input); ++ StringBuffer buffer = new StringBuffer(); ++ while (matcher.find()) { ++ String s = matcher.group().replace(String.valueOf(COLOR_CHAR), "").replace('x', '#'); ++ Color color = Color.decode(s); ++ int red = color.getRed(); ++ int blue = color.getBlue(); ++ int green = color.getGreen(); ++ String replacement = String.format(RGB_ANSI, red, green, blue); ++ matcher.appendReplacement(buffer, replacement); ++ } ++ matcher.appendTail(buffer); ++ return buffer.toString(); ++ } ++ ++ private static String stripRGBColors(String input) { ++ Matcher matcher = RGB_PATTERN.matcher(input); ++ StringBuffer buffer = new StringBuffer(); ++ while (matcher.find()) { ++ matcher.appendReplacement(buffer, ""); ++ } ++ matcher.appendTail(buffer); ++ return buffer.toString(); ++ } ++ ++ static void format(String s, StringBuilder result, int start, boolean ansi) { ++ int next = s.indexOf(COLOR_CHAR); ++ int last = s.length() - 1; ++ if (next == -1 || next == last) { ++ return; ++ } ++ ++ result.setLength(start + next); ++ ++ int pos = next; ++ do { ++ int format = LOOKUP.indexOf(Character.toLowerCase(s.charAt(next + 1))); ++ if (format != -1) { ++ if (pos != next) { ++ result.append(s, pos, next); ++ } ++ if (ansi) { ++ result.append(ansiCodes[format]); ++ } ++ pos = next += 2; ++ } else { ++ next++; ++ } ++ ++ next = s.indexOf(COLOR_CHAR, next); ++ } while (next != -1 && next < last); ++ ++ result.append(s, pos, s.length()); ++ if (ansi) { ++ result.append(ANSI_RESET); ++ } ++ } ++ ++ /** ++ * Gets a new instance of the {@link HexFormattingConverter} with the ++ * specified options. ++ * ++ * @param config The current configuration ++ * @param options The pattern options ++ * @return The new instance ++ * ++ * @see HexFormattingConverter ++ */ ++ public static HexFormattingConverter newInstance(Configuration config, String[] options) { ++ if (options.length < 1 || options.length > 2) { ++ LOGGER.error("Incorrect number of options on paperMinecraftFormatting. Expected at least 1, max 2 received " + options.length); ++ return null; ++ } ++ if (options[0] == null) { ++ LOGGER.error("No pattern supplied on paperMinecraftFormatting"); ++ return null; ++ } ++ ++ PatternParser parser = PatternLayout.createPatternParser(config); ++ List formatters = parser.parse(options[0]); ++ boolean strip = options.length > 1 && "strip".equals(options[1]); ++ return new HexFormattingConverter(formatters, strip); ++ } ++ ++} +diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml +index 8af159abd3d0cc94cf155fec5b384c42f69551bf..67da1aa7a21622fb231d19dede3775a282a4a12e 100644 +--- a/src/main/resources/log4j2.xml ++++ b/src/main/resources/log4j2.xml +@@ -6,21 +6,21 @@ + + + +- ++ + + + ++ pattern="%highlightError{[%d{HH:mm:ss} %level]: %paperMinecraftFormatting{%msg}%n%xEx{full}}" /> + + + + + +- ++ + + + ++ pattern="[%d{HH:mm:ss}] [%t/%level]: %paperMinecraftFormatting{%msg}{strip}%n%xEx{full}" /> + + +