diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index 8323516eeb..3911248ac2 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -18,6 +18,8 @@ import meteordevelopment.meteorclient.mixininterface.IChatHudLine; import meteordevelopment.meteorclient.mixininterface.IChatHudLineVisible; import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.friends.Friends; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.utils.Utils; @@ -33,6 +35,7 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.text.TextColor; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; @@ -40,6 +43,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -103,6 +107,21 @@ public class BetterChat extends Module { .build() ); + private final Setting friendHighlight = sgGeneral.add(new BoolSetting.Builder() + .name("friend-highlight") + .description("Highlights the names of your friends in chat.") + .defaultValue(true) + .build() + ); + + private final Setting friendHighlightColor = sgGeneral.add(new ColorSetting.Builder() + .name("friend-highlight-color") + .description("The color used to highlight friend names in chat.") + .defaultValue(new SettingColor(0, 255, 180)) + .visible(friendHighlight::get) + .build() + ); + // Filter private final Setting antiSpam = sgFilter.add(new BoolSetting.Builder() @@ -296,6 +315,11 @@ private void onMessageReceive(ReceiveMessageEvent event) { message = Text.empty().append(timestamp).append(message); } + if (friendHighlight.get()) { + Text highlighted = applyFriendHighlight(message); + if (highlighted != null) message = highlighted; + } + event.setMessage(message); } @@ -324,6 +348,42 @@ private void onMessageSend(SendMessageEvent event) { event.message = message; } + // Friend Highlight + + private Text applyFriendHighlight(Text message) { + String messageString = message.getString(); + Matcher matcher = usernameRegex.matcher(messageString); + if (!matcher.matches()) return null; + + String username = matcher.group(1); + if (Friends.get().get(username) == null) return null; + + TextColor friendColor = friendHighlightColor.get().toTextColor(); + + // Try to preserve rich text (hover events, colors, etc.) via TextVisitor. + // On cracked servers, player_chat packets use TranslatableText which can cause + // a NoSuchElementException due to a mismatch between collectSiblings and visit(). + // In that case, skip the highlight and leave the message untouched. + try { + MutableText result = Text.empty(); + TextVisitor.visit(message, (text, style, string) -> { + int idx = string.indexOf(username); + if (idx >= 0) { + if (idx > 0) result.append(Text.literal(string.substring(0, idx)).setStyle(style)); + result.append(Text.literal(username).setStyle(style.withColor(friendColor))); + int after = idx + username.length(); + if (after < string.length()) result.append(Text.literal(string.substring(after)).setStyle(style)); + } else { + result.append(text.copyContentOnly().setStyle(style)); + } + return Optional.empty(); + }, Style.EMPTY); + return result; + } catch (NoSuchElementException e) { + return null; + } + } + // Anti Spam private Text appendAntiSpam(Text text) {