fix: give chat mentions default highlight color and support @tags

This commit is contained in:
2026-10-04 11:44:27 +02:00
parent dd12fe4c00
commit f0b5d603ad
+69 -23
View File
@@ -17,6 +17,7 @@ import org.examp.john.stealth.StealthStorage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class ChatHandler {
public static void register() {
@@ -149,10 +150,11 @@ public class ChatHandler {
while (!remaining.isEmpty()) {
int earliestIndex = remaining.length();
ServerPlayer mentioned = null;
String lower = remaining.toLowerCase(Locale.ROOT);
for (ServerPlayer player : sorted) {
String name = player.getName().getString();
int index = remaining.toLowerCase().indexOf(name.toLowerCase());
String nameLower = player.getName().getString().toLowerCase(Locale.ROOT);
int index = indexOfBoundary(lower, nameLower);
if (index >= 0 && index < earliestIndex) {
earliestIndex = index;
mentioned = player;
@@ -164,11 +166,13 @@ public class ChatHandler {
break;
}
if (earliestIndex > 0) {
result.append(Component.literal(remaining.substring(0, earliestIndex)));
boolean withAt = earliestIndex > 0 && remaining.charAt(earliestIndex - 1) == '@';
int prefixEnd = withAt ? earliestIndex - 1 : earliestIndex;
if (prefixEnd > 0) {
result.append(Component.literal(remaining.substring(0, prefixEnd)));
}
result.append(createMentionComponent(mentioned));
result.append(createMentionComponent(mentioned, withAt));
remaining = remaining.substring(earliestIndex + mentioned.getName().getString().length());
}
@@ -176,13 +180,32 @@ public class ChatHandler {
return result;
}
private static Component createMentionComponent(ServerPlayer player) {
String prefix = getLuckPermsPrefix(player);
String formattedPrefix = prefix.replace("&", "\u00a7");
String name = player.getName().getString();
private static int indexOfBoundary(String lowerHaystack, String lowerNeedle) {
int index = lowerHaystack.indexOf(lowerNeedle);
while (index >= 0) {
boolean okBefore = index == 0 || !isNameChar(lowerHaystack.charAt(index - 1));
boolean okAfter = index + lowerNeedle.length() == lowerHaystack.length()
|| !isNameChar(lowerHaystack.charAt(index + lowerNeedle.length()));
if (okBefore && okAfter) {
return index;
}
index = lowerHaystack.indexOf(lowerNeedle, index + 1);
}
return -1;
}
return Component.literal(formattedPrefix + name)
private static boolean isNameChar(char c) {
return Character.isLetterOrDigit(c) || c == '_';
}
private static Component createMentionComponent(ServerPlayer player, boolean withAt) {
String name = player.getName().getString();
String prefix = formatLegacyPrefix(getLuckPermsPrefix(player));
String text = (withAt ? "@" : "") + prefix + name;
return Component.literal(text)
.withStyle(Style.EMPTY
.withColor(ChatFormatting.AQUA)
.withClickEvent(new ClickEvent.SuggestCommand("/msg " + name + " "))
.withHoverEvent(new HoverEvent.ShowText(
Component.literal("Натисніть щоб написати " + name)
@@ -190,6 +213,40 @@ public class ChatHandler {
);
}
private static String formatLegacyPrefix(String raw) {
if (raw == null || raw.isEmpty()) {
return "";
}
String s = raw.replace('&', '§');
StringBuilder out = new StringBuilder(s.length() + 14);
int i = 0;
while (i < s.length()) {
if (s.charAt(i) == '§' && i + 8 <= s.length() && s.charAt(i + 1) == '#'
&& isSixHex(s, i + 2)) {
out.append("§x");
for (int j = 2; j < 8; j++) {
out.append('§').append(s.charAt(i + j));
}
i += 8;
} else {
out.append(s.charAt(i));
i++;
}
}
return out.toString();
}
private static boolean isSixHex(String s, int start) {
for (int i = start; i < start + 6; i++) {
char c = s.charAt(i);
boolean hex = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
if (!hex) {
return false;
}
}
return true;
}
private static String getLuckPermsPrefix(ServerPlayer player) {
try {
LuckPerms luckPerms = LuckPermsProvider.get();
@@ -206,21 +263,10 @@ public class ChatHandler {
}
private static MutableComponent buildFormattedName(ServerPlayer player) {
String prefix = "";
try {
LuckPerms luckPerms = LuckPermsProvider.get();
User user = luckPerms.getUserManager().getUser(player.getUUID());
if (user != null) {
String metaPrefix = user.getCachedData().getMetaData().getPrefix();
if (metaPrefix != null) {
prefix = metaPrefix;
}
}
} catch (Throwable ignored) {
}
String prefix = formatLegacyPrefix(getLuckPermsPrefix(player));
return Component.empty()
.append(Component.literal(prefix.replace("&", "§")))
.append(Component.literal(prefix))
.append(player.getDisplayName());
}
}