Fix Folia chat colors - use Component API properly - ChatListener: use MessageConfig.getComponent() for error messages - ChatManager: build format string then parse with MiniMessage.deserialize() - ChatFormatter.convertAllColors: made idempotent (skip if already has <color:#>) - Removed old formatGlobalMessage/formatLocalMessage methods - All chat messages now properly rendered with colors
This commit is contained in:
parent
8824ccd60f
commit
8c6fb2c92e
4 changed files with 88 additions and 67 deletions
|
|
@ -5,6 +5,9 @@ import com.loki.lochat.managers.AntiSpamManager;
|
|||
import com.loki.lochat.managers.FilterManager;
|
||||
import com.loki.lochat.utils.ChatFormatter;
|
||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextReplacementConfig;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
|
|
@ -14,6 +17,7 @@ import org.bukkit.event.player.PlayerQuitEvent;
|
|||
public class ChatListener implements Listener {
|
||||
|
||||
private final LoChat plugin;
|
||||
private static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.plainText();
|
||||
|
||||
public ChatListener(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -24,12 +28,14 @@ public class ChatListener implements Listener {
|
|||
event.setCancelled(true);
|
||||
|
||||
Player player = event.getPlayer();
|
||||
String message = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer
|
||||
.plainText().serialize(event.message());
|
||||
Component message = event.message();
|
||||
|
||||
// Plain текст только для проверок
|
||||
String plainMessage = PLAIN.serialize(message);
|
||||
|
||||
// Обработка через RegionScheduler для Folia
|
||||
player.getScheduler().run(plugin, task -> {
|
||||
processChat(player, message);
|
||||
processChat(player, plainMessage);
|
||||
}, null);
|
||||
}
|
||||
|
||||
|
|
@ -38,11 +44,9 @@ public class ChatListener implements Listener {
|
|||
if (plugin.getMuteManager().isMuted(player.getUniqueId())) {
|
||||
String timeLeft = plugin.getMuteManager().formatRemainingTime(player.getUniqueId());
|
||||
if (timeLeft.equals("навсегда")) {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("mute.permanent")));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("mute.permanent"));
|
||||
} else {
|
||||
player.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("mute.you-muted", "{time}", timeLeft)
|
||||
));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("mute.you-muted", "{time}", timeLeft));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -59,9 +63,7 @@ public class ChatListener implements Listener {
|
|||
if (cooldown > 0 && !player.hasPermission("chat.bypass.cooldown")) {
|
||||
if (plugin.getCooldownManager().isOnCooldown(player.getUniqueId(), chatType, cooldown)) {
|
||||
int remaining = plugin.getCooldownManager().getRemainingCooldown(player.getUniqueId(), chatType, cooldown);
|
||||
player.sendMessage(ChatFormatter.parse(
|
||||
plugin.getMessageConfig().get("cooldown.wait", "{time}", String.valueOf(remaining))
|
||||
));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("cooldown.wait", "{time}", String.valueOf(remaining)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -71,15 +73,15 @@ public class ChatListener implements Listener {
|
|||
AntiSpamManager.SpamResult spamResult = plugin.getAntiSpamManager().checkMessage(player.getUniqueId(), processedMessage);
|
||||
switch (spamResult) {
|
||||
case TOO_MANY_CAPS -> {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("antispam.caps")));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("antispam.caps"));
|
||||
return;
|
||||
}
|
||||
case REPEAT_CHARS -> {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("antispam.repeat")));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("antispam.repeat"));
|
||||
return;
|
||||
}
|
||||
case SIMILAR_MESSAGE -> {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("antispam.similar")));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("antispam.similar"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,12 +92,11 @@ public class ChatListener implements Listener {
|
|||
FilterManager.FilterResult filterResult = plugin.getFilterManager().checkMessage(processedMessage);
|
||||
switch (filterResult) {
|
||||
case BLOCKED -> {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("filter.blocked")));
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("filter.blocked"));
|
||||
return;
|
||||
}
|
||||
case WARNED -> {
|
||||
player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("filter.warned")));
|
||||
// Продолжаем, но цензурим
|
||||
player.sendMessage(plugin.getMessageConfig().getComponent("filter.warned"));
|
||||
processedMessage = plugin.getFilterManager().censorMessage(processedMessage);
|
||||
}
|
||||
case CENSORED -> processedMessage = plugin.getFilterManager().censorMessage(processedMessage);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.loki.lochat.LoChat;
|
|||
import com.loki.lochat.utils.ChatFormatter;
|
||||
import com.loki.lochat.utils.DistanceUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
|
|
@ -16,6 +17,7 @@ public class ChatManager {
|
|||
|
||||
private final LoChat plugin;
|
||||
private final Set<UUID> globalChatDisabled = ConcurrentHashMap.newKeySet();
|
||||
private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
|
||||
|
||||
public ChatManager(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -23,7 +25,7 @@ public class ChatManager {
|
|||
|
||||
public void sendGlobalMessage(Player sender, String message) {
|
||||
if (!plugin.getConfigManager().isGlobalEnabled()) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("global.disabled")));
|
||||
sender.sendMessage(plugin.getMessageConfig().getComponent("global.disabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -35,15 +37,28 @@ public class ChatManager {
|
|||
String prefix = plugin.getConfigManager().getGlobalPrefix();
|
||||
boolean hasColor = sender.hasPermission("chat.global.color");
|
||||
|
||||
// Получаем отображаемое имя игрока (с градиентом если есть)
|
||||
String playerDisplay = getPlayerDisplay(sender);
|
||||
|
||||
// Обрабатываем сообщение игрока (смайлики, цвета если есть право)
|
||||
String finalMessage = ChatFormatter.processPlayerMessage(processedMessage, sender, hasColor);
|
||||
|
||||
// Отправка каждому игроку персонализированное сообщение
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (isGlobalChatDisabled(player.getUniqueId())) continue;
|
||||
|
||||
// Персонализируем сообщение для этого игрока (выделяем его ник)
|
||||
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(processedMessage, player);
|
||||
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(finalMessage, player);
|
||||
|
||||
Component formatted = ChatFormatter.formatGlobalMessage(format, prefix, sender, personalizedMsg, hasColor);
|
||||
player.sendMessage(formatted);
|
||||
// Формируем итоговую строку
|
||||
String formatted = format
|
||||
.replace("<prefix>", prefix)
|
||||
.replace("<player>", playerDisplay)
|
||||
.replace("<message>", personalizedMsg);
|
||||
|
||||
// Парсим в Component и отправляем
|
||||
Component component = MINI_MESSAGE.deserialize(formatted);
|
||||
player.sendMessage(component);
|
||||
|
||||
// Проверяем упоминание ника без @ и уведомляем
|
||||
plugin.getMentionManager().notifyIfMentioned(message, player, sender);
|
||||
|
|
@ -69,16 +84,29 @@ public class ChatManager {
|
|||
String prefix = plugin.getConfigManager().getLocalPrefix();
|
||||
boolean hasColor = sender.hasPermission("chat.local.color");
|
||||
|
||||
// Получаем отображаемое имя игрока (с градиентом если есть)
|
||||
String playerDisplay = getPlayerDisplay(sender);
|
||||
|
||||
// Обрабатываем сообщение игрока (смайлики, цвета если есть право)
|
||||
String finalMessage = ChatFormatter.processPlayerMessage(processedMessage, sender, hasColor);
|
||||
|
||||
boolean foundRecipient = false;
|
||||
Set<Player> recipients = new HashSet<>();
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (DistanceUtil.isInRange(sender, player, radius)) {
|
||||
// Персонализируем сообщение для этого игрока
|
||||
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(processedMessage, player);
|
||||
String personalizedMsg = plugin.getMentionManager().getPersonalizedMessage(finalMessage, player);
|
||||
|
||||
// Формируем итоговую строку
|
||||
String formatted = prefix + " " + format
|
||||
.replace("<player>", playerDisplay)
|
||||
.replace("<message>", personalizedMsg);
|
||||
|
||||
// Парсим в Component и отправляем
|
||||
Component component = MINI_MESSAGE.deserialize(formatted);
|
||||
player.sendMessage(component);
|
||||
|
||||
Component formatted = ChatFormatter.formatLocalMessage(format, prefix, sender, personalizedMsg, hasColor);
|
||||
player.sendMessage(formatted);
|
||||
recipients.add(player);
|
||||
|
||||
// Проверяем упоминание ника без @
|
||||
|
|
@ -95,10 +123,23 @@ public class ChatManager {
|
|||
plugin.getMentionManager().notifyMentioned(mentionedPlayers);
|
||||
|
||||
if (!foundRecipient) {
|
||||
sender.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().get("local.no-players")));
|
||||
sender.sendMessage(plugin.getMessageConfig().getComponent("local.no-players"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает отображаемое имя игрока с градиентом (если включено)
|
||||
* Возвращает строку в MiniMessage формате
|
||||
*/
|
||||
private String getPlayerDisplay(Player player) {
|
||||
if (plugin.getGradientModule() != null && plugin.getGradientModule().isEnabled()) {
|
||||
String name = plugin.getGradientModule().getFormattedName(player);
|
||||
// Конвертируем &#RRGGBB формат в MiniMessage
|
||||
return ChatFormatter.convertAllColors(name);
|
||||
}
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
public boolean toggleGlobalChat(UUID player) {
|
||||
if (globalChatDisabled.contains(player)) {
|
||||
globalChatDisabled.remove(player);
|
||||
|
|
|
|||
|
|
@ -26,23 +26,29 @@ public class ChatFormatter {
|
|||
|
||||
/**
|
||||
* Конвертирует все форматы цветов в MiniMessage
|
||||
* Поддерживает: &коды, §коды, &#HEX, §x§...HEX, MiniMessage теги
|
||||
* Поддерживает: &коды, §коды, &#HEX, §x§...HEX
|
||||
* Идемпотентный - не конвертирует уже конвертированные теги
|
||||
*/
|
||||
public static String convertAllColors(String message) {
|
||||
if (message == null) return "";
|
||||
|
||||
// Если уже содержит MiniMessage теги <color:...> - не конвертируем повторно
|
||||
if (message.contains("<color:#")) {
|
||||
return message;
|
||||
}
|
||||
|
||||
String result = message;
|
||||
|
||||
// 1. Конвертируем §x§R§R§G§G§B§B -> <#RRGGBB>
|
||||
// 1. Конвертируем §x§R§R§G§G§B§B -> <color:#rrggbb>
|
||||
result = convertSectionHexColors(result);
|
||||
|
||||
// 2. Конвертируем §коды -> &коды (для унификации)
|
||||
result = convertSectionToAmpersand(result);
|
||||
|
||||
// 3. Нормализуем существующие MiniMessage HEX теги в lowercase
|
||||
// 3. Нормализуем существующие MiniMessage HEX теги <#RRGGBB> -> <color:#rrggbb>
|
||||
result = normalizeMiniMessageHex(result);
|
||||
|
||||
// 4. Конвертируем &#RRGGBB -> <#RRGGBB> (только если еще не в MiniMessage формате)
|
||||
// 4. Конвертируем &#RRGGBB -> <color:#rrggbb>
|
||||
result = convertHexColors(result);
|
||||
|
||||
// 5. Конвертируем &коды -> MiniMessage теги
|
||||
|
|
@ -232,10 +238,22 @@ public class ChatFormatter {
|
|||
}
|
||||
|
||||
public static Component parse(String message) {
|
||||
return MINI_MESSAGE.deserialize(message);
|
||||
}
|
||||
|
||||
public static Component parseWithColors(String message) {
|
||||
return MINI_MESSAGE.deserialize(convertAllColors(message));
|
||||
}
|
||||
|
||||
public static Component parse(String message, String... replacements) {
|
||||
String result = message;
|
||||
for (int i = 0; i < replacements.length - 1; i += 2) {
|
||||
result = result.replace(replacements[i], replacements[i + 1]);
|
||||
}
|
||||
return MINI_MESSAGE.deserialize(result);
|
||||
}
|
||||
|
||||
public static Component parseWithColors(String message, String... replacements) {
|
||||
String result = message;
|
||||
for (int i = 0; i < replacements.length - 1; i += 2) {
|
||||
result = result.replace(replacements[i], replacements[i + 1]);
|
||||
|
|
@ -282,45 +300,6 @@ public class ChatFormatter {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирует глобальное сообщение с поддержкой LoPreff
|
||||
*/
|
||||
public static Component formatGlobalMessage(String format, String prefix, Player player, String message, boolean hasColorPermission) {
|
||||
String playerDisplay = getPlayerDisplay(player);
|
||||
String finalMessage = processPlayerMessage(message, player, hasColorPermission);
|
||||
|
||||
String formatted = format
|
||||
.replace("<prefix>", prefix)
|
||||
.replace("<player>", playerDisplay)
|
||||
.replace("<message>", finalMessage);
|
||||
|
||||
return parse(formatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирует локальное сообщение с поддержкой LoPreff
|
||||
*/
|
||||
public static Component formatLocalMessage(String format, String prefix, Player player, String message, boolean hasColorPermission) {
|
||||
String playerDisplay = getPlayerDisplay(player);
|
||||
String finalMessage = processPlayerMessage(message, player, hasColorPermission);
|
||||
|
||||
String formatted = prefix + " " + format
|
||||
.replace("<player>", playerDisplay)
|
||||
.replace("<message>", finalMessage);
|
||||
|
||||
return parse(formatted);
|
||||
}
|
||||
|
||||
private static String getPlayerDisplay(Player player) {
|
||||
LoChat plugin = LoChat.getInstance();
|
||||
if (plugin != null && plugin.getGradientModule() != null && plugin.getGradientModule().isEnabled()) {
|
||||
String name = plugin.getGradientModule().getFormattedName(player);
|
||||
// Конвертируем §x§... формат в MiniMessage
|
||||
return convertAllColors(name);
|
||||
}
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
public static Component formatPmSent(String format, String targetName, String message) {
|
||||
return parse(format
|
||||
.replace("{player}", targetName)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue