From 840318bd8b76ae4d4a4169e17c3a396355394d81 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:04:44 -0500 Subject: [PATCH] Optimize MessageTranslator to not use regex Regexes take up a performance penalty that we can circumvent by iterating over the legacy string once and applying the necessary workarounds. --- .../translator/text/MessageTranslator.java | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java index 68d79dc4f..abce22ff8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java @@ -34,13 +34,13 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.MinecraftTranslationRegistry; -import org.geysermc.geyser.text.GsonComponentSerializerWrapper; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.text.GsonComponentSerializerWrapper; +import org.geysermc.geyser.text.MinecraftTranslationRegistry; import java.util.EnumMap; import java.util.Map; -import java.util.regex.Pattern; public class MessageTranslator { // These are used for handling the translations of the messages @@ -59,11 +59,6 @@ public class MessageTranslator { // Reset character private static final String RESET = BASE + "r"; - /* Various regexes to fix formatting for Bedrock's specifications */ - private static final Pattern STRIKETHROUGH_UNDERLINE = Pattern.compile("\u00a7[mn]"); - private static final Pattern COLOR_CHARACTERS = Pattern.compile("\u00a7([0-9a-f])"); - private static final Pattern DOUBLE_RESET = Pattern.compile("\u00a7r\u00a7r"); - static { TEAM_COLORS.put(TeamColor.NONE, ""); @@ -111,15 +106,34 @@ public class MessageTranslator { String legacy = LegacyComponentSerializer.legacySection().serialize(message); - // Strip strikethrough and underline as they are not supported on bedrock - legacy = STRIKETHROUGH_UNDERLINE.matcher(legacy).replaceAll(""); + StringBuilder finalLegacy = new StringBuilder(); + char[] legacyChars = legacy.toCharArray(); + boolean lastFormatReset = false; + for (int i = 0; i < legacyChars.length; i++) { + char legacyChar = legacyChars[i]; + if (legacyChar != ChatColor.ESCAPE || i >= legacyChars.length - 1) { + // No special formatting for Bedrock needed + // Or, we're at the end of the string + finalLegacy.append(legacyChar); + lastFormatReset = false; + continue; + } - // Make color codes reset formatting like Java - // See https://minecraft.gamepedia.com/Formatting_codes#Usage - legacy = COLOR_CHARACTERS.matcher(legacy).replaceAll("\u00a7r\u00a7$1"); - legacy = DOUBLE_RESET.matcher(legacy).replaceAll("\u00a7r"); + char next = legacyChars[++i]; + if (next != 'm' && next != 'n') { + // Strikethrough and underline do not exist on Bedrock + if ((next >= '0' && next <= '9') || (next >= 'a' && next <= 'f')) { + // Append this color code, as well as a necessary reset code + if (!lastFormatReset) { + finalLegacy.append(RESET); + } + } + finalLegacy.append(BASE).append(next); + } + lastFormatReset = next == 'r'; + } - return legacy; + return finalLegacy.toString(); } catch (Exception e) { GeyserImpl.getInstance().getLogger().debug(GSON_SERIALIZER.serialize(message)); GeyserImpl.getInstance().getLogger().error("Failed to parse message", e);