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.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Locale;
public class ChatHandler { public class ChatHandler {
public static void register() { public static void register() {
@@ -149,10 +150,11 @@ public class ChatHandler {
while (!remaining.isEmpty()) { while (!remaining.isEmpty()) {
int earliestIndex = remaining.length(); int earliestIndex = remaining.length();
ServerPlayer mentioned = null; ServerPlayer mentioned = null;
String lower = remaining.toLowerCase(Locale.ROOT);
for (ServerPlayer player : sorted) { for (ServerPlayer player : sorted) {
String name = player.getName().getString(); String nameLower = player.getName().getString().toLowerCase(Locale.ROOT);
int index = remaining.toLowerCase().indexOf(name.toLowerCase()); int index = indexOfBoundary(lower, nameLower);
if (index >= 0 && index < earliestIndex) { if (index >= 0 && index < earliestIndex) {
earliestIndex = index; earliestIndex = index;
mentioned = player; mentioned = player;
@@ -164,11 +166,13 @@ public class ChatHandler {
break; break;
} }
if (earliestIndex > 0) { boolean withAt = earliestIndex > 0 && remaining.charAt(earliestIndex - 1) == '@';
result.append(Component.literal(remaining.substring(0, earliestIndex))); 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()); remaining = remaining.substring(earliestIndex + mentioned.getName().getString().length());
} }
@@ -176,13 +180,32 @@ public class ChatHandler {
return result; return result;
} }
private static Component createMentionComponent(ServerPlayer player) { private static int indexOfBoundary(String lowerHaystack, String lowerNeedle) {
String prefix = getLuckPermsPrefix(player); int index = lowerHaystack.indexOf(lowerNeedle);
String formattedPrefix = prefix.replace("&", "\u00a7"); while (index >= 0) {
String name = player.getName().getString(); 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 .withStyle(Style.EMPTY
.withColor(ChatFormatting.AQUA)
.withClickEvent(new ClickEvent.SuggestCommand("/msg " + name + " ")) .withClickEvent(new ClickEvent.SuggestCommand("/msg " + name + " "))
.withHoverEvent(new HoverEvent.ShowText( .withHoverEvent(new HoverEvent.ShowText(
Component.literal("Натисніть щоб написати " + name) 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) { private static String getLuckPermsPrefix(ServerPlayer player) {
try { try {
LuckPerms luckPerms = LuckPermsProvider.get(); LuckPerms luckPerms = LuckPermsProvider.get();
@@ -206,21 +263,10 @@ public class ChatHandler {
} }
private static MutableComponent buildFormattedName(ServerPlayer player) { private static MutableComponent buildFormattedName(ServerPlayer player) {
String prefix = ""; String prefix = formatLegacyPrefix(getLuckPermsPrefix(player));
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) {
}
return Component.empty() return Component.empty()
.append(Component.literal(prefix.replace("&", "§"))) .append(Component.literal(prefix))
.append(player.getDisplayName()); .append(player.getDisplayName());
} }
} }