mirror of
https://github.com/PaperMC/Waterfall.git
synced 2024-12-27 11:07:39 +01:00
Add support for hex color codes in console (#612)
This commit is contained in:
parent
2c5c9541c9
commit
565c857605
@ -0,0 +1,250 @@
|
||||
From b7f679467cba1cb04945ab2c777b8020a2be03d9 Mon Sep 17 00:00:00 2001
|
||||
From: Josh Roy <10731363+JRoy@users.noreply.github.com>
|
||||
Date: Sun, 21 Feb 2021 23:52:11 -0500
|
||||
Subject: [PATCH] Add support for hex color codes in console
|
||||
|
||||
Ports my Paper patch which converts upstream's hex color code legacy format into actual hex color codes in the console.
|
||||
|
||||
diff --git a/log4j/src/main/resources/log4j2-bungee.xml b/log4j/src/main/resources/log4j2-bungee.xml
|
||||
index 6e9c09c5..1c3265ed 100644
|
||||
--- a/log4j/src/main/resources/log4j2-bungee.xml
|
||||
+++ b/log4j/src/main/resources/log4j2-bungee.xml
|
||||
@@ -4,17 +4,17 @@
|
||||
<Appenders>
|
||||
<TerminalConsole name="TerminalConsole">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="%highlightError{%d{HH:mm:ss} [%level] [%logger] %minecraftFormatting{%msg}%n%ex}">
|
||||
+ <LoggerNamePatternSelector defaultPattern="%highlightError{%d{HH:mm:ss} [%level] [%logger] %paperMinecraftFormatting{%msg}%n%ex}">
|
||||
<!-- Log root and BungeeCord loggers without prefix -->
|
||||
- <PatternMatch key=",BungeeCord" pattern="%highlightError{%d{HH:mm:ss} [%level] %minecraftFormatting{%msg}%n%ex}" />
|
||||
+ <PatternMatch key=",BungeeCord" pattern="%highlightError{%d{HH:mm:ss} [%level] %paperMinecraftFormatting{%msg}%n%ex}" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
</TerminalConsole>
|
||||
<RollingRandomAccessFile name="File" fileName="proxy.log.0" filePattern="proxy.log.%i" immediateFlush="false">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="%d{HH:mm:ss} [%level] [%logger] %minecraftFormatting{%msg}{strip}%n%ex">
|
||||
+ <LoggerNamePatternSelector defaultPattern="%d{HH:mm:ss} [%level] [%logger] %paperMinecraftFormatting{%msg}{strip}%n%ex">
|
||||
<!-- Log root and BungeeCord loggers without prefix -->
|
||||
- <PatternMatch key=",BungeeCord" pattern="%d{HH:mm:ss} [%level] %minecraftFormatting{%msg}{strip}%n%ex" />
|
||||
+ <PatternMatch key=",BungeeCord" pattern="%d{HH:mm:ss} [%level] %paperMinecraftFormatting{%msg}{strip}%n%ex" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
diff --git a/log4j/src/main/resources/log4j2.xml b/log4j/src/main/resources/log4j2.xml
|
||||
index 3b3525f0..a42d63fa 100644
|
||||
--- a/log4j/src/main/resources/log4j2.xml
|
||||
+++ b/log4j/src/main/resources/log4j2.xml
|
||||
@@ -3,17 +3,17 @@
|
||||
<Appenders>
|
||||
<TerminalConsole name="TerminalConsole">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level] [%logger]: %minecraftFormatting{%msg}%n%xEx}">
|
||||
+ <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level] [%logger]: %paperMinecraftFormatting{%msg}%n%xEx}">
|
||||
<!-- Log root and BungeeCord loggers without prefix -->
|
||||
- <PatternMatch key=",BungeeCord" pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx}" />
|
||||
+ <PatternMatch key=",BungeeCord" pattern="%highlightError{[%d{HH:mm:ss} %level]: %paperMinecraftFormatting{%msg}%n%xEx}" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
</TerminalConsole>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz" immediateFlush="false">
|
||||
<PatternLayout>
|
||||
- <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %minecraftFormatting{%msg}{strip}%n">
|
||||
+ <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level] [%logger]: %paperMinecraftFormatting{%msg}{strip}%n">
|
||||
<!-- Log root and BungeeCord loggers without prefix -->
|
||||
- <PatternMatch key=",BungeeCord" pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n" />
|
||||
+ <PatternMatch key=",BungeeCord" pattern="[%d{HH:mm:ss}] [%t/%level]: %paperMinecraftFormatting{%msg}{strip}%n" />
|
||||
</LoggerNamePatternSelector>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/console/HexFormattingConverter.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/console/HexFormattingConverter.java
|
||||
new file mode 100644
|
||||
index 00000000..eee3cdd6
|
||||
--- /dev/null
|
||||
+++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/console/HexFormattingConverter.java
|
||||
@@ -0,0 +1,182 @@
|
||||
+package io.github.waterfallmc.waterfall.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 <a href="https://github.com/Minecrell/TerminalConsoleAppender/blob/master/src/main/java/net/minecrell/terminalconsole/MinecraftFormattingConverter.java">
|
||||
+ * TerminalConsoleAppender's MinecraftFormattingConverter</a> 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<PatternFormatter> 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<PatternFormatter> 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<PatternFormatter> formatters = parser.parse(options[0]);
|
||||
+ boolean strip = options.length > 1 && "strip".equals(options[1]);
|
||||
+ return new HexFormattingConverter(formatters, strip);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
--
|
||||
2.25.1
|
||||
|
Loading…
Reference in New Issue
Block a user