diff --git a/bin/main/com/loki/lochat/commands/ClearChatCommand.class b/bin/main/com/loki/lochat/commands/ClearChatCommand.class index 96253d1..87ca74e 100644 Binary files a/bin/main/com/loki/lochat/commands/ClearChatCommand.class and b/bin/main/com/loki/lochat/commands/ClearChatCommand.class differ diff --git a/bin/main/com/loki/lochat/commands/MuteCommand.class b/bin/main/com/loki/lochat/commands/MuteCommand.class index 4dcb40a..9673f0a 100644 Binary files a/bin/main/com/loki/lochat/commands/MuteCommand.class and b/bin/main/com/loki/lochat/commands/MuteCommand.class differ diff --git a/bin/main/com/loki/lochat/commands/MuteHistoryCommand.class b/bin/main/com/loki/lochat/commands/MuteHistoryCommand.class index 1b2338c..64f2758 100644 Binary files a/bin/main/com/loki/lochat/commands/MuteHistoryCommand.class and b/bin/main/com/loki/lochat/commands/MuteHistoryCommand.class differ diff --git a/bin/main/com/loki/lochat/commands/UnmuteCommand.class b/bin/main/com/loki/lochat/commands/UnmuteCommand.class index f4f970f..c69e194 100644 Binary files a/bin/main/com/loki/lochat/commands/UnmuteCommand.class and b/bin/main/com/loki/lochat/commands/UnmuteCommand.class differ diff --git a/bin/main/com/loki/lochat/config/ConfigManager.class b/bin/main/com/loki/lochat/config/ConfigManager.class index 231d758..d296b8d 100644 Binary files a/bin/main/com/loki/lochat/config/ConfigManager.class and b/bin/main/com/loki/lochat/config/ConfigManager.class differ diff --git a/bin/main/com/loki/lochat/listeners/ChatListener.class b/bin/main/com/loki/lochat/listeners/ChatListener.class index aa708f5..04b27a7 100644 Binary files a/bin/main/com/loki/lochat/listeners/ChatListener.class and b/bin/main/com/loki/lochat/listeners/ChatListener.class differ diff --git a/bin/main/com/loki/lochat/managers/SpyManager.class b/bin/main/com/loki/lochat/managers/SpyManager.class index d18ae7c..a9cb48f 100644 Binary files a/bin/main/com/loki/lochat/managers/SpyManager.class and b/bin/main/com/loki/lochat/managers/SpyManager.class differ diff --git a/bin/main/com/loki/lochat/utils/Constants.class b/bin/main/com/loki/lochat/utils/Constants.class new file mode 100644 index 0000000..2dbe8d4 Binary files /dev/null and b/bin/main/com/loki/lochat/utils/Constants.class differ diff --git a/bin/main/com/loki/lochat/utils/PlayerUtil.class b/bin/main/com/loki/lochat/utils/PlayerUtil.class new file mode 100644 index 0000000..63fe193 Binary files /dev/null and b/bin/main/com/loki/lochat/utils/PlayerUtil.class differ diff --git a/bin/main/messages.yml b/bin/main/messages.yml index f148fab..6d09ec2 100644 --- a/bin/main/messages.yml +++ b/bin/main/messages.yml @@ -39,10 +39,11 @@ spy: enabled: "CADFШпион режим включен" disabled: "CADFШпион режим выключен" format: "󅒐[SPY] {sender} → {receiver}: {message}" + chat-format: "󅒐[SPY] {type} {sender}: {message}" filter: blocked: "CADFСообщение заблокировано (мат)" - warned: "CADFПредупреждение: не используйте мат!" + warning: "CADFПредупреждение: не используйте мат!" cooldown: wait: "CADFПодождите {time} сек перед следующим сообщением" diff --git a/src/main/java/com/loki/lochat/commands/ClearChatCommand.java b/src/main/java/com/loki/lochat/commands/ClearChatCommand.java index 3460c46..ff1abd1 100644 --- a/src/main/java/com/loki/lochat/commands/ClearChatCommand.java +++ b/src/main/java/com/loki/lochat/commands/ClearChatCommand.java @@ -19,9 +19,9 @@ public class ClearChatCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - // Отправляем 100 пустых строк всем игрокам + // Отправляем пустые строки всем игрокам для очистки чата for (Player player : Bukkit.getOnlinePlayers()) { - for (int i = 0; i < 100; i++) { + for (int i = 0; i < com.loki.lochat.utils.Constants.CLEAR_CHAT_LINES; i++) { player.sendMessage(""); } diff --git a/src/main/java/com/loki/lochat/commands/MuteCommand.java b/src/main/java/com/loki/lochat/commands/MuteCommand.java index 37565a4..00e31c0 100644 --- a/src/main/java/com/loki/lochat/commands/MuteCommand.java +++ b/src/main/java/com/loki/lochat/commands/MuteCommand.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * Команда /mute nick [time] [-s] [причина] @@ -106,24 +107,15 @@ public class MuteCommand implements CommandExecutor, TabCompleter { } // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - String finalTargetName = targetName; - java.util.UUID targetUUID; - - if (target == null) { - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) { - sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); - return true; - } - targetUUID = offlinePlayer.getUniqueId(); - finalTargetName = offlinePlayer.getName() != null ? offlinePlayer.getName() : targetName; - } else { - targetUUID = target.getUniqueId(); - finalTargetName = target.getName(); + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); + return true; } + Player target = Bukkit.getPlayer(targetUUID); + String finalTargetName = com.loki.lochat.utils.PlayerUtil.getPlayerName(targetUUID); + // Проверяем, не замучен ли уже if (plugin.getMuteManager().isMuted(targetUUID)) { sender.sendMessage("§cИгрок уже замучен!"); diff --git a/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java b/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java index 78d2ceb..f61c58b 100644 --- a/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java +++ b/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java @@ -43,22 +43,12 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter { } String targetName = args[0]; - UUID targetUUID = null; // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - if (target != null) { - targetUUID = target.getUniqueId(); - } else { - // Пробуем найти оффлайн игрока - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (offlinePlayer.hasPlayedBefore() || offlinePlayer.isOnline()) { - targetUUID = offlinePlayer.getUniqueId(); - } else { - // Пробуем найти по имени в истории - targetUUID = plugin.getMuteManager().getUUIDByName(targetName); - } + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + // Пробуем найти по имени в истории + targetUUID = plugin.getMuteManager().getUUIDByName(targetName); } if (targetUUID == null) { diff --git a/src/main/java/com/loki/lochat/commands/UnmuteCommand.java b/src/main/java/com/loki/lochat/commands/UnmuteCommand.java index 16ed65e..fb325c1 100644 --- a/src/main/java/com/loki/lochat/commands/UnmuteCommand.java +++ b/src/main/java/com/loki/lochat/commands/UnmuteCommand.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * Команда /unmute nick [-s] @@ -57,24 +58,15 @@ public class UnmuteCommand implements CommandExecutor, TabCompleter { } // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - String finalTargetName = targetName; - java.util.UUID targetUUID; - - if (target == null) { - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) { - sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); - return true; - } - targetUUID = offlinePlayer.getUniqueId(); - finalTargetName = offlinePlayer.getName() != null ? offlinePlayer.getName() : targetName; - } else { - targetUUID = target.getUniqueId(); - finalTargetName = target.getName(); + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); + return true; } + Player target = Bukkit.getPlayer(targetUUID); + String finalTargetName = com.loki.lochat.utils.PlayerUtil.getPlayerName(targetUUID); + String operatorName = sender.getName(); // Размучиваем diff --git a/src/main/java/com/loki/lochat/config/ConfigManager.java b/src/main/java/com/loki/lochat/config/ConfigManager.java index 1da76bd..2813de7 100644 --- a/src/main/java/com/loki/lochat/config/ConfigManager.java +++ b/src/main/java/com/loki/lochat/config/ConfigManager.java @@ -154,7 +154,7 @@ public class ConfigManager { } public int getLocalRadius() { - return config.getInt("chat.local.radius", 100); + return config.getInt("chat.local.radius", com.loki.lochat.utils.Constants.DEFAULT_LOCAL_RADIUS); } public String getLocalPrefix() { diff --git a/src/main/java/com/loki/lochat/listeners/ChatListener.java b/src/main/java/com/loki/lochat/listeners/ChatListener.java index d100bec..f1830ae 100644 --- a/src/main/java/com/loki/lochat/listeners/ChatListener.java +++ b/src/main/java/com/loki/lochat/listeners/ChatListener.java @@ -81,60 +81,23 @@ public class ChatListener implements Listener { String processedPlain = PLAIN.serialize(processedMessage).trim(); if (processedPlain.isEmpty()) return; + // ===== FILTER ===== + processedMessage = applyMessageFilter(player, processedMessage, processedPlain); + if (processedMessage == null) return; // Сообщение заблокировано + + processedPlain = PLAIN.serialize(processedMessage); + // ===== COOLDOWN ===== - int cooldown = isGlobal - ? plugin.getConfigManager().getGlobalCooldown() - : plugin.getConfigManager().getLocalCooldown(); - - 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( - plugin.getMessageConfig() - .getComponent("cooldown.wait", "{time}", String.valueOf(remaining)) - ); - return; - } - } + if (!checkCooldown(player, chatType)) return; // ===== ANTI SPAM ===== - if (!player.hasPermission("chat.bypass.antispam")) { - AntiSpamManager.SpamResult result = - plugin.getAntiSpamManager() - .checkMessage(player.getUniqueId(), processedPlain); - - switch (result) { - case TOO_MANY_CAPS -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.caps") - ); - return; - } - case REPEAT_CHARS -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.repeat") - ); - return; - } - case SIMILAR_MESSAGE -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.similar") - ); - return; - } - case ALLOWED -> { - // Сообщение прошло проверку, продолжаем - } - } - } - + if (!checkAntiSpam(player, processedPlain)) return; plugin.getCooldownManager().setCooldown(player.getUniqueId(), chatType); + // ===== SPY ===== + plugin.getSpyManager().sendToSpies(player, processedMessage, isGlobal); + // ===== SEND ===== if (isGlobal) { plugin.getChatManager().sendGlobalMessage(player, processedMessage); @@ -143,6 +106,98 @@ public class ChatListener implements Listener { } } + private Component applyMessageFilter(Player player, Component message, String plainMessage) { + if (!plugin.getConfigManager().isFilterEnabled() || player.hasPermission("chat.bypass.filter")) { + return message; + } + + String filteredMessage = applyFilter(plainMessage); + if (!filteredMessage.equals(plainMessage)) { + String action = plugin.getConfigManager().getFilterAction(); + switch (action.toLowerCase()) { + case "block" -> { + player.sendMessage(plugin.getMessageConfig().getComponent("filter.blocked")); + return null; + } + case "warn" -> { + player.sendMessage(plugin.getMessageConfig().getComponent("filter.warning")); + return null; + } + case "censor" -> { + return Component.text(filteredMessage); + } + } + } + return message; + } + + private boolean checkCooldown(Player player, String chatType) { + int cooldown = chatType.equals("global") + ? plugin.getConfigManager().getGlobalCooldown() + : plugin.getConfigManager().getLocalCooldown(); + + 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( + plugin.getMessageConfig() + .getComponent("cooldown.wait", "{time}", String.valueOf(remaining)) + ); + return false; + } + } + return true; + } + + private boolean checkAntiSpam(Player player, String message) { + if (player.hasPermission("chat.bypass.antispam")) { + return true; + } + + AntiSpamManager.SpamResult result = plugin.getAntiSpamManager() + .checkMessage(player.getUniqueId(), message); + + switch (result) { + case TOO_MANY_CAPS -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.caps")); + return false; + } + case REPEAT_CHARS -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.repeat")); + return false; + } + case SIMILAR_MESSAGE -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.similar")); + return false; + } + case ALLOWED -> { + return true; + } + } + return true; + } + + private String applyFilter(String message) { + if (!plugin.getConfigManager().isFilterEnabled()) { + return message; + } + + String filtered = message; + String replacement = plugin.getConfigManager().getFilterReplacement(); + + for (String word : plugin.getConfigManager().getFilterWords()) { + if (word == null || word.trim().isEmpty()) continue; + + // Заменяем слово с учетом регистра и границ слов + String pattern = "(?i)\\b" + java.util.regex.Pattern.quote(word.trim()) + "\\b"; + filtered = filtered.replaceAll(pattern, replacement); + } + + return filtered; + } + @EventHandler public void onQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); diff --git a/src/main/java/com/loki/lochat/managers/SpyManager.java b/src/main/java/com/loki/lochat/managers/SpyManager.java index 648c292..5607a57 100644 --- a/src/main/java/com/loki/lochat/managers/SpyManager.java +++ b/src/main/java/com/loki/lochat/managers/SpyManager.java @@ -46,6 +46,25 @@ public class SpyManager { } } + public void sendToSpies(Player sender, net.kyori.adventure.text.Component message, boolean isGlobal) { + if (spyEnabled.isEmpty()) return; + + String chatType = isGlobal ? "Global" : "Local"; + String plainMessage = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(message); + String format = plugin.getMessageConfig().get("spy.chat-format", + "§7[SPY] §e{type} §7{sender}: §f{message}"); + + for (UUID spyUuid : spyEnabled) { + Player spy = Bukkit.getPlayer(spyUuid); + if (spy != null && spy.isOnline() && !spy.equals(sender)) { + spy.sendMessage(ChatFormatter.parse(format + .replace("{type}", chatType) + .replace("{sender}", sender.getName()) + .replace("{message}", plainMessage))); + } + } + } + public void removeSpy(UUID player) { spyEnabled.remove(player); } diff --git a/src/main/java/com/loki/lochat/utils/Constants.java b/src/main/java/com/loki/lochat/utils/Constants.java new file mode 100644 index 0000000..dfe05e6 --- /dev/null +++ b/src/main/java/com/loki/lochat/utils/Constants.java @@ -0,0 +1,31 @@ +package com.loki.lochat.utils; + +/** + * Константы плагина + */ +public final class Constants { + + private Constants() {} + + // Чат + public static final int DEFAULT_LOCAL_RADIUS = 100; + public static final int CLEAR_CHAT_LINES = 100; + + // Время + public static final long MILLIS_IN_SECOND = 1000L; + public static final int SECONDS_IN_MINUTE = 60; + public static final int MINUTES_IN_HOUR = 60; + public static final int HOURS_IN_DAY = 24; + + // Градиенты + public static final int DEFAULT_PRICE_PER_COLOR = 50; + public static final int DEFAULT_PREFIX_PRICE = 500; + public static final int LUCKPERMS_PREFIX_PRIORITY = 100; + + // Folia/Paper совместимость + public static final int TICKS_PER_SECOND = 20; + public static final int MILLIS_PER_TICK = 50; + + // Анти-спам + public static final int PERCENTAGE_MULTIPLIER = 100; +} \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/utils/PlayerUtil.java b/src/main/java/com/loki/lochat/utils/PlayerUtil.java new file mode 100644 index 0000000..655d1f0 --- /dev/null +++ b/src/main/java/com/loki/lochat/utils/PlayerUtil.java @@ -0,0 +1,70 @@ +package com.loki.lochat.utils; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.UUID; + +/** + * Утилиты для работы с игроками + */ +public final class PlayerUtil { + + private PlayerUtil() {} + + /** + * Находит игрока по имени (онлайн или оффлайн) + * @param name имя игрока + * @return UUID игрока или null если не найден + */ + public static UUID findPlayerUUID(String name) { + // Сначала ищем онлайн игрока + Player onlinePlayer = Bukkit.getPlayer(name); + if (onlinePlayer != null) { + return onlinePlayer.getUniqueId(); + } + + // Затем ищем оффлайн игрока + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name); + if (offlinePlayer.hasPlayedBefore() || offlinePlayer.isOnline()) { + return offlinePlayer.getUniqueId(); + } + + return null; + } + + /** + * Проверяет, существует ли игрок (играл на сервере) + * @param name имя игрока + * @return true если игрок существует + */ + public static boolean playerExists(String name) { + return findPlayerUUID(name) != null; + } + + /** + * Получает имя игрока по UUID + * @param uuid UUID игрока + * @return имя игрока или null + */ + public static String getPlayerName(UUID uuid) { + Player onlinePlayer = Bukkit.getPlayer(uuid); + if (onlinePlayer != null) { + return onlinePlayer.getName(); + } + + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + return offlinePlayer.getName(); + } + + /** + * Проверяет, онлайн ли игрок + * @param uuid UUID игрока + * @return true если игрок онлайн + */ + public static boolean isPlayerOnline(UUID uuid) { + Player player = Bukkit.getPlayer(uuid); + return player != null && player.isOnline(); + } +} \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index f148fab..6d09ec2 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -39,10 +39,11 @@ spy: enabled: "CADFШпион режим включен" disabled: "CADFШпион режим выключен" format: "󅒐[SPY] {sender} → {receiver}: {message}" + chat-format: "󅒐[SPY] {type} {sender}: {message}" filter: blocked: "CADFСообщение заблокировано (мат)" - warned: "CADFПредупреждение: не используйте мат!" + warning: "CADFПредупреждение: не используйте мат!" cooldown: wait: "CADFПодождите {time} сек перед следующим сообщением"