From 5088e3ad1c142e5e5b8663fe04bd60eee1f5efc6 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Fri, 13 Mar 2026 15:51:47 +0100 Subject: [PATCH] fix color --- README.md | 61 ++++++ src/main/java/com/loki/lochat/LoChat.java | 14 +- .../commands/CustomCommandsCommand.java | 128 +++++++++++ .../loki/lochat/commands/DiscordCommand.java | 27 ++- .../loki/lochat/commands/LoChatCommand.java | 22 +- .../lochat/core/service/ChatServiceImpl.java | 7 + .../gradient/config/GradientConfig.java | 5 + .../listeners/GradientPlayerListener.java | 6 +- .../lochat/gradient/util/DisplayNameUtil.java | 2 +- .../integrations/DiscordIntegration.java | 6 + .../lochat/integrations/DiscordWebhook.java | 35 ++- .../lochat/listener/ChatEventListener.java | 18 ++ .../lochat/managers/CustomCommandManager.java | 79 +++++-- .../lochat/renderer/EnhancedChatRenderer.java | 14 +- src/main/resources/config.yml | 8 + src/main/resources/config/custom-commands.yml | 203 ------------------ src/main/resources/config/gradient-config.yml | 49 ++++- src/main/resources/custom-commands.yml | 140 ++++++++++++ src/main/resources/messages.yml | 50 +++++ src/main/resources/plugin.yml | 172 +-------------- 20 files changed, 623 insertions(+), 423 deletions(-) create mode 100644 src/main/java/com/loki/lochat/commands/CustomCommandsCommand.java delete mode 100644 src/main/resources/config/custom-commands.yml create mode 100644 src/main/resources/custom-commands.yml diff --git a/README.md b/README.md index 805c061..052d503 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,67 @@ cd Lochat ``` Установит префикс `[VIP]` перед ником. +### Настройка системы оплаты градиентов + +#### Вариант 1: Через PlayerPoints (платно) +```yaml +# config/gradient-config.yml +gradient: + price-per-color: 50 # 50 поинтов за каждый цвет + prefix-price: 500 # 500 поинтов за префикс + use-permission-instead-of-cost: false +``` + +Игроки платят поинтами за установку градиентов. + +#### Вариант 2: Через пермишены (бесплатно) +```yaml +# config/gradient-config.yml +gradient: + price-per-color: 0 # Бесплатно + prefix-price: 0 # Бесплатно + use-permission-instead-of-cost: true +``` + +Выдайте игрокам права: +``` +/lp user <игрок> permission set gradient.color true +/lp user <игрок> permission set gradient.prefix true +/lp user <игрок> permission set gradient.bypass.cost true +``` + +Или через группу: +``` +/lp group vip permission set gradient.color true +/lp group vip permission set gradient.prefix true +/lp group vip permission set gradient.bypass.cost true +``` + +### Основные пермишены градиентов + +| Пермишен | Описание | +|----------|----------| +| `gradient.color` | Доступ к команде /color | +| `gradient.prefix` | Доступ к команде /prefix | +| `gradient.bypass.cost` | Бесплатное использование (обход стоимости) | +| `gradient.bypass.cooldown` | Обход кулдауна | +| `gradient.admin` | Админские команды /aprefix | +| `gradient.colors.5` | Максимум 5 цветов в градиенте | +| `gradient.colors.10` | Максимум 10 цветов в градиенте | +| `gradient.colors.unlimited` | Неограниченное количество цветов | + +### Текущие цены (по умолчанию) + +- **Градиент**: 50 поинтов за каждый цвет + - 1 цвет = 50 поинтов + - 2 цвета = 100 поинтов + - 3 цвета = 150 поинтов + - и т.д. + +- **Префикс**: 500 поинтов (одноразовая покупка) + +Цены настраиваются в `config/gradient-config.yml` + ### Мут игрока ``` /lmute Player123 1h Спам в чате diff --git a/src/main/java/com/loki/lochat/LoChat.java b/src/main/java/com/loki/lochat/LoChat.java index 1b0d5a5..ac23e39 100644 --- a/src/main/java/com/loki/lochat/LoChat.java +++ b/src/main/java/com/loki/lochat/LoChat.java @@ -119,7 +119,6 @@ public final class LoChat extends JavaPlugin { getCommand("announce").setExecutor(new AnnounceCommand(this)); getCommand("chatspy").setExecutor(new ChatSpyCommand(this)); getCommand("clearchat").setExecutor(new ClearChatCommand(this)); - getCommand("hub").setExecutor(new HubCommand(this)); NickCommand nickCmd = new NickCommand(this); getCommand("nick").setExecutor(nickCmd); @@ -151,10 +150,15 @@ public final class LoChat extends JavaPlugin { getCommand("clearchatconfig").setExecutor(clearCfgCmd); getCommand("clearchatconfig").setTabCompleter(clearCfgCmd); - // Discord команда - DiscordCommand discordCmd = new DiscordCommand(this, discordIntegration); - getCommand("discord").setExecutor(discordCmd); - getCommand("discord").setTabCompleter(discordCmd); + // Custom commands управление + CustomCommandsCommand customCommandsCmd = new CustomCommandsCommand(this, customCommandManager); + getCommand("customcommands").setExecutor(customCommandsCmd); + getCommand("customcommands").setTabCompleter(customCommandsCmd); + + // Discord admin команда (отдельно от кастомной /discord) + DiscordCommand discordAdminCmd = new DiscordCommand(this, discordIntegration); + getCommand("discordadmin").setExecutor(discordAdminCmd); + getCommand("discordadmin").setTabCompleter(discordAdminCmd); } private void registerListeners() { diff --git a/src/main/java/com/loki/lochat/commands/CustomCommandsCommand.java b/src/main/java/com/loki/lochat/commands/CustomCommandsCommand.java new file mode 100644 index 0000000..ec61511 --- /dev/null +++ b/src/main/java/com/loki/lochat/commands/CustomCommandsCommand.java @@ -0,0 +1,128 @@ +package com.loki.lochat.commands; + +import com.loki.lochat.LoChat; +import com.loki.lochat.managers.CustomCommandManager; +import com.loki.lochat.utils.ChatFormatter; +import net.kyori.adventure.text.Component; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CustomCommandsCommand implements CommandExecutor, TabCompleter { + + private final LoChat plugin; + private final CustomCommandManager commandManager; + + public CustomCommandsCommand(LoChat plugin, CustomCommandManager commandManager) { + this.plugin = plugin; + this.commandManager = commandManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!sender.hasPermission("lochat.customcommands")) { + sender.sendMessage(ChatFormatter.parse("<#F44336>❌ У вас нет прав для использования этой команды!")); + return true; + } + + if (args.length == 0) { + showHelp(sender); + return true; + } + + switch (args[0].toLowerCase()) { + case "list" -> showCommandsList(sender); + case "reload" -> reloadCommands(sender); + case "enable" -> { + if (args.length < 2) { + sender.sendMessage(ChatFormatter.parse("<#FFA726>⚠️ Использование: /customcommands enable <команда>")); + return true; + } + toggleCommand(sender, args[1], true); + } + case "disable" -> { + if (args.length < 2) { + sender.sendMessage(ChatFormatter.parse("<#FFA726>⚠️ Использование: /customcommands disable <команда>")); + return true; + } + toggleCommand(sender, args[1], false); + } + default -> showHelp(sender); + } + + return true; + } + + private void showHelp(CommandSender sender) { + Component message = ChatFormatter.parse(""" + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + 🛠️ Управление кастомными командами + + <#FFEB3B>📋 Доступные команды: + <#9E9E9E>• <#FFFFFF>/customcommands list - список команд + <#9E9E9E>• <#FFFFFF>/customcommands reload - перезагрузить команды + <#9E9E9E>• <#FFFFFF>/customcommands enable <команда> - включить команду + <#9E9E9E>• <#FFFFFF>/customcommands disable <команда> - выключить команду + + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + """); + sender.sendMessage(message); + } + + private void showCommandsList(CommandSender sender) { + net.kyori.adventure.text.TextComponent.Builder message = Component.text() + .append(ChatFormatter.parse("▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n")) + .append(ChatFormatter.parse("📋 Кастомные команды\n\n")); + + for (CustomCommandManager.CustomCommandData data : commandManager.getCommands().values()) { + String status = data.enabled() ? "<#4CAF50>✅ Включена" : "<#F44336>❌ Выключена"; + String permission = data.permission() != null ? " <#9E9E9E>(Права: " + data.permission() + ")" : ""; + + message.append(ChatFormatter.parse( + "<#FFFFFF>/" + data.name() + " " + status + permission + "\n" + )); + } + + message.append(ChatFormatter.parse("\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬")); + sender.sendMessage(message.build()); + } + + private void reloadCommands(CommandSender sender) { + try { + commandManager.reload(); + sender.sendMessage(ChatFormatter.parse("<#4CAF50>✅ Кастомные команды успешно перезагружены!")); + } catch (Exception e) { + sender.sendMessage(ChatFormatter.parse("<#F44336>❌ Ошибка при перезагрузке команд: " + e.getMessage())); + plugin.getLogger().severe("Ошибка перезагрузки кастомных команд: " + e.getMessage()); + } + } + + private void toggleCommand(CommandSender sender, String commandName, boolean enable) { + sender.sendMessage(ChatFormatter.parse( + "<#FFA726>⚠️ Для изменения статуса команд отредактируйте файл custom-commands.yml и выполните /customcommands reload" + )); + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (!sender.hasPermission("lochat.customcommands")) { + return new ArrayList<>(); + } + + if (args.length == 1) { + return Arrays.asList("list", "reload", "enable", "disable"); + } + + if (args.length == 2 && (args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("disable"))) { + return new ArrayList<>(commandManager.getCommands().keySet()); + } + + return new ArrayList<>(); + } +} \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/commands/DiscordCommand.java b/src/main/java/com/loki/lochat/commands/DiscordCommand.java index 566ca22..8b39d94 100644 --- a/src/main/java/com/loki/lochat/commands/DiscordCommand.java +++ b/src/main/java/com/loki/lochat/commands/DiscordCommand.java @@ -90,17 +90,28 @@ public class DiscordCommand implements CommandExecutor, TabCompleter { sender.sendMessage(ChatFormatter.parse("&e⏳ Отправка тестового сообщения...")); - // Отправляем тестовое сообщение - plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + // Используем CompletableFuture для асинхронной отправки (Folia-совместимо) + java.util.concurrent.CompletableFuture.runAsync(() -> { try { discord.sendTestMessage(message, sender.getName()); - plugin.getServer().getScheduler().runTask(plugin, () -> - sender.sendMessage(ChatFormatter.parse("&a✓ Тестовое сообщение отправлено в Discord")) - ); + // Возвращаемся в главный поток для отправки сообщения + if (sender instanceof org.bukkit.entity.Player player) { + player.getScheduler().run(plugin, (task) -> + sender.sendMessage(ChatFormatter.parse("&a✓ Тестовое сообщение отправлено в Discord")), null + ); + } else { + // Для консоли можно отправить сразу + sender.sendMessage(ChatFormatter.parse("&a✓ Тестовое сообщение отправлено в Discord")); + } } catch (Exception e) { - plugin.getServer().getScheduler().runTask(plugin, () -> - sender.sendMessage(ChatFormatter.parse("&c✗ Ошибка отправки: " + e.getMessage())) - ); + if (sender instanceof org.bukkit.entity.Player player) { + player.getScheduler().run(plugin, (task) -> + sender.sendMessage(ChatFormatter.parse("&c✗ Ошибка отправки: " + e.getMessage())), null + ); + } else { + sender.sendMessage(ChatFormatter.parse("&c✗ Ошибка отправки: " + e.getMessage())); + } + plugin.getLogger().severe("Discord test error: " + e.getMessage()); } }); } diff --git a/src/main/java/com/loki/lochat/commands/LoChatCommand.java b/src/main/java/com/loki/lochat/commands/LoChatCommand.java index 3fee605..687855c 100644 --- a/src/main/java/com/loki/lochat/commands/LoChatCommand.java +++ b/src/main/java/com/loki/lochat/commands/LoChatCommand.java @@ -30,36 +30,36 @@ public class LoChatCommand implements CommandExecutor, TabCompleter { } if (args.length == 0) { - sender.sendMessage(MM.deserialize("&#FFD700LoChat v" + plugin.getPluginMeta().getVersion())); - sender.sendMessage(MM.deserialize("󅒐Команды:")); - sender.sendMessage(MM.deserialize("&#FFFF00/lochat reload - Перезагрузить конфиги")); - sender.sendMessage(MM.deserialize("&#FFFF00/lochat commands - Список кастомных команд")); - sender.sendMessage(MM.deserialize("&#FFFF00/lochat commands reload - Перезагрузить кастомные команды")); + sender.sendMessage(MM.deserialize("<#FFD700>LoChat v" + plugin.getPluginMeta().getVersion())); + sender.sendMessage(MM.deserialize("<#808080>Команды:")); + sender.sendMessage(MM.deserialize("<#FFFF00>/lochat reload <#808080>- Перезагрузить конфиги")); + sender.sendMessage(MM.deserialize("<#FFFF00>/lochat commands <#808080>- Список кастомных команд")); + sender.sendMessage(MM.deserialize("<#FFFF00>/lochat commands reload <#808080>- Перезагрузить кастомные команды")); return true; } switch (args[0].toLowerCase()) { case "reload" -> { plugin.reload(); - sender.sendMessage(MM.deserialize("�FF00Конфигурация перезагружена!")); + sender.sendMessage(MM.deserialize("<#00FF00>Конфигурация перезагружена!")); } case "commands" -> { if (args.length > 1 && args[1].equalsIgnoreCase("reload")) { plugin.getCustomCommandManager().reload(); - sender.sendMessage(MM.deserialize("�FF00Кастомные команды перезагружены!")); + sender.sendMessage(MM.deserialize("<#00FF00>Кастомные команды перезагружены!")); } else { var commands = plugin.getCustomCommandManager().getCommands(); - sender.sendMessage(MM.deserialize("&#FFD700Кастомные команды (" + commands.size() + "):")); + sender.sendMessage(MM.deserialize("<#FFD700>Кастомные команды (" + commands.size() + "):")); for (var cmd : commands.values()) { - sender.sendMessage(MM.deserialize("&e/" + cmd.name() + " 󅒐(" + cmd.type() + ")")); + sender.sendMessage(MM.deserialize("<#FFEB3B>/" + cmd.name() + " <#808080>(" + cmd.type() + ")")); if (!cmd.aliases().isEmpty()) { - sender.sendMessage(MM.deserialize("󅒐 Алиасы: " + String.join(", ", cmd.aliases()))); + sender.sendMessage(MM.deserialize("<#808080> Алиасы: " + String.join(", ", cmd.aliases()))); } } } } default -> - sender.sendMessage(MM.deserialize("&#FF0000Неизвестная команда. Используйте /lochat для помощи.")); + sender.sendMessage(MM.deserialize("<#FF0000>Неизвестная команда. Используйте /lochat для помощи.")); } return true; diff --git a/src/main/java/com/loki/lochat/core/service/ChatServiceImpl.java b/src/main/java/com/loki/lochat/core/service/ChatServiceImpl.java index 0a0c39f..edf43aa 100644 --- a/src/main/java/com/loki/lochat/core/service/ChatServiceImpl.java +++ b/src/main/java/com/loki/lochat/core/service/ChatServiceImpl.java @@ -53,12 +53,19 @@ public class ChatServiceImpl implements ChatService { // Используем тот же рендерер что и в ChatEventListener для единообразия EnhancedChatRenderer renderer = new EnhancedChatRenderer(plugin, sender, messageComponent, false); + int recipientCount = 0; for (Player player : Bukkit.getOnlinePlayers()) { if (DistanceUtil.isInRange(sender, player, radius)) { Component renderedMessage = renderer.render(sender, sender.displayName(), messageComponent, player); player.sendMessage(renderedMessage); + recipientCount++; } } + + // Если никто не услышал (только отправитель в радиусе) + if (recipientCount <= 1) { + sender.sendMessage(ChatFormatter.parse(plugin.getConfig().getString("messages.local.nobody-heard", "<#FFA726>Вас никто не услышал - рядом нет игроков"))); + } } @Override diff --git a/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java b/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java index 51834f7..ffecf73 100644 --- a/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java +++ b/src/main/java/com/loki/lochat/gradient/config/GradientConfig.java @@ -81,6 +81,11 @@ public class GradientConfig { } public String getPrefixFormat() { + // Сначала проверяем в formatting.prefix-format (из gradient-config.yml) + if (config.contains("formatting.prefix-format")) { + return config.getString("formatting.prefix-format", "[{prefix}] "); + } + // Затем проверяем в gradient.prefix-format (из config.yml) return config.getString("gradient.prefix-format", "[{prefix}] "); } diff --git a/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java b/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java index 2ece0b1..4f2ed44 100644 --- a/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java +++ b/src/main/java/com/loki/lochat/gradient/listeners/GradientPlayerListener.java @@ -24,7 +24,11 @@ public class GradientPlayerListener implements Listener { public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); FoliaUtil.runAsync(module.getPlugin(), () -> { - module.getDataManager().getPlayerData(player.getUniqueId()); + var data = module.getDataManager().getPlayerData(player.getUniqueId()); + // Применяем градиент к displayName при входе + FoliaUtil.runEntityTask(module.getPlugin(), player, () -> { + com.loki.lochat.gradient.util.DisplayNameUtil.updateDisplayName(module, player, data); + }); }); } diff --git a/src/main/java/com/loki/lochat/gradient/util/DisplayNameUtil.java b/src/main/java/com/loki/lochat/gradient/util/DisplayNameUtil.java index 4fab35c..4b97c74 100644 --- a/src/main/java/com/loki/lochat/gradient/util/DisplayNameUtil.java +++ b/src/main/java/com/loki/lochat/gradient/util/DisplayNameUtil.java @@ -16,7 +16,7 @@ import java.util.regex.Pattern; public final class DisplayNameUtil { private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder() - .character('§') + .character('&') .hexCharacter('#') .hexColors() .build(); diff --git a/src/main/java/com/loki/lochat/integrations/DiscordIntegration.java b/src/main/java/com/loki/lochat/integrations/DiscordIntegration.java index ea27ffb..6091a44 100644 --- a/src/main/java/com/loki/lochat/integrations/DiscordIntegration.java +++ b/src/main/java/com/loki/lochat/integrations/DiscordIntegration.java @@ -59,6 +59,12 @@ public class DiscordIntegration { int retryAttempts = config.getInt("performance.retry_attempts", 3); long retryDelay = config.getLong("performance.retry_delay", 1000); + // Логируем информацию о URL для отладки + plugin.getLogger().info("Discord webhook URL length: " + webhookUrl.length()); + if (webhookUrl.length() > 0) { + plugin.getLogger().info("Discord webhook URL starts with: " + webhookUrl.substring(0, Math.min(50, webhookUrl.length()))); + } + webhook = new DiscordWebhook(plugin, webhookUrl, username, avatarUrl, timeout, retryAttempts, retryDelay); if (!webhook.isValid()) { diff --git a/src/main/java/com/loki/lochat/integrations/DiscordWebhook.java b/src/main/java/com/loki/lochat/integrations/DiscordWebhook.java index 045d2ac..5be5dd1 100644 --- a/src/main/java/com/loki/lochat/integrations/DiscordWebhook.java +++ b/src/main/java/com/loki/lochat/integrations/DiscordWebhook.java @@ -28,7 +28,7 @@ public class DiscordWebhook { public DiscordWebhook(JavaPlugin plugin, String webhookUrl, String username, String avatarUrl, int timeout, int retryAttempts, long retryDelay) { this.plugin = plugin; - this.webhookUrl = webhookUrl; + this.webhookUrl = webhookUrl != null ? webhookUrl.trim() : null; // Убираем пробелы this.username = username; this.avatarUrl = avatarUrl; this.timeout = timeout * 1000; // конвертируем в миллисекунды @@ -142,7 +142,8 @@ public class DiscordWebhook { * Синхронная отправка в вебхук */ private boolean sendWebhookSync(String jsonPayload) throws IOException { - URL url = URI.create(webhookUrl).toURL(); + String cleanUrl = webhookUrl.trim(); + URL url = URI.create(cleanUrl).toURL(); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); try { @@ -180,8 +181,32 @@ public class DiscordWebhook { * Проверить валидность вебхука */ public boolean isValid() { - return webhookUrl != null && - webhookUrl.startsWith("https://discord.com/api/webhooks/") && - webhookUrl.length() > 50; // Минимальная длина валидного URL + if (webhookUrl == null || webhookUrl.trim().isEmpty()) { + plugin.getLogger().warning("Discord webhook URL is null or empty"); + return false; + } + + String cleanUrl = webhookUrl.trim(); + + if (!cleanUrl.startsWith("https://discord.com/api/webhooks/") && + !cleanUrl.startsWith("https://discordapp.com/api/webhooks/")) { + plugin.getLogger().warning("Discord webhook URL has invalid format: " + cleanUrl); + return false; + } + + if (cleanUrl.length() < 50) { + plugin.getLogger().warning("Discord webhook URL is too short: " + cleanUrl); + return false; + } + + // Проверяем на недопустимые символы + try { + URI.create(cleanUrl); + } catch (IllegalArgumentException e) { + plugin.getLogger().warning("Discord webhook URL contains illegal characters: " + e.getMessage()); + return false; + } + + return true; } } \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/listener/ChatEventListener.java b/src/main/java/com/loki/lochat/listener/ChatEventListener.java index 6919221..66f9b67 100644 --- a/src/main/java/com/loki/lochat/listener/ChatEventListener.java +++ b/src/main/java/com/loki/lochat/listener/ChatEventListener.java @@ -1,5 +1,6 @@ package com.loki.lochat.listener; +import com.loki.lochat.LoChat; import com.loki.lochat.api.service.MessageService; import com.loki.lochat.core.filter.AdvancedMessageFilter; import com.loki.lochat.core.registry.ServiceRegistry; @@ -62,8 +63,25 @@ public class ChatEventListener implements Listener { event.viewers().removeIf(viewer -> viewer instanceof Player p && !com.loki.lochat.util.DistanceUtil.isInRange(sender, p, radius) ); + + // Проверяем, есть ли получатели (кроме отправителя) + long recipientCount = event.viewers().stream() + .filter(viewer -> viewer instanceof Player p && !p.equals(sender)) + .count(); + + if (recipientCount == 0) { + // Отправляем уведомление отправителю после обработки события (Folia-совместимо) + sender.getScheduler().run(plugin, (task) -> + sender.sendMessage(com.loki.lochat.utils.ChatFormatter.parse(plugin.getConfig().getString("messages.local.nobody-heard", "<#FFA726>Вас никто не услышал - рядом нет игроков"))), null + ); + } } event.renderer(new EnhancedChatRenderer(plugin, sender, event.message(), isGlobal)); + + // Отправляем сообщение в Discord + if (plugin instanceof LoChat loChat) { + loChat.getDiscordIntegration().sendChatMessage(sender, filteredMessage, isGlobal); + } } } \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/managers/CustomCommandManager.java b/src/main/java/com/loki/lochat/managers/CustomCommandManager.java index 04ae7aa..b807fc8 100644 --- a/src/main/java/com/loki/lochat/managers/CustomCommandManager.java +++ b/src/main/java/com/loki/lochat/managers/CustomCommandManager.java @@ -10,6 +10,8 @@ import org.bukkit.command.CommandMap; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import java.io.File; @@ -57,7 +59,8 @@ public class CustomCommandManager { section.getString("message", ""), section.getStringList("aliases"), section.getString("type", "chat"), - section.getString("target", "sender") + section.getString("target", "sender"), + section.getBoolean("enabled", true) ); commands.put(commandName, data); @@ -75,17 +78,18 @@ public class CustomCommandManager { CommandMap commandMap = Bukkit.getCommandMap(); // Создаем и регистрируем команду - CustomCommand command = new CustomCommand(data.name, this); + CustomCommand command = new CustomCommand(data.name(), this); commandMap.register("lochat", command); // Регистрируем алиасы - for (String alias : data.aliases) { + for (String alias : data.aliases()) { CustomCommand aliasCommand = new CustomCommand(alias, this); commandMap.register("lochat", aliasCommand); } } catch (Exception e) { - plugin.getLogger().severe("Ошибка регистрации команды " + data.name + ": " + e.getMessage()); + plugin.getLogger().severe("Ошибка регистрации команды " + data.name() + ": " + e.getMessage()); + e.printStackTrace(); } } @@ -98,7 +102,7 @@ public class CustomCommandManager { if (data == null) { // Проверяем алиасы for (CustomCommandData cmd : commands.values()) { - if (cmd.aliases.contains(commandName)) { + if (cmd.aliases().contains(commandName)) { data = cmd; break; } @@ -107,21 +111,28 @@ public class CustomCommandManager { if (data == null) return false; + // Проверяем включена ли команда + if (!data.enabled()) { + // Не показываем ошибку, просто игнорируем команду + return true; + } + // Проверяем права - if (data.permission != null && !player.hasPermission(data.permission)) { + if (data.permission() != null && !player.hasPermission(data.permission())) { player.sendMessage(ChatFormatter.parse(plugin.getMessageConfig().getNoPermission())); return true; } // Обрабатываем плейсхолдеры - String message = processPlaceholders(data.message, player, args); + String message = processPlaceholders(data.message(), player, args); // Выполняем команду в зависимости от типа - switch (data.type.toLowerCase()) { - case "broadcast" -> sendBroadcast(data.target, message); - case "title" -> sendTitle(data.target, player, message); - case "actionbar" -> sendActionBar(data.target, player, message); - default -> sendChatMessage(data.target, player, message); + switch (data.type().toLowerCase()) { + case "broadcast" -> sendBroadcast(data.target(), message); + case "title" -> sendTitle(data.target(), player, message); + case "actionbar" -> sendActionBar(data.target(), player, message); + case "bungee" -> sendBungeeCommand(player, data); + default -> sendChatMessage(data.target(), player, message); } return true; @@ -136,6 +147,7 @@ public class CustomCommandManager { result = result.replace("{y}", String.valueOf(player.getLocation().getBlockY())); result = result.replace("{z}", String.valueOf(player.getLocation().getBlockZ())); result = result.replace("{world}", player.getWorld().getName()); + result = result.replace("{ping}", String.valueOf(player.getPing())); // Аргументы команды for (int i = 0; i < args.length; i++) { @@ -258,11 +270,52 @@ public class CustomCommandManager { } } + private void sendBungeeCommand(Player player, CustomCommandData data) { + // Отправляем сообщение игроку + if (!data.message().isEmpty()) { + Component component = ChatFormatter.parse(data.message()); + player.sendMessage(component); + } + + // Подключаем к серверу через BungeeCord + String serverName = getServerFromConfig(data); + if (serverName != null && !serverName.isEmpty()) { + connectToServer(player, serverName); + } + } + + private String getServerFromConfig(CustomCommandData data) { + // Ищем параметр server в конфиге команды + try { + File commandsFile = new File(plugin.getDataFolder(), "custom-commands.yml"); + FileConfiguration config = YamlConfiguration.loadConfiguration(commandsFile); + return config.getString(data.name() + ".server", "hub"); + } catch (Exception e) { + plugin.getLogger().warning("Ошибка получения сервера для команды " + data.name() + ": " + e.getMessage()); + return "hub"; + } + } + + private void connectToServer(Player player, String serverName) { + try { + java.io.ByteArrayOutputStream b = new java.io.ByteArrayOutputStream(); + java.io.DataOutputStream out = new java.io.DataOutputStream(b); + + out.writeUTF("Connect"); + out.writeUTF(serverName); + + player.sendPluginMessage(plugin, "BungeeCord", b.toByteArray()); + } catch (Exception e) { + plugin.getLogger().severe("Ошибка подключения к серверу " + serverName + ": " + e.getMessage()); + player.sendMessage(ChatFormatter.parse("<#F44336>❌ Ошибка подключения к серверу")); + } + } + public Map getCommands() { return commands; } public record CustomCommandData(String name, String permission, String message, List aliases, String type, - String target) { + String target, boolean enabled) { } } \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/renderer/EnhancedChatRenderer.java b/src/main/java/com/loki/lochat/renderer/EnhancedChatRenderer.java index a126356..f975483 100644 --- a/src/main/java/com/loki/lochat/renderer/EnhancedChatRenderer.java +++ b/src/main/java/com/loki/lochat/renderer/EnhancedChatRenderer.java @@ -45,16 +45,16 @@ public class EnhancedChatRenderer implements ChatRenderer { .append(Component.text("A").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FF6347"))) .append(Component.text("L").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FF4500"))); } else { - // 📍 LOCAL с градиентом от голубого к синему - prefixComponent = Component.text("📍 ") - .append(Component.text("L").color(net.kyori.adventure.text.format.TextColor.fromHexString("#87CEEB"))) + // LOCAL с градиентом от голубого к синему (без эмодзи) + prefixComponent = Component.text("L").color(net.kyori.adventure.text.format.TextColor.fromHexString("#87CEEB")) .append(Component.text("O").color(net.kyori.adventure.text.format.TextColor.fromHexString("#87CEFA"))) .append(Component.text("C").color(net.kyori.adventure.text.format.TextColor.fromHexString("#00BFFF"))) .append(Component.text("A").color(net.kyori.adventure.text.format.TextColor.fromHexString("#1E90FF"))) .append(Component.text("L").color(net.kyori.adventure.text.format.TextColor.fromHexString("#4169E1"))); } - Component playerComponent = createPlayerComponent(source, sourceDisplayName); + // Используем displayName игрока напрямую (он уже Component с градиентом) + Component playerComponent = createPlayerComponent(source, source.displayName()); Component processedMessage = message; processedMessage = TextFormatter.formatMarkdown(processedMessage); @@ -67,13 +67,13 @@ public class EnhancedChatRenderer implements ChatRenderer { // Красивое разделение с градиентными стрелками Component separator = isGlobal ? - Component.text(" ▶ ").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FFD700")) : - Component.text(" ▶ ").color(net.kyori.adventure.text.format.TextColor.fromHexString("#87CEEB")); + Component.text(" ▶ ", net.kyori.adventure.text.format.TextColor.fromHexString("#FFD700")) : + Component.text(" ▶ ", net.kyori.adventure.text.format.TextColor.fromHexString("#FFFFFF")); return prefixComponent .append(separator) .append(playerComponent) - .append(Component.text(": ").color(net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY)) + .append(Component.text(": ", net.kyori.adventure.text.format.NamedTextColor.WHITE)) .append(processedMessage); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9e5623b..0a1bdaf 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -293,10 +293,18 @@ gradient: price-per-color: 50 prefix-price: 500 prefix-one-time-purchase: true + use-permission-instead-of-cost: false max-prefix-length: 16 color-cooldown: 60 prefix-cooldown: 120 + # Форматирование + prefix-format: "[{prefix}] " + gradient-on-prefix: true + gradient-on-luckperms-prefix: true + continuous-gradient: true + use-legacy-rgb-format: true + presets: fire: [ "#FF4500", "#FF6347", "#FFD700" ] ocean: [ "#00CED1", "#1E90FF", "#4169E1" ] diff --git a/src/main/resources/config/custom-commands.yml b/src/main/resources/config/custom-commands.yml deleted file mode 100644 index d985368..0000000 --- a/src/main/resources/config/custom-commands.yml +++ /dev/null @@ -1,203 +0,0 @@ -# ╔══════════════════════════════════════════════════════════════════════════════╗ -# ║ LoChat Custom Commands ║ -# ║ Кастомные команды ║ -# ║ Версия: 1.5.5-1.20.1 ║ -# ╚══════════════════════════════════════════════════════════════════════════════╝ - -# ┌─────────────────────────────────────────────────────────────────────────────┐ -# │ НАСТРОЙКИ КОМАНД │ -# └─────────────────────────────────────────────────────────────────────────────┘ - -settings: - # Включить кастомные команды - enabled: true - - # Настройки Discord команды - discord: - invite-link: "discord.gg/example" - - # Настройки Website команды - website: - url: "https://example.com" - - # Настройки координат - coords: - show-in-actionbar: true - actionbar-duration: 60 - - # Настройки /me команды - me: - radius: 100 # Радиус для локального действия - - # Настройки звуков - sounds: - allow-toggle: true - - # Настройки статистики - stats: - show-server-stats: true - show-player-stats: true - -# ┌─────────────────────────────────────────────────────────────────────────────┐ -# │ ТЕКСТОВЫЕ КОМАНДЫ │ -# └─────────────────────────────────────────────────────────────────────────────┘ - -# Структура команды: -# command-name: -# permission: "право.для.использования" # Опционально -# message: "Текст сообщения" # Обязательно -# aliases: ["alias1", "alias2"] # Опционально -# type: "chat" # chat, broadcast, title, actionbar -# target: "sender" # sender, all, permission:право - -# ═══════════════════════════════════════════════════════════════════════════════ -# ИНФОРМАЦИОННЫЕ КОМАНДЫ -# ═══════════════════════════════════════════════════════════════════════════════ - -help: - message: | - ═══════ Помощь по серверу ═══════ - /rules - правила сервера - /discord - наш Discord - /website - официальный сайт - /coords - ваши координаты - /time - время на сервере - aliases: [ "помощь", "хелп" ] - type: "chat" - target: "sender" - -rules: - message: | - ═══════ Правила сервера ═══════ - 1. Не используйте читы и моды - 2. Уважайте других игроков - 3. Не спамьте в чате - 4. Не стройте рядом с чужими постройками - 5. Не используйте мат и оскорбления - - Нарушение правил карается мутом или баном! - aliases: [ "правила", "rule" ] - type: "chat" - target: "sender" - -discord: - message: | - ═══════ Наш Discord ═══════ - Присоединяйтесь к нашему сообществу! - - 🔗 discord.gg/example - - В Discord вы можете: - • Общаться с игроками - • Получать новости сервера - • Участвовать в событиях - aliases: [ "дискорд", "ds" ] - type: "chat" - target: "sender" - -website: - message: | - ═══════ Официальный сайт ═══════ - 🌐 example.com - - На сайте доступно: - • Карта сервера - • Статистика игроков - • Форум и новости - aliases: [ "сайт", "site" ] - type: "chat" - target: "sender" - -# ═══════════════════════════════════════════════════════════════════════════════ -# УТИЛИТЫ -# ═══════════════════════════════════════════════════════════════════════════════ - -coords: - message: | - Ваши координаты: - X: {x} - Y: {y} - Z: {z} - Мир: {world} - aliases: [ "координаты", "pos", "position" ] - type: "actionbar" - target: "sender" - -time: - message: | - Время на сервере: %server_time_24% - Дата: %server_date% - Онлайн: %server_online% игроков - aliases: [ "время", "дата" ] - type: "chat" - target: "sender" - -# ═══════════════════════════════════════════════════════════════════════════════ -# АДМИНСКИЕ КОМАНДЫ -# ═══════════════════════════════════════════════════════════════════════════════ - -restart-warning: - permission: "lochat.admin" - message: | - ⚠ ВНИМАНИЕ! ⚠ - Сервер будет перезагружен через 5 минут! - Сохраните свой прогресс и подготовьтесь к перезагрузке. - aliases: [ "рестарт", "reboot" ] - type: "title" - target: "all" - -maintenance: - permission: "lochat.admin" - message: | - Сервер переходит в режим технических работ - Ожидаемое время: 30 минут - aliases: [ "тех-работы", "maintenance" ] - type: "broadcast" - target: "all" - -# ═══════════════════════════════════════════════════════════════════════════════ -# VIP КОМАНДЫ -# ═══════════════════════════════════════════════════════════════════════════════ - -vip-info: - permission: "lochat.vip" - message: | - ═══════ VIP Привилегии ═══════ - • Цветной ник и префикс - • Приоритет входа на сервер - • Дополнительные команды - • Больше возможностей в чате - - Спасибо за поддержку сервера! - type: "chat" - target: "permission:lochat.vip" - -# ═══════════════════════════════════════════════════════════════════════════════ -# РАЗВЛЕКАТЕЛЬНЫЕ КОМАНДЫ -# ═══════════════════════════════════════════════════════════════════════════════ - -welcome: - message: | - Добро пожаловать на сервер! - Игрок {player} присоединился к игре - aliases: [ "привет", "hello" ] - type: "title" - target: "sender" - -# ┌─────────────────────────────────────────────────────────────────────────────┐ -# │ ПЛЕЙСХОЛДЕРЫ │ -# └─────────────────────────────────────────────────────────────────────────────┘ - -# Доступные плейсхолдеры в сообщениях: -# {player} - имя игрока -# {x}, {y}, {z} - координаты игрока -# {world} - название мира -# {arg0}, {arg1}, {arg2} - аргументы команды (нумерация с 0) -# {args} - все аргументы через пробел -# -# Также поддерживаются все плейсхолдеры PlaceholderAPI: -# %player_name% - имя игрока -# %server_online% - количество игроков онлайн -# %server_time_24% - время в формате 24 часа -# %server_date% - текущая дата -# И многие другие... \ No newline at end of file diff --git a/src/main/resources/config/gradient-config.yml b/src/main/resources/config/gradient-config.yml index 5585758..d09a894 100644 --- a/src/main/resources/config/gradient-config.yml +++ b/src/main/resources/config/gradient-config.yml @@ -3,7 +3,33 @@ # ║ Конфигурация градиентов ║ # ║ Версия: 1.5.5-1.20.1 ║ # ╚══════════════════════════════════════════════════════════════════════════════╝ - +# +# ┌─────────────────────────────────────────────────────────────────────────────┐ +# │ СИСТЕМА ОПЛАТЫ │ +# └─────────────────────────────────────────────────────────────────────────────┘ +# +# Есть два способа контролировать доступ к градиентам: +# +# 1. ЧЕРЕЗ PLAYERPOINTS (по умолчанию): +# - Установите use-permission-instead-of-cost: false +# - Игроки платят поинтами за установку градиентов +# - price-per-color: стоимость за каждый цвет +# - prefix-price: стоимость префикса +# - Игроки с правом "gradient.bypass.cost" могут использовать бесплатно +# +# 2. ЧЕРЕЗ ПЕРМИШЕНЫ (бесплатно): +# - Установите use-permission-instead-of-cost: true +# - Установите price-per-color: 0 и prefix-price: 0 +# - Выдайте игрокам право "gradient.bypass.cost" для бесплатного использования +# - Или выдайте "gradient.color" для доступа к командам +# +# ОСНОВНЫЕ ПЕРМИШЕНЫ: +# - gradient.color - доступ к команде /color +# - gradient.prefix - доступ к команде /prefix +# - gradient.bypass.cost - бесплатное использование (обход стоимости) +# - gradient.bypass.cooldown - обход кулдауна +# - gradient.admin - админские команды +# # ┌─────────────────────────────────────────────────────────────────────────────┐ # │ ОСНОВНЫЕ НАСТРОЙКИ │ # └─────────────────────────────────────────────────────────────────────────────┘ @@ -19,14 +45,21 @@ gradient: max-colors: 7 # Стоимость за каждый цвет (PlayerPoints) + # Установите 0 для бесплатного использования price-per-color: 50 # Стоимость префикса + # Установите 0 для бесплатного использования prefix-price: 500 # Одноразовая покупка префикса (true) или за каждое изменение (false) prefix-one-time-purchase: true + # Использовать пермишены вместо поинтов + # Если true, игроки с правом gradient.bypass.cost могут использовать бесплатно + # Если false, используется система PlayerPoints + use-permission-instead-of-cost: false + # Максимальная длина префикса max-prefix-length: 16 @@ -171,16 +204,18 @@ features: permissions: # Базовые права - use-gradient: "gradient.use" - use-prefix: "gradient.prefix" - admin: "gradient.admin" + use-gradient: "gradient.use" # Право использовать градиенты + use-color: "gradient.color" # Право использовать команду /color + use-prefix: "gradient.prefix" # Право использовать команду /prefix + admin: "gradient.admin" # Админские права # Обход ограничений - bypass-cooldown: "gradient.bypass.cooldown" - bypass-cost: "gradient.bypass.cost" - bypass-length: "gradient.bypass.length" + bypass-cooldown: "gradient.bypass.cooldown" # Обход кулдауна + bypass-cost: "gradient.bypass.cost" # Бесплатное использование (обход стоимости) + bypass-length: "gradient.bypass.length" # Обход ограничения длины префикса # Дополнительные цвета + # Игроки с этими правами могут использовать больше цветов extra-colors: "gradient.colors.5": 5 "gradient.colors.10": 10 diff --git a/src/main/resources/custom-commands.yml b/src/main/resources/custom-commands.yml new file mode 100644 index 0000000..75b7de7 --- /dev/null +++ b/src/main/resources/custom-commands.yml @@ -0,0 +1,140 @@ +# ╔══════════════════════════════════════════════════════════════════════════════╗ +# ║ Custom Commands Configuration ║ +# ║ Конфигурация кастомных команд ║ +# ╚══════════════════════════════════════════════════════════════════════════════╝ + +# Информационные команды +help: + enabled: true + message: | + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + 📚 Помощь по серверу + + <#FFEB3B>🏠 Основные команды: + <#9E9E9E>• <#FFFFFF>/spawn - телепорт на спавн + <#9E9E9E>• <#FFFFFF>/home - телепорт домой + <#9E9E9E>• <#FFFFFF>/sethome - установить дом + + <#FFEB3B>💬 Чат команды: + <#9E9E9E>• <#FFFFFF>!сообщение - глобальный чат + <#9E9E9E>• <#FFFFFF>/msg игрок - личное сообщение + <#9E9E9E>• <#FFFFFF>/reply - ответить на ЛС + + <#FFEB3B>🎨 Кастомизация: + <#9E9E9E>• <#FFFFFF>/color - градиентный ник + <#9E9E9E>• <#FFFFFF>/prefix - кастомный префикс + + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + aliases: ["помощь", "хелп"] + type: "chat" + target: "sender" + +rules: + enabled: true + message: | + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + 📋 Правила сервера + + <#F44336>🚫 Запрещено: + <#9E9E9E>• Читерство и использование модов + <#9E9E9E>• Гриферство и воровство + <#9E9E9E>• Мат и оскорбления + <#9E9E9E>• Спам в чате + <#9E9E9E>• Реклама других серверов + + <#4CAF50>✅ Разрешено: + <#9E9E9E>• Строительство в любом стиле + <#9E9E9E>• Торговля между игроками + <#9E9E9E>• Создание команд и кланов + <#9E9E9E>• Использование /home и /spawn + + <#FFA726>⚠️ За нарушения: + <#9E9E9E>• Предупреждение → Мут → Бан + + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + aliases: ["правила", "rule"] + type: "chat" + target: "sender" + +discord: + enabled: true + message: | + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + 💬 Discord сервер + + <#5865F2>Присоединяйся к нашему Discord! + + <#FFEB3B>🔗 Ссылка: <#00BFFF>discord.gg/yourserver + + <#FFEB3B>📢 В Discord ты найдешь: + <#9E9E9E>• Общение с игроками + <#9E9E9E>• Новости и обновления + <#9E9E9E>• Поддержку администрации + <#9E9E9E>• Конкурсы и ивенты + + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + aliases: ["дискорд", "ds"] + type: "chat" + target: "sender" + +coords: + enabled: true + message: "<#FFEB3B>📍 Ваши координаты: <#9E9E9E>X: <#FFFFFF>{x} Y: <#FFFFFF>{y} Z: <#FFFFFF>{z} <#9E9E9E>Мир: <#4CAF50>{world}" + aliases: ["координаты", "pos", "position"] + type: "chat" + target: "sender" + +ping: + enabled: true + message: "<#FFEB3B>📶 Ваш пинг: <#4CAF50>{ping}ms" + aliases: ["пинг"] + type: "chat" + target: "sender" + type: "chat" + target: "sender" + +hub: + enabled: true + message: "<#4CAF50>🏠 Подключение к хабу..." + aliases: ["lobby", "хаб"] + type: "bungee" + target: "sender" + server: "hub" + +discord: + enabled: true + message: | + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + 💬 Discord сервер + + <#5865F2>Присоединяйся к нашему Discord! + + <#FFEB3B>🔗 Ссылка: <#00BFFF>discord.gg/yourserver + + <#FFEB3B>📢 В Discord ты найдешь: + <#9E9E9E>• Общение с игроками + <#9E9E9E>• Новости и обновления + <#9E9E9E>• Поддержку администрации + <#9E9E9E>• Конкурсы и ивенты + + ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + aliases: ["дискорд", "ds"] + type: "chat" + target: "sender" + +# Команды для администрации +broadcast: + enabled: true + permission: "lochat.broadcast" + message: "{message}" + aliases: ["bc", "объявить"] + type: "broadcast" + target: "all" + +maintenance: + enabled: false + permission: "lochat.maintenance" + message: "<#FFA726>🔧 Сервер переведен в режим технических работ" + aliases: ["тех-работы", "техработы"] + type: "title" + target: "all" \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 29d8789..b835871 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -26,6 +26,7 @@ global: local: no-players: "&#FFA726Р&#FFA322я&#FF9F1Eд&#FF9B1Aо&#FF9716м &#FF9312н&#FF8F0Eе&#FF8B0Aт &#FF8706и&#FF8302г&#FF8000р&#FF8000о&#FF8000к&#FF8000о&#FF8000в" + nobody-heard: "&#FFA726Вас никто не услышал - рядом нет игроков" # ┌─────────────────────────────────────────────────────────────────────────────┐ # │ ЛИЧНЫЕ СООБЩЕНИЯ │ @@ -165,9 +166,58 @@ gradient: color-reset: "&#FFA726Градиент сброшен" prefix-set: "BCB77Префикс установлен!" prefix-reset: "&#FFA726Префикс сброшен" + prefix-reset-success: "BCB77Префикс успешно сброшен!" + prefix-enabled: "BCB77Префикс включен" + prefix-disabled: "&#FF6B6BПрефикс отключен" invalid-hex: "&#FF6B6BНеверный HEX цвет: {color}" + invalid-color: "&#FF6B6BНеверный цвет: {color}" too-many-colors: "&#FF6B6BСлишком много цветов! Максимум: {max}" too-few-colors: "&#FF6B6BСлишком мало цветов! Минимум: {min}" + not-enough-colors: "&#FF6B6BСлишком мало цветов! Минимум: {min}" cooldown: "&#FFA726Подождите {time} сек" not-enough-points: "&#FF6B6BНедостаточно поинтов! Нужно: {price}" + not-enough-points-color: "&#FF6B6BНедостаточно поинтов! Нужно: {price}" + not-enough-points-prefix: "&#FF6B6BНедостаточно поинтов! Нужно: {price}" player-not-found: "&#FF6B6BИгрок не найден" + color-help: "&#FFD700И&#FFC900с&#FFBB00п&#FFAD00о&#FF9F00л&#FF9100ь&#FF8300з&#FF7500о&#FF6700в&#FF5900а&#FF4B00н&#FF3D00и&#FF2F00е&#FF2100:&#FF1300 &#FF0500/&#FF0000c&#FF0000o&#FF0000l&#FF0000o&#FF0000r &#FF0000<&#FF0000H&#FF0000E&#FF0000X&#FF00001&#FF0000> &#FF0000<&#FF0000H&#FF0000E&#FF0000X&#FF00002&#FF0000>" + color-success: "BCB77Г>C973рAC76Fа3C56Bд1C367и(C163е&BF5FнFBD5Bт BB57уEB953сB74Fп�DB54BеB347шB347нB347о B347уB347сB347тB347аB347нB347оB347вB347лB347еB347нB347!" + color-no-colors: "&#FFA726У вас нет установленных цветов!" + color-copy-usage: "&#FFA726Использование: /color copy <игрок>" + color-copy-no-colors: "&#FFA726У игрока {player} нет установленных цветов!" + prefix-help: "&#FFD700Использование: /prefix <текст> или /prefix reset" + prefix-success: "BCB77Префикс успешно установлен! Стоимость: {price} поинтов" + prefix-success-free: "BCB77Префикс успешно установлен!" + prefix-no-prefix: "&#FFA726У вас нет установленного префикса!" + prefix-too-long: "&#FF6B6BПрефикс слишком длинный! Максимум: {max} символов" + prefix-no-colors: "&#FF6B6BПрефикс не может содержать цветовые коды!" + prefix-invalid-chars: "&#FF6B6BПрефикс содержит недопустимые символы!" + prefix-blacklisted: "&#FF6B6BЭтот префикс запрещён!" + only-player: "&#FF6B6BЭта команда только для игроков!" + no-permission: "&#FF6B6BУ вас нет прав!" + reload-success: "BCB77Конфигурация градиента перезагружена!" + info-header: "&#FFD700=== Информация о {player} ===" + info-prefix: "WCEEBПрефикс: &#FFFFFF{prefix}" + info-prefix-enabled: "WCEEBПрефикс включен: &#FFFFFF{enabled}" + info-colors: "WCEEBЦвета: &#FFFFFF{colors}" + info-color-enabled: "WCEEBЦвет включен: &#FFFFFF{enabled}" + info-prefix-purchased: "WCEEBПрефикс куплен: &#FFFFFF{purchased}" + +# ┌─────────────────────────────────────────────────────────────────────────────┐ +# │ КАСТОМНЫЕ НИКИ │ +# └─────────────────────────────────────────────────────────────────────────────┘ + +nick: + current: "WCEEBВаш текущий ник: {nick}" + usage: "&#FFA726Использование: /nick <ник> или /nick reset" + reset-usage: "&#FFA726Используйте /nick reset для сброса" + set-usage: "&#FFA726Используйте /nick <ник> для установки" + no-nick: "&#FFA726У вас нет кастомного ника" + reset-success: "BCB77Ваш ник сброшен!" + set-success: "BCB77Ваш ник изменён на: {nick}" + invalid: "&#FF6B6BНевалидный ник!" + requirements-header: "&#FFA726Требования:" + requirements-length: "WCEEB• Длина: 3-16 символов" + requirements-chars: "WCEEB• Разрешены: буквы, цифры, _, русские буквы" + requirements-colors: "WCEEB• Поддержка цветов: &#FF0000текст, текст" + taken: "&#FF6B6BЭтот ник уже занят!" + error: "&#FF6B6BНе удалось установить ник!" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 691d868..e200719 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -92,11 +92,6 @@ commands: permission: lochat.clearchat.config aliases: [ ccc, настройкаочистки ] - hub: - description: Connect to hub server - usage: /hub - aliases: [ lobby, хаб, рги ] - lochat: description: LoChat admin command usage: /lochat [reload] @@ -155,130 +150,17 @@ commands: # КАСТОМНЫЕ КОМАНДЫ # ═══════════════════════════════════════════════════════════════════════════════ - help: - description: Show server help - usage: /help - aliases: [ помощь, хелп ] + customcommands: + description: Manage custom commands + usage: /customcommands [list|reload|enable|disable] [command] + permission: lochat.customcommands + aliases: [ cc-admin, кастомкоманды ] - rules: - description: Show server rules - usage: /rules - aliases: [ правила, rule ] - - discord: + discordadmin: description: Discord integration management - usage: /discord [status|reload|test] + usage: /discordadmin [status|reload|test] permission: lochat.discord.admin - aliases: [ дискорд, ds ] - - website: - description: Show website link - usage: /website - aliases: [ сайт, site ] - - coords: - description: Show your coordinates - usage: /coords - aliases: [ координаты, pos, position ] - - time: - description: Show server time - usage: /time - aliases: [ время, дата ] - - playerinfo: - description: Show player information - usage: /playerinfo [player] - permission: lochat.playerinfo - aliases: [ pinfo, инфо, info ] - - sounds: - description: Toggle sound effects - usage: /sounds [on|off] - aliases: [ звуки, sound ] - - automessage: - description: Toggle auto messages - usage: /automessage [on|off] - aliases: [ автосообщения, am ] - - stats: - description: Show chat statistics - usage: /stats [player] - permission: lochat.stats - aliases: [ статистика, статы ] - - top: - description: Show top chatters - usage: /top [messages|playtime] - aliases: [ топ, рейтинг ] - - me: - description: Send action message - usage: /me - permission: chat.me - aliases: [ action, действие ] - - broadcast: - description: Broadcast message to all players - usage: /broadcast - permission: lochat.broadcast - aliases: [ bc, объявить ] - - maintenance: - description: Toggle maintenance mode - usage: /maintenance [on|off] [reason] - permission: lochat.maintenance - aliases: [ тех-работы, техработы ] - - motd: - description: Show message of the day - usage: /motd - aliases: [ сообщение-дня, мотд ] - - ping: - description: Show your ping - usage: /ping [player] - aliases: [ пинг ] - - list: - description: Show online players - usage: /list - aliases: [ онлайн, online, who ] - - afk: - description: Toggle AFK status - usage: /afk [reason] - aliases: [ афк, away ] - - back: - description: Return from AFK - usage: /back - aliases: [ назад, return ] - - tps: - description: Show server TPS - usage: /tps - permission: lochat.tps - aliases: [ тпс, performance ] - - memory: - description: Show server memory usage - usage: /memory - permission: lochat.memory - aliases: [ mem, память, ram ] - - version: - description: Show plugin version - usage: /version - permission: lochat.version - aliases: [ ver, версия ] - - reload: - description: Reload plugin configuration - usage: /reload - permission: lochat.reload - aliases: [ rl, перезагрузить ] + aliases: [ dadmin ] permissions: chat.global.use: @@ -406,42 +288,8 @@ permissions: description: Bypass domains filter default: op - # ═══════════════════════════════════════════════════════════════════════════════ - # ПРАВА КАСТОМНЫХ КОМАНД - # ═══════════════════════════════════════════════════════════════════════════════ - - lochat.playerinfo: - description: Can view player information - default: op - lochat.stats: - description: Can view chat statistics - default: op - chat.me: - description: Can use /me command - default: true - lochat.broadcast: - description: Can broadcast messages - default: op - lochat.maintenance: - description: Can toggle maintenance mode - default: op - lochat.tps: - description: Can view server TPS - default: op - lochat.memory: - description: Can view server memory - default: op - lochat.version: - description: Can view plugin version - default: true - lochat.reload: - description: Can reload plugin - default: op - lochat.afk: - description: Can use AFK commands - default: true - lochat.ping.others: - description: Can view other players' ping + lochat.customcommands: + description: Can manage custom commands default: op lochat.discord.admin: description: Can manage Discord integration