refactor: restructure services and filters architecture
- Remove deprecated service interfaces (CooldownService, IgnoreService, PMService, PlayerDataService, SpyService) - Add new unified service interfaces (MessagingService, PlayerService, PunishmentService) - Extract FilterResult as standalone class from AdvancedMessageFilter - Implement individual filter classes (CharacterFilter, FloodFilter, SpamFilter, SwearFilter, UrlFilter) - Add moderation commands (BanCommand, WarnCommand, SilentWarnCommand, UnbanCommand) - Introduce data models for punishment tracking (BanRecord, WarnEntry) - Refactor messaging service with new MessagingServiceImpl implementation - Add mute service utilities (MuteDataStorage, MutePermissionChecker) - Implement PunishmentServiceImpl with snapshot tracking - Add Discord integration components (DiscordConfig, DiscordMessageService) - Introduce command handlers for gradient module (ColorCommandHandler, PrefixCommandHandler) - Add renderer components (EmojiComponent, GradientBuilder, UrlProcessor) - Add utility classes (ColorConverter, MessageSender, PlaceholderProcessor) - Update configuration files and plugin metadata - Add documentation files (CODE_REVIEW_RU.md, REFACTORING_SERVICES.md) - Consolidate service architecture for improved maintainability and separation of concerns
This commit is contained in:
parent
2d79d2a91d
commit
bba480002f
181 changed files with 3455 additions and 2908 deletions
|
|
@ -1,87 +1,36 @@
|
|||
package com.loki.lochat.integrations;
|
||||
|
||||
import com.loki.lochat.util.FoliaUtil;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import com.loki.lochat.integrations.discord.DiscordConfig;
|
||||
import com.loki.lochat.integrations.discord.DiscordMessageService;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Интеграция с Discord через вебхуки
|
||||
* Интеграция с Discord - упрощенная версия
|
||||
*/
|
||||
public class DiscordIntegration {
|
||||
private final JavaPlugin plugin;
|
||||
private YamlConfiguration config;
|
||||
private DiscordWebhook webhook;
|
||||
private DiscordConfig config;
|
||||
private DiscordMessageService messageService;
|
||||
private boolean enabled = false;
|
||||
|
||||
// Паттерны для очистки сообщений
|
||||
private static final Pattern MENTION_PATTERN = Pattern.compile("@(everyone|here)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("§[0-9a-fk-or]", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public DiscordIntegration(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
loadConfig();
|
||||
initWebhook();
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Загрузить конфигурацию
|
||||
*/
|
||||
private void loadConfig() {
|
||||
// Создаём папку config если её нет
|
||||
File configFolder = new File(plugin.getDataFolder(), "config");
|
||||
if (!configFolder.exists()) {
|
||||
configFolder.mkdirs();
|
||||
}
|
||||
|
||||
File configFile = new File(configFolder, "discord.yml");
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
// Копируем из resources/config/discord.yml
|
||||
java.io.InputStream in = plugin.getResource("config/discord.yml");
|
||||
if (in != null) {
|
||||
java.nio.file.Files.copy(in, configFile.toPath());
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to copy config/discord.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
config = YamlConfiguration.loadConfiguration(configFile);
|
||||
enabled = config.getBoolean("enabled", false);
|
||||
private void init() {
|
||||
config = new DiscordConfig(plugin);
|
||||
enabled = config.isEnabled();
|
||||
|
||||
if (!enabled) {
|
||||
plugin.getLogger().info("Discord integration disabled in config");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Инициализировать вебхук
|
||||
*/
|
||||
private void initWebhook() {
|
||||
if (!enabled) return;
|
||||
|
||||
// Получаем конфигурацию внешнего вида для дефолтных значений
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
messageService = new DiscordMessageService(plugin, config);
|
||||
|
||||
String webhookUrl = config.getString("webhook.url", "");
|
||||
String username = config.getString("webhook.username", "Minecraft Server");
|
||||
String avatarUrl = config.getString("webhook.avatar_url", appearanceConfig.getDefaultAvatarUrl());
|
||||
int timeout = config.getInt("performance.timeout", 10);
|
||||
int retryAttempts = config.getInt("performance.retry_attempts", 3);
|
||||
long retryDelay = config.getLong("performance.retry_delay", 1000);
|
||||
|
||||
// Логируем только факт наличия URL, но не его содержимое (security)
|
||||
|
||||
webhook = new DiscordWebhook(plugin, webhookUrl, username, avatarUrl, timeout, retryAttempts, retryDelay);
|
||||
|
||||
if (!webhook.isValid()) {
|
||||
if (!messageService.isValid()) {
|
||||
plugin.getLogger().severe("Invalid Discord webhook URL! Please check config/discord.yml");
|
||||
enabled = false;
|
||||
return;
|
||||
|
|
@ -90,205 +39,47 @@ public class DiscordIntegration {
|
|||
plugin.getLogger().info("Discord integration initialized successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить сообщение чата в Discord
|
||||
*/
|
||||
public void sendChatMessage(Player player, String message, boolean isGlobal) {
|
||||
if (!enabled || !config.getBoolean("chat.enabled", true)) return;
|
||||
if (!enabled || !config.isChatEnabled()) return;
|
||||
|
||||
// Проверяем фильтр глобального чата
|
||||
if (config.getBoolean("chat.global_only", true) && !isGlobal) {
|
||||
if (config.isGlobalOnly() && !isGlobal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Фильтрация сообщения
|
||||
String cleanMessage = sanitizeMessage(message);
|
||||
if (cleanMessage.length() < config.getInt("filter.min_message_length", 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Обрезаем если слишком длинное
|
||||
int maxLength = config.getInt("filter.max_message_length", 2000);
|
||||
if (cleanMessage.length() > maxLength) {
|
||||
cleanMessage = cleanMessage.substring(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
String playerName = player.getName();
|
||||
String format = config.getString("chat.format", "**{player}**: {message}");
|
||||
String formattedMessage = format
|
||||
.replace("{player}", playerName)
|
||||
.replace("{message}", cleanMessage);
|
||||
|
||||
// Отправляем асинхронно
|
||||
if (config.getBoolean("performance.async", true)) {
|
||||
FoliaUtil.runAsync(plugin, () -> sendChatMessageInternal(formattedMessage, playerName, isGlobal));
|
||||
} else {
|
||||
sendChatMessageInternal(formattedMessage, playerName, isGlobal);
|
||||
}
|
||||
messageService.sendChatMessage(player, message, isGlobal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Внутренний метод отправки сообщения чата
|
||||
*/
|
||||
private void sendChatMessageInternal(String message, String playerName, boolean isGlobal) {
|
||||
if (config.getBoolean("chat.use_embed", true)) {
|
||||
// Получаем заголовки из конфигурации внешнего вида
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String title = isGlobal ?
|
||||
appearanceConfig.getDiscordEventTitle("global_chat") :
|
||||
appearanceConfig.getDiscordEventTitle("local_chat");
|
||||
|
||||
// Если заголовок не найден в новой конфигурации, используем старый способ
|
||||
if (title.isEmpty()) {
|
||||
title = isGlobal ? "🌍 Глобальный чат" : "📍 Локальный чат";
|
||||
}
|
||||
|
||||
String color = config.getString("chat.embed_color", appearanceConfig.getDefaultEmbedColor());
|
||||
String thumbnail = appearanceConfig.getPlayerAvatarUrl().replace("{player}", playerName);
|
||||
|
||||
webhook.sendEmbed(title, message, color, thumbnail);
|
||||
} else {
|
||||
webhook.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить событие входа игрока
|
||||
*/
|
||||
public void sendPlayerJoin(Player player) {
|
||||
if (!enabled || !config.getBoolean("events.enabled", true) ||
|
||||
!config.getBoolean("events.join.enabled", true)) return;
|
||||
|
||||
// Получаем конфигурацию внешнего вида
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String playerName = player.getName();
|
||||
String title = config.getString("events.join.title", appearanceConfig.getDiscordEventTitle("join"));
|
||||
String description = config.getString("events.join.description", "**{player}** присоединился к серверу")
|
||||
.replace("{player}", playerName);
|
||||
String color = config.getString("events.join.color", "00FF00");
|
||||
String thumbnail = config.getString("events.join.thumbnail", appearanceConfig.getPlayerAvatarUrl())
|
||||
.replace("{player}", playerName);
|
||||
|
||||
if (config.getBoolean("performance.async", true)) {
|
||||
FoliaUtil.runAsync(plugin, () -> webhook.sendEmbed(title, description, color, thumbnail));
|
||||
} else {
|
||||
webhook.sendEmbed(title, description, color, thumbnail);
|
||||
}
|
||||
if (!enabled || !config.isEventEnabled("join")) return;
|
||||
messageService.sendPlayerJoin(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить событие выхода игрока
|
||||
*/
|
||||
public void sendPlayerQuit(Player player) {
|
||||
if (!enabled || !config.getBoolean("events.enabled", true) ||
|
||||
!config.getBoolean("events.quit.enabled", true)) return;
|
||||
|
||||
// Получаем конфигурацию внешнего вида
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String playerName = player.getName();
|
||||
String title = config.getString("events.quit.title", appearanceConfig.getDiscordEventTitle("quit"));
|
||||
String description = config.getString("events.quit.description", "**{player}** покинул сервер")
|
||||
.replace("{player}", playerName);
|
||||
String color = config.getString("events.quit.color", "FF0000");
|
||||
String thumbnail = config.getString("events.quit.thumbnail", appearanceConfig.getPlayerAvatarUrl())
|
||||
.replace("{player}", playerName);
|
||||
|
||||
if (config.getBoolean("performance.async", true)) {
|
||||
FoliaUtil.runAsync(plugin, () -> webhook.sendEmbed(title, description, color, thumbnail));
|
||||
} else {
|
||||
webhook.sendEmbed(title, description, color, thumbnail);
|
||||
}
|
||||
if (!enabled || !config.isEventEnabled("quit")) return;
|
||||
messageService.sendPlayerQuit(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить событие смерти игрока
|
||||
*/
|
||||
public void sendPlayerDeath(Player player, String deathMessage) {
|
||||
if (!enabled || !config.getBoolean("events.enabled", true) ||
|
||||
!config.getBoolean("events.death.enabled", true)) return;
|
||||
|
||||
// Получаем конфигурацию внешнего вида
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String playerName = player.getName();
|
||||
String title = config.getString("events.death.title", appearanceConfig.getDiscordEventTitle("death"));
|
||||
String description = config.getString("events.death.description", "**{player}** {death_message}")
|
||||
.replace("{player}", playerName)
|
||||
.replace("{death_message}", sanitizeMessage(deathMessage));
|
||||
String color = config.getString("events.death.color", "800080");
|
||||
String thumbnail = config.getString("events.death.thumbnail", appearanceConfig.getPlayerAvatarUrl())
|
||||
.replace("{player}", playerName);
|
||||
|
||||
if (config.getBoolean("performance.async", true)) {
|
||||
FoliaUtil.runAsync(plugin, () -> webhook.sendEmbed(title, description, color, thumbnail));
|
||||
} else {
|
||||
webhook.sendEmbed(title, description, color, thumbnail);
|
||||
}
|
||||
if (!enabled || !config.isEventEnabled("death")) return;
|
||||
messageService.sendPlayerDeath(player, deathMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Очистить сообщение от нежелательных элементов
|
||||
*/
|
||||
private String sanitizeMessage(String message) {
|
||||
if (message == null) return "";
|
||||
|
||||
// Удаляем цветовые коды Minecraft
|
||||
message = COLOR_CODE_PATTERN.matcher(message).replaceAll("");
|
||||
|
||||
// Заменяем опасные упоминания
|
||||
if (config.getBoolean("filter.sanitize_mentions", true)) {
|
||||
message = MENTION_PATTERN.matcher(message).replaceAll("@\u200B$1"); // Добавляем невидимый символ
|
||||
}
|
||||
|
||||
// Экранируем Discord markdown
|
||||
message = message.replace("*", "\\*")
|
||||
.replace("_", "\\_")
|
||||
.replace("`", "\\`")
|
||||
.replace("~", "\\~");
|
||||
|
||||
return message.trim();
|
||||
public void sendTestMessage(String message, String senderName) {
|
||||
if (!enabled) return;
|
||||
messageService.sendTestMessage(message, senderName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Перезагрузить конфигурацию
|
||||
*/
|
||||
public void reload() {
|
||||
loadConfig();
|
||||
initWebhook();
|
||||
init();
|
||||
plugin.getLogger().info("Discord integration reloaded");
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправить тестовое сообщение
|
||||
*/
|
||||
public void sendTestMessage(String message, String senderName) {
|
||||
if (!enabled) return;
|
||||
|
||||
String title = "🧪 Тестовое сообщение";
|
||||
String description = "**Отправитель:** " + senderName + "\n**Сообщение:** " + message;
|
||||
String color = "FFD700"; // золотой цвет
|
||||
String thumbnail = "https://mc-heads.net/avatar/" + senderName + "/64";
|
||||
|
||||
webhook.sendEmbed(title, description, color, thumbnail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить executor при выключении плагина
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (webhook != null) webhook.shutdown();
|
||||
if (messageService != null) {
|
||||
messageService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить включена ли интеграция
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package com.loki.lochat.integrations;
|
|||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.api.service.ChatService;
|
||||
import com.loki.lochat.api.service.IgnoreService;
|
||||
import com.loki.lochat.api.service.PMService;
|
||||
import com.loki.lochat.api.service.SpyService;
|
||||
import com.loki.lochat.api.service.MessagingService;
|
||||
import com.loki.lochat.gradient.GradientModule;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.Bukkit;
|
||||
|
|
@ -19,17 +17,13 @@ import java.util.UUID;
|
|||
public class PlaceholderAPIHook extends PlaceholderExpansion {
|
||||
|
||||
private final LoChat plugin;
|
||||
private final IgnoreService ignoreService;
|
||||
private final MessagingService messagingService;
|
||||
private final ChatService chatService;
|
||||
private final PMService pmService;
|
||||
private final SpyService spyService;
|
||||
|
||||
public PlaceholderAPIHook(LoChat plugin) {
|
||||
this.plugin = plugin;
|
||||
this.ignoreService = plugin.getServiceRegistry().get(IgnoreService.class);
|
||||
this.messagingService = plugin.getServiceRegistry().get(MessagingService.class);
|
||||
this.chatService = plugin.getServiceRegistry().get(ChatService.class);
|
||||
this.pmService = plugin.getServiceRegistry().get(PMService.class);
|
||||
this.spyService = plugin.getServiceRegistry().get(SpyService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -60,15 +54,15 @@ public class PlaceholderAPIHook extends PlaceholderExpansion {
|
|||
GradientModule gradient = plugin.getGradientModule();
|
||||
|
||||
return switch (params.toLowerCase()) {
|
||||
case "ignored_count" -> String.valueOf(ignoreService.getIgnoredCount(uuid));
|
||||
case "ignored_count" -> String.valueOf(messagingService.getIgnoredCount(uuid));
|
||||
case "global_enabled" -> String.valueOf(!chatService.isGlobalChatDisabled(uuid));
|
||||
case "last_pm" -> {
|
||||
Optional<UUID> lastOpt = pmService.getLastConversation(uuid);
|
||||
Optional<UUID> lastOpt = messagingService.getLastConversation(uuid);
|
||||
if (lastOpt.isEmpty()) yield "";
|
||||
var lastPlayer = Bukkit.getOfflinePlayer(lastOpt.get());
|
||||
yield lastPlayer.getName() != null ? lastPlayer.getName() : "";
|
||||
}
|
||||
case "spy_enabled" -> String.valueOf(spyService.isSpying(uuid));
|
||||
case "spy_enabled" -> String.valueOf(messagingService.isSpying(uuid));
|
||||
|
||||
// Gradient placeholders (совместимость с LoPreff)
|
||||
// Используем TAB формат §x§R§R§G§G§B§B для совместимости с TAB плагином
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
package com.loki.lochat.integrations.discord;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Конфигурация Discord интеграции
|
||||
*/
|
||||
public class DiscordConfig {
|
||||
private final JavaPlugin plugin;
|
||||
private YamlConfiguration config;
|
||||
|
||||
public DiscordConfig(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
File configFolder = new File(plugin.getDataFolder(), "config");
|
||||
if (!configFolder.exists()) {
|
||||
configFolder.mkdirs();
|
||||
}
|
||||
|
||||
File configFile = new File(configFolder, "discord.yml");
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
java.io.InputStream in = plugin.getResource("config/discord.yml");
|
||||
if (in != null) {
|
||||
java.nio.file.Files.copy(in, configFile.toPath());
|
||||
in.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to copy config/discord.yml: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
config = YamlConfiguration.loadConfiguration(configFile);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return config.getBoolean("enabled", false);
|
||||
}
|
||||
|
||||
public String getWebhookUrl() {
|
||||
return config.getString("webhook.url", "");
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return config.getString("webhook.username", "Minecraft Server");
|
||||
}
|
||||
|
||||
public String getAvatarUrl() {
|
||||
return config.getString("webhook.avatar_url", "");
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return config.getInt("performance.timeout", 10);
|
||||
}
|
||||
|
||||
public int getRetryAttempts() {
|
||||
return config.getInt("performance.retry_attempts", 3);
|
||||
}
|
||||
|
||||
public long getRetryDelay() {
|
||||
return config.getLong("performance.retry_delay", 1000);
|
||||
}
|
||||
|
||||
public boolean isAsync() {
|
||||
return config.getBoolean("performance.async", true);
|
||||
}
|
||||
|
||||
public boolean isChatEnabled() {
|
||||
return config.getBoolean("chat.enabled", true);
|
||||
}
|
||||
|
||||
public boolean isGlobalOnly() {
|
||||
return config.getBoolean("chat.global_only", true);
|
||||
}
|
||||
|
||||
public boolean useEmbed() {
|
||||
return config.getBoolean("chat.use_embed", true);
|
||||
}
|
||||
|
||||
public String getChatFormat() {
|
||||
return config.getString("chat.format", "**{player}**: {message}");
|
||||
}
|
||||
|
||||
public String getEmbedColor() {
|
||||
return config.getString("chat.embed_color", "5865F2");
|
||||
}
|
||||
|
||||
public boolean isEventEnabled(String event) {
|
||||
return config.getBoolean("events.enabled", true) &&
|
||||
config.getBoolean("events." + event + ".enabled", true);
|
||||
}
|
||||
|
||||
public String getEventTitle(String event) {
|
||||
return config.getString("events." + event + ".title", "");
|
||||
}
|
||||
|
||||
public String getEventDescription(String event) {
|
||||
return config.getString("events." + event + ".description", "");
|
||||
}
|
||||
|
||||
public String getEventColor(String event) {
|
||||
return config.getString("events." + event + ".color", "5865F2");
|
||||
}
|
||||
|
||||
public String getEventThumbnail(String event) {
|
||||
return config.getString("events." + event + ".thumbnail", "");
|
||||
}
|
||||
|
||||
public int getMinMessageLength() {
|
||||
return config.getInt("filter.min_message_length", 1);
|
||||
}
|
||||
|
||||
public int getMaxMessageLength() {
|
||||
return config.getInt("filter.max_message_length", 2000);
|
||||
}
|
||||
|
||||
public boolean sanitizeMentions() {
|
||||
return config.getBoolean("filter.sanitize_mentions", true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package com.loki.lochat.integrations.discord;
|
||||
|
||||
import com.loki.lochat.integrations.DiscordWebhook;
|
||||
import com.loki.lochat.utils.FoliaUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Сервис для отправки сообщений в Discord
|
||||
*/
|
||||
public class DiscordMessageService {
|
||||
private static final Pattern MENTION_PATTERN = Pattern.compile("@(everyone|here)", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("§[0-9a-fk-or]", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final DiscordConfig config;
|
||||
private final DiscordWebhook webhook;
|
||||
|
||||
public DiscordMessageService(JavaPlugin plugin, DiscordConfig config) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.webhook = new DiscordWebhook(
|
||||
plugin,
|
||||
config.getWebhookUrl(),
|
||||
config.getUsername(),
|
||||
getAvatarUrl(),
|
||||
config.getTimeout(),
|
||||
config.getRetryAttempts(),
|
||||
config.getRetryDelay()
|
||||
);
|
||||
}
|
||||
|
||||
private String getAvatarUrl() {
|
||||
String url = config.getAvatarUrl();
|
||||
if (url.isEmpty()) {
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
return loChat.getConfigManager().getAppearanceConfig().getDefaultAvatarUrl();
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
public void sendChatMessage(Player player, String message, boolean isGlobal) {
|
||||
String cleanMessage = sanitizeMessage(message);
|
||||
|
||||
if (cleanMessage.length() < config.getMinMessageLength()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanMessage.length() > config.getMaxMessageLength()) {
|
||||
cleanMessage = cleanMessage.substring(0, config.getMaxMessageLength() - 3) + "...";
|
||||
}
|
||||
|
||||
String formatted = config.getChatFormat()
|
||||
.replace("{player}", player.getName())
|
||||
.replace("{message}", cleanMessage);
|
||||
|
||||
if (config.isAsync()) {
|
||||
FoliaUtil.runAsync(plugin, () -> sendFormatted(formatted, player, isGlobal));
|
||||
} else {
|
||||
sendFormatted(formatted, player, isGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFormatted(String message, Player player, boolean isGlobal) {
|
||||
if (config.useEmbed()) {
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String title = isGlobal ?
|
||||
appearanceConfig.getDiscordEventTitle("global_chat") :
|
||||
appearanceConfig.getDiscordEventTitle("local_chat");
|
||||
|
||||
if (title.isEmpty()) {
|
||||
title = isGlobal ? "🌍 Глобальный чат" : "📍 Локальный чат";
|
||||
}
|
||||
|
||||
String color = config.getEmbedColor();
|
||||
String thumbnail = appearanceConfig.getPlayerAvatarUrl().replace("{player}", player.getName());
|
||||
|
||||
webhook.sendEmbed(title, message, color, thumbnail);
|
||||
} else {
|
||||
webhook.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPlayerJoin(Player player) {
|
||||
sendEvent(player, "join", null);
|
||||
}
|
||||
|
||||
public void sendPlayerQuit(Player player) {
|
||||
sendEvent(player, "quit", null);
|
||||
}
|
||||
|
||||
public void sendPlayerDeath(Player player, String deathMessage) {
|
||||
sendEvent(player, "death", deathMessage);
|
||||
}
|
||||
|
||||
private void sendEvent(Player player, String event, String extraMessage) {
|
||||
com.loki.lochat.LoChat loChat = (com.loki.lochat.LoChat) plugin;
|
||||
com.loki.lochat.config.AppearanceConfig appearanceConfig = loChat.getConfigManager().getAppearanceConfig();
|
||||
|
||||
String title = config.getEventTitle(event);
|
||||
if (title.isEmpty()) {
|
||||
title = appearanceConfig.getDiscordEventTitle(event);
|
||||
}
|
||||
|
||||
String description = config.getEventDescription(event)
|
||||
.replace("{player}", player.getName());
|
||||
|
||||
if (extraMessage != null) {
|
||||
description = description.replace("{death_message}", sanitizeMessage(extraMessage));
|
||||
}
|
||||
|
||||
String color = config.getEventColor(event);
|
||||
String thumbnail = config.getEventThumbnail(event);
|
||||
if (thumbnail.isEmpty()) {
|
||||
thumbnail = appearanceConfig.getPlayerAvatarUrl();
|
||||
}
|
||||
final String finalThumbnail = thumbnail.replace("{player}", player.getName());
|
||||
final String finalTitle = title;
|
||||
final String finalDescription = description;
|
||||
final String finalColor = color;
|
||||
|
||||
if (config.isAsync()) {
|
||||
FoliaUtil.runAsync(plugin, () -> webhook.sendEmbed(finalTitle, finalDescription, finalColor, finalThumbnail));
|
||||
} else {
|
||||
webhook.sendEmbed(title, description, color, finalThumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendTestMessage(String message, String senderName) {
|
||||
String title = "🧪 Тестовое сообщение";
|
||||
String description = "**Отправитель:** " + senderName + "\n**Сообщение:** " + message;
|
||||
String color = "FFD700";
|
||||
String thumbnail = "https://mc-heads.net/avatar/" + senderName + "/64";
|
||||
|
||||
webhook.sendEmbed(title, description, color, thumbnail);
|
||||
}
|
||||
|
||||
private String sanitizeMessage(String message) {
|
||||
if (message == null) return "";
|
||||
|
||||
message = COLOR_CODE_PATTERN.matcher(message).replaceAll("");
|
||||
|
||||
if (config.sanitizeMentions()) {
|
||||
message = MENTION_PATTERN.matcher(message).replaceAll("@\u200B$1");
|
||||
}
|
||||
|
||||
message = message.replace("*", "\\*")
|
||||
.replace("_", "\\_")
|
||||
.replace("`", "\\`")
|
||||
.replace("~", "\\~");
|
||||
|
||||
return message.trim();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return webhook.isValid();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
webhook.shutdown();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue