From 6925d11945c2bbe7e752aa892cdcb7724199495a Mon Sep 17 00:00:00 2001 From: Emilia Kond Date: Tue, 13 Jun 2023 01:00:12 +0300 Subject: [PATCH] Use net.kyori.ansi for console logging (#9313) Uses the new ANSIComponentSerializer introduced in Adventure 4.14.0 to serialize components when logging them via the ComponentLogger, or when sending messages to the console. This replaces the old solution which uses legacy jank and custom color conversions, with a new library that handles the conversion and config --- ...pport-for-hex-color-codes-in-console.patch | 327 ------------------ ...ktraces-in-log-messages-crash-report.patch | 8 - ...n-prefixes-using-Log4J-configuration.patch | 14 +- ...e-Log4J-Configuration-Plugin-Loggers.patch | 16 +- patches/server/Paper-config-files.patch | 4 +- ...oleAppender-for-console-improvements.patch | 145 +++++++- 6 files changed, 156 insertions(+), 358 deletions(-) delete mode 100644 patches/server/Add-support-for-hex-color-codes-in-console.patch diff --git a/patches/server/Add-support-for-hex-color-codes-in-console.patch b/patches/server/Add-support-for-hex-color-codes-in-console.patch deleted file mode 100644 index 33fa37d21f..0000000000 --- a/patches/server/Add-support-for-hex-color-codes-in-console.patch +++ /dev/null @@ -1,327 +0,0 @@ -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/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java -+++ b/src/main/java/com/destroystokyo/paper/console/TerminalConsoleCommandSender.java -@@ -0,0 +0,0 @@ - package com.destroystokyo.paper.console; - -+import net.kyori.adventure.audience.MessageType; -+import net.kyori.adventure.identity.Identity; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.logger.slf4j.ComponentLogger; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; - import org.apache.logging.log4j.LogManager; --import org.apache.logging.log4j.Logger; - import org.bukkit.craftbukkit.command.CraftConsoleCommandSender; - - public class TerminalConsoleCommandSender extends CraftConsoleCommandSender { - -- private static final Logger LOGGER = LogManager.getRootLogger(); -+ private static final ComponentLogger LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName()); - - @Override - public void sendRawMessage(String message) { -- // TerminalConsoleAppender supports color codes directly in log messages -+ final Component msg = LegacyComponentSerializer.legacySection().deserialize(message); -+ this.sendMessage(Identity.nil(), msg, MessageType.SYSTEM); -+ } -+ -+ @Override -+ public void sendMessage(Identity identity, Component message, MessageType type) { - LOGGER.info(message); - } - -diff --git a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java -+++ b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java -@@ -0,0 +0,0 @@ - package io.papermc.paper.adventure.providers; - --import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.console.HexFormattingConverter; -+import java.util.Locale; - import net.kyori.adventure.text.Component; - import net.kyori.adventure.text.logger.slf4j.ComponentLogger; - import net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider; -+import net.kyori.adventure.translation.GlobalTranslator; - import org.jetbrains.annotations.NotNull; - import org.slf4j.LoggerFactory; - -@@ -0,0 +0,0 @@ public class ComponentLoggerProviderImpl implements ComponentLoggerProvider { - } - - private String serialize(final Component message) { -- return PaperAdventure.asPlain(message, null); -+ return HexFormattingConverter.SERIALIZER.serialize(GlobalTranslator.render(message, Locale.getDefault())); - } - } -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..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/console/HexFormattingConverter.java -@@ -0,0 +0,0 @@ -+package io.papermc.paper.console; -+ -+import io.papermc.paper.configuration.GlobalConfiguration; -+import io.papermc.paper.adventure.PaperAdventure; -+import net.kyori.adventure.text.format.NamedTextColor; -+import net.kyori.adventure.text.format.TextColor; -+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -+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.ConverterKeys; -+import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; -+import org.apache.logging.log4j.core.pattern.PatternConverter; -+import org.apache.logging.log4j.core.pattern.PatternFormatter; -+import org.apache.logging.log4j.core.pattern.PatternParser; -+import org.apache.logging.log4j.util.PerformanceSensitive; -+import org.apache.logging.log4j.util.PropertiesUtil; -+ -+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 Adventure [char]#rrggbb 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 = 0x7f; -+ public static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder() -+ .hexColors() -+ .flattener(PaperAdventure.FLATTENER) -+ .character(HexFormattingConverter.COLOR_CHAR) -+ .build(); -+ private static final String LOOKUP = "0123456789abcdefklmnor"; -+ -+ private static final String RGB_ANSI = "\u001B[38;2;%d;%d;%dm"; -+ private static final String RESET_RGB_ANSI = ANSI_RESET + RGB_ANSI; -+ private static final Pattern NAMED_PATTERN = Pattern.compile(COLOR_CHAR + "[0-9a-fk-orA-FK-OR]"); -+ private static final Pattern RGB_PATTERN = Pattern.compile(COLOR_CHAR + "#([0-9a-fA-F]){6}"); -+ -+ private static final String[] RGB_ANSI_CODES = new String[]{ -+ formatHexAnsi(NamedTextColor.BLACK), // Black §0 -+ formatHexAnsi(NamedTextColor.DARK_BLUE), // Dark Blue §1 -+ formatHexAnsi(NamedTextColor.DARK_GREEN), // Dark Green §2 -+ formatHexAnsi(NamedTextColor.DARK_AQUA), // Dark Aqua §3 -+ formatHexAnsi(NamedTextColor.DARK_RED), // Dark Red §4 -+ formatHexAnsi(NamedTextColor.DARK_PURPLE), // Dark Purple §5 -+ formatHexAnsi(NamedTextColor.GOLD), // Gold §6 -+ formatHexAnsi(NamedTextColor.GRAY), // Gray §7 -+ formatHexAnsi(NamedTextColor.DARK_GRAY), // Dark Gray §8 -+ formatHexAnsi(NamedTextColor.BLUE), // Blue §9 -+ formatHexAnsi(NamedTextColor.GREEN), // Green §a -+ formatHexAnsi(NamedTextColor.AQUA), // Aqua §b -+ formatHexAnsi(NamedTextColor.RED), // Red §c -+ formatHexAnsi(NamedTextColor.LIGHT_PURPLE), // Light Purple §d -+ formatHexAnsi(NamedTextColor.YELLOW), // Yellow §e -+ formatHexAnsi(NamedTextColor.WHITE), // White §f -+ "\u001B[5m", // Obfuscated §k -+ "\u001B[1m", // Bold §l -+ "\u001B[9m", // Strikethrough §m -+ "\u001B[4m", // Underline §n -+ "\u001B[3m", // Italic §o -+ ANSI_RESET, // Reset §r -+ }; -+ private static final String[] ANSI_ANSI_CODES = new String[]{ -+ ANSI_RESET + "\u001B[0;30m", // Black §0 -+ ANSI_RESET + "\u001B[0;34m", // Dark Blue §1 -+ ANSI_RESET + "\u001B[0;32m", // Dark Green §2 -+ ANSI_RESET + "\u001B[0;36m", // Dark Aqua §3 -+ ANSI_RESET + "\u001B[0;31m", // Dark Red §4 -+ ANSI_RESET + "\u001B[0;35m", // Dark Purple §5 -+ ANSI_RESET + "\u001B[0;33m", // Gold §6 -+ ANSI_RESET + "\u001B[0;37m", // Gray §7 -+ ANSI_RESET + "\u001B[0;30;1m", // Dark Gray §8 -+ ANSI_RESET + "\u001B[0;34;1m", // Blue §9 -+ ANSI_RESET + "\u001B[0;32;1m", // Green §a -+ ANSI_RESET + "\u001B[0;36;1m", // Aqua §b -+ ANSI_RESET + "\u001B[0;31;1m", // Red §c -+ ANSI_RESET + "\u001B[0;35;1m", // Light Purple §d -+ ANSI_RESET + "\u001B[0;33;1m", // Yellow §e -+ ANSI_RESET + "\u001B[0;37;1m", // White §f -+ "\u001B[5m", // Obfuscated §k -+ "\u001B[1m", // 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("paperMinecraftFormatting", 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 = toAppendTo.substring(start); -+ content = useAnsi ? convertRGBColors(content) : stripRGBColors(content); -+ format(content, toAppendTo, start, useAnsi); -+ } -+ -+ private static String convertRGBColors(final String input) { -+ return RGB_PATTERN.matcher(input).replaceAll(result -> { -+ final int hex = Integer.decode(result.group().substring(1)); -+ return formatHexAnsi(hex); -+ }); -+ } -+ -+ private static String formatHexAnsi(final TextColor color) { -+ return formatHexAnsi(color.value()); -+ } -+ -+ private static String formatHexAnsi(final int color) { -+ final int red = color >> 16 & 0xFF; -+ final int green = color >> 8 & 0xFF; -+ final int blue = color & 0xFF; -+ return String.format(RESET_RGB_ANSI, red, green, blue); -+ } -+ -+ private static String stripRGBColors(final String input) { -+ return RGB_PATTERN.matcher(input).replaceAll(""); -+ } -+ -+ static void format(String content, StringBuilder result, int start, boolean ansi) { -+ int next = content.indexOf(COLOR_CHAR); -+ int last = content.length() - 1; -+ if (next == -1 || next == last) { -+ result.setLength(start); -+ result.append(content); -+ if (ansi) { -+ result.append(ANSI_RESET); -+ } -+ return; -+ } -+ -+ Matcher matcher = NAMED_PATTERN.matcher(content); -+ StringBuilder buffer = new StringBuilder(); -+ final String[] ansiCodes = GlobalConfiguration.get().logging.useRgbForNamedTextColors ? RGB_ANSI_CODES : ANSI_ANSI_CODES; -+ while (matcher.find()) { -+ int format = LOOKUP.indexOf(Character.toLowerCase(matcher.group().charAt(1))); -+ if (format != -1) { -+ matcher.appendReplacement(buffer, ansi ? ansiCodes[format] : ""); -+ } -+ } -+ matcher.appendTail(buffer); -+ -+ result.setLength(start); -+ result.append(buffer); -+ 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/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop - - -- -+ - - - -+ 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}" /> - - - diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index 0d9b3a0693..6d4ff62aea 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -9,14 +9,6 @@ diff --git a/build.gradle.kts b/build.gradle.kts index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -0,0 +0,0 @@ dependencies { - Scanning takes about 1-2 seconds so adding this speeds up the server start. - */ - implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation -+ annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins - // Paper end - implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion - implementation("org.ow2.asm:asm:9.4") @@ -0,0 +0,0 @@ dependencies { testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files diff --git a/patches/server/Handle-plugin-prefixes-using-Log4J-configuration.patch b/patches/server/Handle-plugin-prefixes-using-Log4J-configuration.patch index 150d84a271..cf13c857ce 100644 --- a/patches/server/Handle-plugin-prefixes-using-Log4J-configuration.patch +++ b/patches/server/Handle-plugin-prefixes-using-Log4J-configuration.patch @@ -24,9 +24,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ - runtimeOnly("org.apache.logging.log4j:log4j-core:2.14.1") + implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation + annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins // Paper end implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion - implementation("org.ow2.asm:asm:9.4") diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/SpigotConfig.java @@ -48,22 +48,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 -- +- + -+ ++ + + ++ pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" /> + + -- +- + -+ ++ + + ++ pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" /> + + diff --git a/patches/server/Improve-Log4J-Configuration-Plugin-Loggers.patch b/patches/server/Improve-Log4J-Configuration-Plugin-Loggers.patch index 4258e756b5..4cd4de018f 100644 --- a/patches/server/Improve-Log4J-Configuration-Plugin-Loggers.patch +++ b/patches/server/Improve-Log4J-Configuration-Plugin-Loggers.patch @@ -21,27 +21,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 -- -+ +- ++ - +- pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx}" /> + + ++ pattern="%highlightError{[%d{HH:mm:ss} %level]: %msg%n%xEx{full}}" /> -- -+ +- ++ - +- pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n" /> + + ++ pattern="[%d{HH:mm:ss}] [%t/%level]: %stripAnsi{%msg}%n%xEx{full}" /> diff --git a/patches/server/Paper-config-files.patch b/patches/server/Paper-config-files.patch index 7657bb6be0..387d8beb5c 100644 --- a/patches/server/Paper-config-files.patch +++ b/patches/server/Paper-config-files.patch @@ -604,7 +604,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public class Logging extends ConfigurationPart { + public boolean logPlayerIpAddresses = true; + public boolean deobfuscateStacktraces = true; -+ public boolean useRgbForNamedTextColors = true; + } + + public Scoreboards scoreboards; @@ -1442,7 +1441,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + path("commandErrorMessage"), + path("baby-zombie-movement-speed"), + path("limit-player-interactions"), -+ path("warnWhenSettingExcessiveVelocity") ++ path("warnWhenSettingExcessiveVelocity"), ++ path("logging", "use-rgb-for-named-text-colors") + }; + +} diff --git a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch index 3f2fd691de..597f10fe61 100644 --- a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch @@ -6,6 +6,10 @@ Subject: [PATCH] Use TerminalConsoleAppender for console improvements Rewrite console improvements (console colors, tab completion, persistent input line, ...) using JLine 3.x and TerminalConsoleAppender. +Also uses the new ANSIComponentSerializer to serialize components when +logging them via the ComponentLogger, or when sending messages to the +console, for hex color support. + New features: - Support console colors for Vanilla commands - Add console colors for warnings and errors @@ -18,6 +22,8 @@ Other changes: - Server starts 1-2 seconds faster thanks to optimizations in Log4j configuration +Co-Authored-By: Emilia Kond + diff --git a/build.gradle.kts b/build.gradle.kts index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/build.gradle.kts @@ -30,6 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + implementation("org.jline:jline-terminal-jansi:3.21.0") + implementation("net.minecrell:terminalconsoleappender:1.3.0") ++ implementation("net.kyori:adventure-text-serializer-ansi") + /* + Required to add the missing Log4j2Plugins.dat file from log4j-core + which has been removed by Mojang. Without it, log4j has to classload @@ -37,6 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + Scanning takes about 1-2 seconds so adding this speeds up the server start. + */ + runtimeOnly("org.apache.logging.log4j:log4j-core:2.14.1") ++ annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins + // Paper end implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion implementation("org.ow2.asm:asm:9.4") @@ -96,21 +104,133 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package com.destroystokyo.paper.console; + ++import net.kyori.adventure.audience.MessageType; ++import net.kyori.adventure.identity.Identity; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.logger.slf4j.ComponentLogger; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; +import org.bukkit.craftbukkit.command.CraftConsoleCommandSender; + +public class TerminalConsoleCommandSender extends CraftConsoleCommandSender { + -+ private static final Logger LOGGER = LogManager.getRootLogger(); ++ private static final ComponentLogger LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName()); + + @Override + public void sendRawMessage(String message) { -+ // TerminalConsoleAppender supports color codes directly in log messages ++ final Component msg = LegacyComponentSerializer.legacySection().deserialize(message); ++ this.sendMessage(Identity.nil(), msg, MessageType.SYSTEM); ++ } ++ ++ @Override ++ public void sendMessage(Identity identity, Component message, MessageType type) { + LOGGER.info(message); + } + +} +diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java ++++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +@@ -0,0 +0,0 @@ import net.kyori.adventure.text.TranslatableComponent; + import net.kyori.adventure.text.flattener.ComponentFlattener; + import net.kyori.adventure.text.format.TextColor; + import net.kyori.adventure.text.serializer.ComponentSerializer; ++import net.kyori.adventure.text.serializer.ansi.ANSIComponentSerializer; + import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; + import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; + import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +@@ -0,0 +0,0 @@ public final class PaperAdventure { + public static final AttributeKey LOCALE_ATTRIBUTE = AttributeKey.valueOf("adventure:locale"); // init after FLATTENER because classloading triggered here might create a logger + @Deprecated + public static final PlainComponentSerializer PLAIN = PlainComponentSerializer.builder().flattener(FLATTENER).build(); ++ ++ public static final ANSIComponentSerializer ANSI_SERIALIZER = ANSIComponentSerializer.builder().flattener(FLATTENER).build(); ++ + private static final Codec NBT_CODEC = new Codec() { + @Override + public @NotNull CompoundTag decode(final @NotNull String encoded) throws IOException { +diff --git a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java ++++ b/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java +@@ -0,0 +0,0 @@ + package io.papermc.paper.adventure.providers; + + import io.papermc.paper.adventure.PaperAdventure; ++import java.util.Locale; + import net.kyori.adventure.text.Component; + import net.kyori.adventure.text.logger.slf4j.ComponentLogger; + import net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider; ++import net.kyori.adventure.translation.GlobalTranslator; + import org.jetbrains.annotations.NotNull; + import org.slf4j.LoggerFactory; + +@@ -0,0 +0,0 @@ public class ComponentLoggerProviderImpl implements ComponentLoggerProvider { + } + + private String serialize(final Component message) { +- return PaperAdventure.asPlain(message, null); ++ return PaperAdventure.ANSI_SERIALIZER.serialize(GlobalTranslator.render(message, Locale.getDefault())); + } + } +diff --git a/src/main/java/io/papermc/paper/console/StripANSIConverter.java b/src/main/java/io/papermc/paper/console/StripANSIConverter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/console/StripANSIConverter.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.console; ++ ++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.ConverterKeys; ++import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; ++import org.apache.logging.log4j.core.pattern.PatternConverter; ++import org.apache.logging.log4j.core.pattern.PatternFormatter; ++import org.apache.logging.log4j.core.pattern.PatternParser; ++ ++import java.util.List; ++import java.util.regex.Pattern; ++ ++@Plugin(name = "stripAnsi", category = PatternConverter.CATEGORY) ++@ConverterKeys({"stripAnsi"}) ++public final class StripANSIConverter extends LogEventPatternConverter { ++ final private Pattern ANSI_PATTERN = Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); ++ ++ private final List formatters; ++ ++ private StripANSIConverter(List formatters) { ++ super("stripAnsi", null); ++ this.formatters = formatters; ++ } ++ ++ @Override ++ public void format(LogEvent event, StringBuilder toAppendTo) { ++ int start = toAppendTo.length(); ++ for (PatternFormatter formatter : formatters) { ++ formatter.format(event, toAppendTo); ++ } ++ String content = toAppendTo.substring(start); ++ content = ANSI_PATTERN.matcher(content).replaceAll(""); ++ ++ toAppendTo.setLength(start); ++ toAppendTo.append(content); ++ } ++ ++ public static StripANSIConverter newInstance(Configuration config, String[] options) { ++ if (options.length != 1) { ++ LOGGER.error("Incorrect number of options on stripAnsi. Expected exactly 1, received " + options.length); ++ return null; ++ } ++ ++ PatternParser parser = PatternLayout.createPatternParser(config); ++ List formatters = parser.parse(options[0]); ++ return new StripANSIConverter(formatters); ++ } ++} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -166,7 +286,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override public void sendSystemMessage(Component message) { - MinecraftServer.LOGGER.info(message.getString()); -+ MinecraftServer.LOGGER.info(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(io.papermc.paper.adventure.PaperAdventure.asAdventure(message))); // Paper - Log message with colors ++ MinecraftServer.LOGGER.info(io.papermc.paper.adventure.PaperAdventure.ANSI_SERIALIZER.serialize(io.papermc.paper.adventure.PaperAdventure.asAdventure(message))); // Paper - Log message with colors } public KeyPair getKeyPair() { @@ -221,6 +341,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream()); System.setErr(IoBuilder.forLogger(logger).setLevel(Level.WARN).buildPrintStream()); +diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java ++++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java +@@ -0,0 +0,0 @@ public class MinecraftServerGui extends JComponent { + this.finalizers.forEach(Runnable::run); + } + +- private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})*)?[m|K]"); // CraftBukkit ++ private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\e\\[[\\d;]*[^\\d;]"); // CraftBukkit // Paper + public void print(JTextArea textArea, JScrollPane scrollPane, String message) { + if (!SwingUtilities.isEventDispatchThread()) { + SwingUtilities.invokeLater(() -> { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java @@ -495,11 +628,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - + -+ ++ + - -+ ++