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 33fa37d21..000000000
--- 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 0d9b3a069..6d4ff62ae 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 150d84a27..cf13c857c 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 4258e756b..4cd4de018 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 7657bb6be..387d8beb5 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 3f2fd691d..597f10fe6 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
-
-
+
-+
++
+
-
-+
++